BIG requests/responses to POST and post_handler return value
Maxim Dounin
mdounin at mdounin.ru
Tue Feb 22 13:49:59 MSK 2011
Hello!
On Tue, Feb 22, 2011 at 01:34:51AM -0800, Antoine BONAVITA wrote:
> Hello,
>
> I'm trying to write my first module, so bear with me if my question feel silly.
> The situation is fairly simple:
> - My module accepts GET, POST and HEAD methods.
> - My module can return big chunks of data for GET and POST.
> - When I'm processing the GET everything is OK.
> - When I'm processing a POST which does not trigger saving the body to a temp
> file, everything is OK.
> - When I'm processing a POST which triggers saving the body to a temp file, my
> client only gets the first 65536 bytes (confirmed by both a wireshark capture
> and the nginx logs).
>
> Now, I understand nginx is happy when handling GET and "small POST" because
> everything happens in the content handler which returns appropriately
> NGX_AGAIN/NGX_OK/NGX_DONE. I would be happy to do the same with the
> post_handler. Unfortunately the signature of the post_handler (as defined by
> ngx_http_read_client_request_body) is:
> typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);
> and therefore I cannot return NGX_AGAIN (which would be natural).
When reading request body, your code in handler should look like:
static ngx_int_t
ngx_http_your_module_handler(...)
{
...
rc = ngx_http_read_client_request_body(r, ngx_http_your_body_hander);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
return NGX_DONE;
}
static void
ngx_http_your_body_handler(...)
{
...
ngx_http_finalize_request(...);
return;
}
Key points are:
1. You always return NGX_DONE from handler.
2. You are responsible to call ngx_http_finalize_request() as
you've retruned NGX_DONE.
> I'll try to get some "bare-bone" code together to reproduce this but high-level
> it looks like:
> ngx_int_t ngx_http_xxx_handler(ngx_http_request_t *r) {
> if (NGX_HTTP_GET == r->method) {
> return ngx_http_xxx_do_get(r);
> } else if (NGX_HTTP_POST == r->method) {
> return ngx_http_xxx_do_post(r);
> }
> }
>
> ngx_int_t ngx_http_xxx_do_post(ngx_http_request_t *r) {
> [...]
> rc = ngx_http_read_client_request_body(r, ngx_http_xxx_body_received);
>
> if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
> return rc;
> }
>
> if (rc == NGX_AGAIN) {
> /* It will not call me again, but call the body_received. */
> return NGX_AGAIN;
> }
No, NGX_AGAIN here means: setup http writer and call it again once
write is possible on client connection. It is designed to be
natural for code like
return ngx_http_output_filter(r, &out);
Returning NGX_AGAIN in case of reading body will result in
problems (exactly as you see). Use the above pattern instead.
Maxim Dounin
More information about the nginx-devel
mailing list