I’m writing a module for nginx and am hoping someone could enlighten me.
The module takes in some parameters via either GET or POST methods.
Everything works fine except when using Python’s urllib which appears
to send the HTTP POST data as two TCP packets.
The short of it is that ngx_http_read_client_request_body() returns
NGX_AGAIN because c->read->ready is not set. My module in turn passes
NGX_AGAIN back up to the calling routine.
The confusing part to me is the following lines from
src/http/ngx_http_core_module.c:
which appears to (according the debug stuff in the log) simply close
out the connection regardless of the return value from
content_handler(). Shouldn’t my module be getting re-called when more
data is available from the connection or am I misunderstanding
something?
out the connection regardless of the return value from
content_handler(). Shouldn’t my module be getting re-called when more
data is available from the connection or am I misunderstanding
something?
No. post_handler (the second argument of
ngx_http_read_client_request_body) should be called when the body will
be
successfully received.
ngx_http_finalize_request does not close the connection whenever rc ==
NGX_AGAIN. Instead ngx_http_read_client_request_body sets read handler
to
ngx_http_read_client_request_body_handler. Therefore the read handler
will
be recalled, not your handler.
Ok, now I’m really confused, here is my call to
ngx_http_read_client_request_body:
rc = ngx_http_read_client_request_body(r,
ngx_http_mymodule_request_body_handler);
If I use any other client (firefox, links, wget) then
ngx_http_mymodule_request_body_handler gets called.
Using urllib, which causes the NGX_AGAIN return, I get the following
in the log (the first statement is mine after the call to
ngx_http_read_client_request_body prior to returning NGX_AGAIN to the
caller).
I see the message in the log, so I know I returned from here with
NGX_AGAIN, but the request_body_handler never gets invoked. Is there
some state I should be setting on the ngx_http_request_t before
returning control?
I see the message in the log, so I know I returned from here with
NGX_AGAIN, but the request_body_handler never gets invoked. Is there
some state I should be setting on the ngx_http_request_t before
returning control?
post_handler is the state. It is being written into request. But you
should return NGX_DONE as I wrote before.
Most examples of using ngx_http_read_client_request_body seem to be
upstream modules which really doesn’t apply to my situation. The DAV
module does this at the end of the post_handler
(ngx_http_dav_put_handler):
I’m a little unsure what I should be doing at the end of my
post_handler.
When my code was in the main handler I returned with:
return ngx_http_output_filter(r, &out);
Most examples of using ngx_http_read_client_request_body seem to be
upstream modules which really doesn’t apply to my situation. The DAV
module does this at the end of the post_handler
(ngx_http_dav_put_handler):
What I want to do is “return ngx_http_output_filter(r, &out);” just
like before, but that seems to not work, my question is should it work
from the request_body_handler and is there any special trick to doing
so or better yet an existing module I can look at for pointers? I
couldn’t find one, virtually everything that uses
ngx_http_read_client_request_body is an upstream module.
I don’t know whether a module doing similar thing exists, but I assume
you
invoke ngx_http_send_header, interpret the result, call
ngx_http_output_filter and it should be ok.
Basically, I am returning some JSON objects as the text/plain mime type.
This had been working fine (creating the out buffer, etc…) as long
as I did it in the main handler, but it doesn’t seem to work quite
right in the request_body_handler. The client hangs on the response,
if I kill the nginx server, the client returns with the data, but
obviously that’s not what I’m looking for. I would like for the
output to be passed through the filter chain for gzipping and such.
What I want to do is “return ngx_http_output_filter(r, &out);” just
like before, but that seems to not work, my question is should it work
from the request_body_handler and is there any special trick to doing
so or better yet an existing module I can look at for pointers? I
couldn’t find one, virtually everything that uses
ngx_http_read_client_request_body is an upstream module.
I still not sure this is quite right, particularly on which value I
should be sending for the second argument to
ngx_http_finalize_request(), but it does seem to work reliably.
First, thanks for all your help, I’m slowing getting a handle on the
internal workings of nginx but it’s been a bit of a learning curve.
I did some more digging and what I’m finding is that everything is
indeed working correctly except the connection is not closed after the
results are returned. Here is the transaction with my module in the
loop:
request:
POST /hello HTTP/1.0
Content-Length: 10
abcd=12345
response:
HTTP/1.1 200 OK
Server: nginx/0.7.19
Date: Wed, 15 Oct 2008 03:02:41 GMT
Content-Type: text/plain
Content-Length: 11
Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT
Connection: close
hello world
The connection then hangs until another character is sent from the
client to the server at which time it closes.
I’ve replicated the same request using fastcgi/perl and it works
flawlessly.
Any thoughts on why my module would require additional input from the
client to close the connection?