NGX_DONE from body_filter, and what's next?

Hi,
I’m writing a filter which do something like this:

  1. collect incoming data from chains
  2. enqueues some asynchronous connections using nginx event mechanism
  3. returns NGX_DONE

How should I finalize work of this filter from callback?

Calling next_body_filter(request, result) from callback doesn’t work,
probably because of NGX_DONE returned from body_filter.
Calling next_body_filter and ngx_http_finalize_request(r, rc) seems to
work (site is served, client can see the result), but it causes
segfaults in strange places (outside my filter). Probably
ngx_http_finalize_request must not be used in that way.

Does anybody know how to finalize work of filter which returned
NGX_DONE?
Is it allowed to return NGX_DONE from filter?

Posted at Nginx Forum:

I will give some code example:

ngx_http_my_filter_header_filter(ngx_http_request_t *r)
{
// (…)

// I clear content length, because it will be modified by my filter
if (r == r->main) {
ngx_http_clear_content_length(r);
ngx_http_clear_last_modified(r);
}
return ngx_http_next_header_filter(r);
}

ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
// process data
// enqueue downloads etc.
//…
return NGX_DONE;
}

The function which is called when downloads are finished:

ngx_http_myfilter_download_finished()
{
// process data etc.

// create and fill new ngx_chain_t
// set in bufs: memory = 1, last_buf = 1 in last buffer

rc = ngx_http_next_body_filter(r, output_chain);

if(rc == NGX_AGAIN)
{
    ngx_add_timer(r->connection->write, timeout);
    r->write_event_handler = ngx_http_myfilter_fast_handler;

    if (ngx_handle_write_event(r->connection->write, 0) == 

NGX_ERROR)
{
// error handling
}
}
else {
ngx_http_myfilter_fast_handler(r);
}
}

and fast_handler:

ngx_http_xxslt_fast_handler(ngx_http_request_t *r)
{
ngx_int_t rc;

rc = ngx_http_send_special(r, NGX_HTTP_LAST);

ngx_http_finalize_request(r, rc);

}

When ngx_http_next_body_filter returns NGX_OK everything is fine, no
problem.
My filter behaves strange, when ngx_http_next_body_filter returns
NGX_AGAIN (for large output chains).
When I refresh website, first request is handled properly, I can see the
result in the web browser.
Second request is broken. After receiving rc = NGX_AGAIN my fast_handler
is not called and response isn’t transferred to the client.
There are two messages in logs from nginx:
2009/09/18 11:40:25 30067#0: *52 client closed prematurely connection
(104: Connection reset by peer) while sending response to client,
client: 10.166…
2009/09/18 11:40:54 30067#0: *1 client timed out (110: Connection timed
out) while sending response to client, client: 10.166…

When I use telnet it looks like this:
GET /sth HTTP/1.1
Host: host

0

0

// this is ok, because of Transfer-Encoding: chunked there are two zeros
at the end

GET /sth HTTP/1.1
Host: host

0

// where is second 0?

GET /sth HTTP/1.1
Host: host

GET /sth HTTP/1.1
Host: host

etc.

These request which are not handled just call my body_filter with in =
NULL (it’s visible in logs).

Any ideas what am I doing wrong?
Any help will be greatly appreciated :wink:

Posted at Nginx Forum: