Example body filter hangs when modified a little bit - request is not terminating.

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Example body filter hangs when modified a little bit - request is not terminating.

ashuai
I tried out this nginx example ngx_http_foo_body_filter body filter (here
http://nginx.org/en/docs/dev/development_guide.html#http_body_buffers_reuse
) and got that to work just fine.  It inserts a "foo" string before each
incoming buffer.

I tried modifying a little bit so that it puts the foo string AFTER each
incoming buffer chain in the list.   The pages render correctly, but the
request never terminates and the browser just sits there spinning.   I don't
know what I'm doing wrong.   I'm pretty sure it is not module ordering
because the original version works ok.   I also set the content length to -1
in the header filter, etc.

In the debugger, the out linked chain looks right with no cycles or
anything.

I appreciate any help you can give.  Thank you.

Here is my version:

ngx_int_t
ngx_http_foo_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_int_t                   rc;
    ngx_buf_t                  *b;
    ngx_chain_t                *cl, *tl, *out, **ll;
    ngx_http_foo_filter_ctx_t  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_foo_filter_module);
    if (ctx == NULL) {
        return ngx_http_next_body_filter(r, in);
    }

    /* create a new chain "out" from "in" with all the changes */

    ll = &out;

    for (cl = in; cl; cl = cl->next) {

        /* append the next incoming buffer */

        tl = ngx_alloc_chain_link(r->pool);
        if (tl == NULL) {
            return NGX_ERROR;
        }

        tl->buf = cl->buf;
        *ll = tl;
        ll = &tl->next;

        /* append "foo" in a reused buffer if possible */

        tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
        if (tl == NULL) {
            return NGX_ERROR;
        }

        b = tl->buf;
        b->tag = (ngx_buf_tag_t) &ngx_http_foo_filter_module;
        b->memory = 1;
        b->pos = (u_char *) "foo";
        b->last = b->pos + 3;

        *ll = tl;
        ll = &tl->next;

    }

    *ll = NULL;

    /* send the new chain */

    rc = ngx_http_next_body_filter(r, out);

    /* update "busy" and "free" chains for reuse */

    ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
                            (ngx_buf_tag_t) &ngx_http_foo_filter_module);

    return rc;
}

Posted at Nginx Forum: https://forum.nginx.org/read.php?2,278094,278094#msg-278094

_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Example body filter hangs when modified a little bit - request is not terminating.

Zhang Chao
Hi!

what’s the corresponding response headers of your browser?

_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Example body filter hangs when modified a little bit - request is not terminating.

ashuai
here is with the body filter disabled (works normally):

HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Thu, 11 Jan 2018 04:16:07 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive

here is with the body filter enabled (connection does not terminate):

HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Thu, 11 Jan 2018 04:19:59 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive

Essentially the same.

Posted at Nginx Forum: https://forum.nginx.org/read.php?2,278094,278096#msg-278096

_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Example body filter hangs when modified a little bit - request is not terminating.

Roman Arutyunyan
In reply to this post by ashuai
Hi,

On Wed, Jan 10, 2018 at 08:05:15PM -0500, ptcell wrote:

> I tried out this nginx example ngx_http_foo_body_filter body filter (here
> http://nginx.org/en/docs/dev/development_guide.html#http_body_buffers_reuse
> ) and got that to work just fine.  It inserts a "foo" string before each
> incoming buffer.
>
> I tried modifying a little bit so that it puts the foo string AFTER each
> incoming buffer chain in the list.   The pages render correctly, but the
> request never terminates and the browser just sits there spinning.   I don't
> know what I'm doing wrong.   I'm pretty sure it is not module ordering
> because the original version works ok.   I also set the content length to -1
> in the header filter, etc.
>
> In the debugger, the out linked chain looks right with no cycles or
> anything.
>
> I appreciate any help you can give.  Thank you.

The last buffer in chain should normally have the last_buf flag set.
This is not changed by the devguide example, but in your code it's your buffer
which is the last one, and it obviously does not have the right flag.
This is why ngx_http_chunked_filter does not end the HTTP chunked response
with the final empty chunk, but your client is expecting it.

> Here is my version:
>
> ngx_int_t
> ngx_http_foo_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
> {
>     ngx_int_t                   rc;
>     ngx_buf_t                  *b;
>     ngx_chain_t                *cl, *tl, *out, **ll;
>     ngx_http_foo_filter_ctx_t  *ctx;
>
>     ctx = ngx_http_get_module_ctx(r, ngx_http_foo_filter_module);
>     if (ctx == NULL) {
>         return ngx_http_next_body_filter(r, in);
>     }
>
>     /* create a new chain "out" from "in" with all the changes */
>
>     ll = &out;
>
>     for (cl = in; cl; cl = cl->next) {
>
>         /* append the next incoming buffer */
>
>         tl = ngx_alloc_chain_link(r->pool);
>         if (tl == NULL) {
>             return NGX_ERROR;
>         }
>
>         tl->buf = cl->buf;
>         *ll = tl;
>         ll = &tl->next;
>
>         /* append "foo" in a reused buffer if possible */
>
>         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
>         if (tl == NULL) {
>             return NGX_ERROR;
>         }
>
>         b = tl->buf;
>         b->tag = (ngx_buf_tag_t) &ngx_http_foo_filter_module;
>         b->memory = 1;
>         b->pos = (u_char *) "foo";
>         b->last = b->pos + 3;
>
>         *ll = tl;
>         ll = &tl->next;
>
>     }
>
>     *ll = NULL;
>
>     /* send the new chain */
>
>     rc = ngx_http_next_body_filter(r, out);
>
>     /* update "busy" and "free" chains for reuse */
>
>     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
>                             (ngx_buf_tag_t) &ngx_http_foo_filter_module);
>
>     return rc;
> }
>
> Posted at Nginx Forum: https://forum.nginx.org/read.php?2,278094,278094#msg-278094
>
> _______________________________________________
> nginx mailing list
> [hidden email]
> http://mailman.nginx.org/mailman/listinfo/nginx

--
Roman Arutyunyan
_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx