Flushing responses in nginx modules

Johan Andersson ng23 at firemail.cc
Tue Jul 11 14:57:33 UTC 2017


Hi Andreas and Zhang,

Thank you for your hint with the http_echo_module! I read through their 
code to get a hang of how the event loop and the event handling actually 
works.

If I replace the hello_world command in my config files with the 
echo/echo_flush/echo_sleep commands, everything works as expected.

If I use my modified hello_world module (code below), I still get a 
three second pause and then all three "hello world" at once.

So I do not think that my configuration (which is the default Debian 
Stretch configuration) is at fault.

I pasted the whole debug log here: https://pastebin.com/raw/uwuK4UJB

When I look into the debug log, I see four writev lines corresponding to 
the initial header and the three "helloworld" outputs.

So I think the socket gets its data, but perhaps I am missing some magic 
socket options? Which would be strange, as I cannot see the 
http_echo_module doing such a thing.

This is my current code (all error handling omitted -- I will take care 
of that):

struct ngx_http_hello_world_ctx
{
     int counter;
     ngx_event_t event;
};

static int numberOfMessages = 3;

static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r)
{
     struct ngx_http_hello_world_ctx * ctx = ngx_http_get_module_ctx(r, 
ngx_http_hello_world_module);

     if(ctx == NULL)
     {
         ctx = ngx_pcalloc(r->pool, sizeof(struct 
ngx_http_hello_world_ctx));
         ngx_http_set_ctx(r, ctx, ngx_http_hello_world_module);
     }

     ctx->counter = 0;
     ctx->event.data = r;
     ctx->event.handler = ngx_http_hello_world_event_handler;
     ctx->event.log = r->connection->log;

     r->headers_out.content_type.len = sizeof("text/html") - 1;
     r->headers_out.content_type.data = (u_char *) "text/html";
     r->headers_out.status = NGX_HTTP_OK;
     ngx_http_send_header(r);

     r->main->count++; // Increments reference count
     ngx_add_timer(&ctx->event, 0);

     return ngx_http_output_filter(r, NULL);
}

static void ngx_http_hello_world_event_handler(ngx_event_t *ev)
{
     ngx_http_request_t * r = ev->data;
     struct ngx_http_hello_world_ctx * ctx = ngx_http_get_module_ctx(r, 
ngx_http_hello_world_module);

     if(ctx->counter < numberOfMessages)
     {
         ngx_buf_t *b;
         ngx_chain_t out;

         b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

         out.buf = b;
         out.next = NULL;

         b->pos = ngx_hello_world;
         b->last = ngx_hello_world + sizeof(ngx_hello_world);
         b->memory = 1;
         b->flush = 1;
         b->last_buf = (ctx->counter == numberOfMessages);

         ngx_http_output_filter(r, &out);
         ngx_http_send_special(r, NGX_HTTP_FLUSH);

         ctx->counter++;

         if(ctx->counter == numberOfMessages)
         {
             ctx->counter = 0;
             ngx_http_send_special(r, NGX_HTTP_LAST);
             ngx_http_finalize_request(r, NGX_OK); // Decrements 
reference count
         }
         else
         {
             ngx_add_timer(&ctx->event, 1000);
         }
     }
}

Cheers
Johan

On 2017-07-10 04:04, Zhang Chao wrote:
> Hello!
> 
> You mustn’t use standard sleep function for it will block Nginx’s
> events loop, alternatively, you need to put your write event to a
> timer, set the proper handler when the timer expires.
> BTW, you should always check the return value of ngx_http_send_header
> and ngx_http_output_filter.
> 
> On 10 July 2017 at 01:43:46, Johan Andersson (ng23 at firemail.cc) wrote:
> 
>> Hi everyone,
>> 
>> I have some issues writing my nginx modules.
>> 
>> I am on Debian Stretch, installed nginx with the default
>> configuration,
>> and took the hello_world module. It works without a hitch. Then I
>> changed the handler to send three "hello world" responses, and sleep
>> for
>> one second between each response.
>> 
>> However, when I look at the result in my browser, the page loads,
>> pauses
>> for three seconds, and then displays all three "hello world"
>> messages at
>> once.
>> 
>> Actually I was flushing each response, so I expected each "hello
>> world"
>> message to appear one after the other, with one second pause between
>> 
>> them.
>> 
>> Am I doing something wrong? Is this event the correct way to achieve
>> 
>> this? All functions return NGX_OK. This is my code:
>> 
>> static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r)
>> 
>> {
>> ngx_buf_t *b;
>> ngx_chain_t out;
>> ngx_int_t result;
>> 
>> r->headers_out.content_type.len = sizeof("text/html") - 1;
>> r->headers_out.content_type.data = (u_char *) "text/html";
>> r->headers_out.status = NGX_HTTP_OK;
>> //r->headers_out.content_length_n = sizeof(ngx_hello_world);
>> ngx_http_send_header(r);
>> 
>> for(int i = 0; i < 3; i++)
>> {
>> b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
>> 
>> out.buf = b;
>> out.next = NULL;
>> 
>> b->pos = ngx_hello_world;
>> b->last = ngx_hello_world + sizeof(ngx_hello_world);
>> b->memory = 1;
>> b->flush = 1;
>> b->last_buf = (i == 2);
>> 
>> result = ngx_http_output_filter(r, &out);
>> ngx_http_send_special(r, NGX_HTTP_FLUSH);
>> 
>> sleep(1);
>> }
>> 
>> return result;
>> }
>> 
>> Cheers
>> Johann
>> _______________________________________________
>> nginx mailing list
>> nginx at nginx.org
>> http://mailman.nginx.org/mailman/listinfo/nginx
> _______________________________________________
> nginx mailing list
> nginx at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx


More information about the nginx mailing list