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