Nginx的请求处理流程之二:handler发送包头、包体

Nginx的请求处理流程之二:handler发送包头、包体

     本文是解析自定义module的handler中调用了发送包头、包体函数后,nginx做了哪些工作。
    参考《 Nginx的请求处理流程之一:分派handler 》中的框图。简要的说,就是调用了filters模块的链表,对handler生成的包头、包体内容最后进行加工,然后调用writev()来发送。


一、发送http包头

1、ngx_http_send_header()
    系统将各个包头过滤模块的处理加入ngx_http_next_header_filter指针链表中,在调用ngx_http_send_header()时,会依次调用所有头部的过滤模块。这些模块是处理r->headers_outs 中的内容。
    包头Filter模块的调用链表是如何实现的,请见下面2.2中的包体Filter模块的调用链表的说明。

2、 ngx_http_header_filter()   
   包头Filter模块处理链表最后一个头部过滤的方法负责发送头部。 包头最后的过滤模块就是ngx_http_header_filter_module。  ngx_http_header_filter(),它 将r->header_outs的内容序列化并发送出去。如果一次发送不完,需要将剩下的响应头部保存到r->out链表中,以备后续发送:
ngx_int_t ngx_http_header_filter(ngx_http_request_t *r)
{
  ngx_chain_t out;

   if (r->header_sent) return NGX_OK;
   r->header_sent = 1;

   //将r->header_outs的内容序列化为http包头
  ......
  return  ngx_http_write_filter(r, &out);  //发送包头
}

3、ngx_http_write_filter()  //ngx_http_writer_filter_module  
    这是包头Filter模块处理链表的最后一个 模块ngx_http_writer_filter_module的处理方法。发送包头、包体都用这个的:
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
  ngx_chain_t      *chain;
  ngx_connection_t *c;

  c = r->connection;
  ... //将in追加如r->out的尾部。

  if (c->write->delayed) {
     c->buffered |= NGX_HTTP_WRITE_BUFFERED;
     return NGX_AGAIN;
  }

  //send_chain返回的是没有发完的chain
  chain = c-> send_chain(c, r->out, limit);

  r->out = chain;
   //如果chain不为空,那么buf没有发送完,需要设置buffered标记,并返回NGX_AGAIN
  if (chain) 
  {
      c-> buffered |= NGX_HTTP_WRITE_BUFFERED;
      return  NGX_AGAIN;
  }

   //如果已经没有未发送的chain,就清空buffered标记
  c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;

   //如果其他filter模块buffer了chain并且postponed为NULL,那么返回NGX_AGAIN,需要继续处理buf
  if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
      return  NGX_AGAIN;
  }

  return  NGX_OK;
}
    如果无法一次发送,则将剩余内容保存到r->out中,并返回NGX_AGAIN。
    返回到ngx_http_finalize_request(),这时http框架就会继续将可写事件注册到epoll。

其中,c->send_chain在 ngx_event_accept()和 ngx_event_connect_peer()中设置:
    c->recv = ngx_recv;
    c->send = ngx_send;
    c->recv_chain = ngx_recv_chain;
    c->send_chain = ngx_send_chain;

ngx_send_chain最后调用了  ngx_writev_chain.c的
ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
   |- ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec);
            |- writev( c->fd, vec->iovs, vec->count );
    
4、ngx_http_finalize_request()
    ngx_http_write_filter()的返回值的最终会在ngx_http_finalize_request()中处理,该函数 负责根据返回值调整 当前请求的后续流程,包括结束请求:
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
    if (rc ==  NGX_DONE) {
        ngx_http_finalize_connection(r);
        return;
    }

    if (rc ==  NGX_OK && r->filter_finalize) {
        c->error = 1;
    }

    if (rc ==  NGX_DECLINED) {
        r->content_handler = NULL;
        r->write_event_handler =  ngx_http_core_run_phases;
        ngx_http_core_run_phases(r);
        return;
    }

    if (rc ==  NGX_ERROR
        || rc == NGX_HTTP_REQUEST_TIME_OUT
        || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
        || c->error)
    {
        if (ngx_http_post_action(r) == NGX_OK)
            return;

        if (r->main->blocked) 
            r->write_event_handler = ngx_http_request_finalizer;

        ngx_http_terminate_request(r, rc);
        return;
    }    

     ...
    if (r->buffered || c-> buffered || r->postponed || r->blocked) {
         //这里应该就是默认的NGX_AGAIN
        if ( ngx_http_set_write_handler(r) != NGX_OK) 
            ngx_http_terminate_request(r, 0);

        return;
    } 

    if (c->read->eof) {
        ngx_http_close_request(r, 0);
        return;
    }

     ngx_http_finalize_connection(r);      
}
    每个请求动作结束时都会调用ngx_http_finalize_request()函数来结束请求。 其中,如果完成或出错则终止连接;如果默认且数据未发完,则调用 ngx_http_set_write_handler()来处理。
    
5、ngx_http_set_write_handler()
    该函数(ngx_http_request.c中)中 调用了 ngx_handle_write_event()将当前连接的写事件重新加入epoll:
ngx_int_t  ngx_http_set_write_handler(ngx_http_request_t *r)
{
    ngx_event_t               *wev;
    ngx_http_core_loc_conf_t  *clcf;

    r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
    r->write_event_handler =  ngx_http_writer;

    wev = r->connection->write;

    ...
    if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
        ngx_http_close_request(r, 0);
        return NGX_ERROR;
    }

    return NGX_OK;
}

6、void ngx_http_writer()
    该函数(ngx_http_request.c中)中调用了ngx_http_output_filter发送。并根据结果重设epoll事件。
void ngx_http_writer(ngx_http_request_t *r)
{
    int                        rc;
    ngx_event_t               *wev;
    ngx_connection_t          *c;
    ngx_http_core_loc_conf_t  *clcf;

    c = r->connection;
     wev = c->write;

    clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);

     //首先处理写事件超时
    if (wev->timedout) 
    {
        if (!wev->delayed) 
        {
            c->timedout = 1;

            ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
            return;
        }

        wev->timedout = 0;
        wev->delayed = 0;

        //如果写事件延迟了但仍未准备好,重新放入epoll事件
        if (!wev->ready) 
        {
            ngx_add_timer(wev, clcf->send_timeout);

            if ( ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) 
                ngx_http_close_request(r, 0);

            return;
        }
    }

     //未超时时,但事件需要延期,重新加入epoll事件。
    if (wev->delayed || r->aio) 
    {
        if ( ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) 
            ngx_http_close_request(r, 0);

        return;
    }

    rc =  ngx_http_output_filter(r, NULL);
    if (rc == NGX_ERROR) 
    {
        ngx_http_finalize_request(r, rc);
        return;
    }

    //已经发送完了包了,如果当前还在接收数据,或需要延期时,进行的处理
    if (r->buffered || r->postponed || (r == r->main && c->buffered)) 
    {
         //如果没有写延期,将启动超时定时器
        if (!wev->delayed) 
            ngx_add_timer(wev, clcf->send_timeout);

         //将当前写事件加入epoll中等待处理。
        if ( ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
            ngx_http_close_request(r, 0);

        return;
    }

     //即不再处理写事件了
     r->write_event_handler = ngx_http_request_empty_handler;

    ngx_http_finalize_request(r,  rc);
}


二、发送包体
    发送包头执行的也就是ngx_http_writer()中调用的ngx_http_output_filter这个函数。而发送包体 也要先经过包体 过滤模块来处理,最后再发送。

1、ngx_http_output_filter()
typedef ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_http_output_body_filter_pt    ngx_http_top_body_filter;

ngx_int_t  ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    return ngx_http_top_body_filter(r, in);
}

2、 ngx_http_write_filter()   //ngx_http_writer_filter_module
    如下可见通过各包体Filter模块的本地变量ngx_http_next_body_filter,形成了一个包体Filter模块的调用链表。最后调用的ngx_http_top_body_filter 就是 ngx_http_write_filter_module模块的ngx_http_write_filter()。
    ngx_http_write_filter()的流程解析,参考前面 发送包头部分
//ngx_http_write_filter_module.c:
//ngx_http_write_filter_module_ctx的postconfiguration函数
ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf)
{
    ngx_http_top_body_filter =  ngx_http_write_filter;
    return NGX_OK;
}

//ngx_http_copy_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;

ngx_int_t ngx_http_copy_filter_init(ngx_conf_t *cf)
{
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_copy_filter;
    return NGX_OK;
}

//ngx_http_postpone_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;

ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf)
{
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_postpone_filter;
    return NGX_OK;
}
注意:
    ngx_http_top_body_filter是全局的。而ngx_http_next_body_filter静态的,当前filter文件中的,用于缓存全局变量,而在执行ngx_http_copy_filter完成时再把静态变量赋给全局的。
    ngx_http_write_filter_module是最后一个模块,因此不再设置ngx_http_next_body_filter了。
    这样实现了一个output filter链表,由Filter模块代码自己来加入链表,而不需修改其他代码。如nginx自己的gzip压缩处理等Filter模块就是这样被调用的。


三、结束请求

1、ngx_http_finalize_request()
    前面已经有分析了,所有发送结果都要返回这里重新进行分派,是终止连接、正常结束请求还是继续发送,视模块handler的返回值来定。

2、ngx_http_close_request()
    最终的结束请求的方法,在于其中调用的最后两个函数:
void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
{
    ngx_connection_t  *c;

    r = r->main;
    c = r->connection;

    r->count--;

    if (r->count || r->blocked) 
        return;

    ngx_http_free_request(r, rc); 
    ngx_http_close_connection(c);
}


Nginx的请求处理流程之二:handler发送包头、包体

     本文是解析自己写的module的handler中调用了发送包头、包体函数后,nginx做了哪些工作。
    参考《 Nginx的请求处理流程之一:分派handler 》中的框图。简要的说,就是调用了filters模块的链表,对handler生成的包头、包体内容最后进行加工,然后调用writev()来发送。


一、发送http包头

1、ngx_http_send_header()
    系统将各个包头过滤模块的处理加入ngx_http_next_header_filter指针链表中,在调用ngx_http_send_header()时,会依次调用所有头部的过滤模块。这些模块是处理r->headers_outs 中的内容。
    包头Filter模块的调用链表是如何实现的,请见下面2.2中的包体Filter模块的调用链表的说明。

2、 ngx_http_header_filter()   
   包头Filter模块处理链表最后一个头部过滤的方法负责发送头部。 包头最后的过滤模块就是ngx_http_header_filter_module。  ngx_http_header_filter(),它 将r->header_outs的内容序列化并发送出去。如果一次发送不完,需要将剩下的响应头部保存到r->out链表中,以备后续发送:
ngx_int_t ngx_http_header_filter(ngx_http_request_t *r)
{
  ngx_chain_t out;

   if (r->header_sent) return NGX_OK;
   r->header_sent = 1;

   //将r->header_outs的内容序列化为http包头
  ......
  return  ngx_http_write_filter(r, &out);  //发送包头
}

3、ngx_http_write_filter()  //ngx_http_writer_filter_module  
    这是包头Filter模块处理链表的最后一个 模块ngx_http_writer_filter_module的处理方法。发送包头、包体都用这个的:
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
  ngx_chain_t      *chain;
  ngx_connection_t *c;

  c = r->connection;
  ... //将in追加如r->out的尾部。

  if (c->write->delayed) {
     c->buffered |= NGX_HTTP_WRITE_BUFFERED;
     return NGX_AGAIN;
  }

  //send_chain返回的是没有发完的chain
  chain = c-> send_chain(c, r->out, limit);

  r->out = chain;
   //如果chain不为空,那么buf没有发送完,需要设置buffered标记,并返回NGX_AGAIN
  if (chain) 
  {
      c-> buffered |= NGX_HTTP_WRITE_BUFFERED;
      return  NGX_AGAIN;
  }

   //如果已经没有未发送的chain,就清空buffered标记
  c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;

   //如果其他filter模块buffer了chain并且postponed为NULL,那么返回NGX_AGAIN,需要继续处理buf
  if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
      return  NGX_AGAIN;
  }

  return  NGX_OK;
}
    如果无法一次发送,则将剩余内容保存到r->out中,并返回NGX_AGAIN。
    返回到ngx_http_finalize_request(),这时http框架就会继续将可写事件注册到epoll。

其中,c->send_chain在 ngx_event_accept()和 ngx_event_connect_peer()中设置:
    c->recv = ngx_recv;
    c->send = ngx_send;
    c->recv_chain = ngx_recv_chain;
    c->send_chain = ngx_send_chain;

ngx_send_chain最后调用了  ngx_writev_chain.c的
ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
   |- ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec);
            |- writev( c->fd, vec->iovs, vec->count );
    
4、ngx_http_finalize_request()
    ngx_http_write_filter()的返回值的最终会在ngx_http_finalize_request()中处理,该函数 负责根据返回值调整 当前请求的后续流程,包括结束请求:
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
    if (rc ==  NGX_DONE) {
        ngx_http_finalize_connection(r);
        return;
    }

    if (rc ==  NGX_OK && r->filter_finalize) {
        c->error = 1;
    }

    if (rc ==  NGX_DECLINED) {
        r->content_handler = NULL;
        r->write_event_handler =  ngx_http_core_run_phases;
        ngx_http_core_run_phases(r);
        return;
    }

    if (rc ==  NGX_ERROR
        || rc == NGX_HTTP_REQUEST_TIME_OUT
        || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
        || c->error)
    {
        if (ngx_http_post_action(r) == NGX_OK)
            return;

        if (r->main->blocked) 
            r->write_event_handler = ngx_http_request_finalizer;

        ngx_http_terminate_request(r, rc);
        return;
    }    

     ...
    if (r->buffered || c-> buffered || r->postponed || r->blocked) {
         //这里应该就是默认的NGX_AGAIN
        if ( ngx_http_set_write_handler(r) != NGX_OK) 
            ngx_http_terminate_request(r, 0);

        return;
    } 

    if (c->read->eof) {
        ngx_http_close_request(r, 0);
        return;
    }

     ngx_http_finalize_connection(r);      
}
    每个请求动作结束时都会调用ngx_http_finalize_request()函数来结束请求。 其中,如果完成或出错则终止连接;如果默认且数据未发完,则调用 ngx_http_set_write_handler()来处理。
    
5、ngx_http_set_write_handler()
    该函数(ngx_http_request.c中)中 调用了 ngx_handle_write_event()将当前连接的写事件重新加入epoll:
ngx_int_t  ngx_http_set_write_handler(ngx_http_request_t *r)
{
    ngx_event_t               *wev;
    ngx_http_core_loc_conf_t  *clcf;

    r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
    r->write_event_handler =  ngx_http_writer;

    wev = r->connection->write;

    ...
    if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
        ngx_http_close_request(r, 0);
        return NGX_ERROR;
    }

    return NGX_OK;
}

6、void ngx_http_writer()
    该函数(ngx_http_request.c中)中调用了ngx_http_output_filter发送。并根据结果重设epoll事件。
void ngx_http_writer(ngx_http_request_t *r)
{
    int                        rc;
    ngx_event_t               *wev;
    ngx_connection_t          *c;
    ngx_http_core_loc_conf_t  *clcf;

    c = r->connection;
     wev = c->write;

    clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);

     //首先处理写事件超时
    if (wev->timedout) 
    {
        if (!wev->delayed) 
        {
            c->timedout = 1;

            ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
            return;
        }

        wev->timedout = 0;
        wev->delayed = 0;

        //如果写事件延迟了但仍未准备好,重新放入epoll事件
        if (!wev->ready) 
        {
            ngx_add_timer(wev, clcf->send_timeout);

            if ( ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) 
                ngx_http_close_request(r, 0);

            return;
        }
    }

     //未超时时,但事件需要延期,重新加入epoll事件。
    if (wev->delayed || r->aio) 
    {
        if ( ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) 
            ngx_http_close_request(r, 0);

        return;
    }

    rc =  ngx_http_output_filter(r, NULL);
    if (rc == NGX_ERROR) 
    {
        ngx_http_finalize_request(r, rc);
        return;
    }

    //已经发送完了包了,如果当前还在接收数据,或需要延期时,进行的处理
    if (r->buffered || r->postponed || (r == r->main && c->buffered)) 
    {
         //如果没有写延期,将启动超时定时器
        if (!wev->delayed) 
            ngx_add_timer(wev, clcf->send_timeout);

         //将当前写事件加入epoll中等待处理。
        if ( ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
            ngx_http_close_request(r, 0);

        return;
    }

     //即不再处理写事件了
     r->write_event_handler = ngx_http_request_empty_handler;

    ngx_http_finalize_request(r,  rc);
}


二、发送包体
    发送包头执行的也就是ngx_http_writer()中调用的ngx_http_output_filter这个函数。而发送包体 也要先经过包体 过滤模块来处理,最后再发送。

1、ngx_http_output_filter()
typedef ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_http_output_body_filter_pt    ngx_http_top_body_filter;

ngx_int_t  ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    return ngx_http_top_body_filter(r, in);
}

2、 ngx_http_write_filter()   //ngx_http_writer_filter_module
    如下可见通过各包体Filter模块的本地变量ngx_http_next_body_filter,形成了一个包体Filter模块的调用链表。最后调用的ngx_http_top_body_filter 就是 ngx_http_write_filter_module模块的ngx_http_write_filter()。
    ngx_http_write_filter()的流程解析,参考前面 发送包头部分
//ngx_http_write_filter_module.c:
//ngx_http_write_filter_module_ctx的postconfiguration函数
ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf)
{
    ngx_http_top_body_filter =  ngx_http_write_filter;
    return NGX_OK;
}

//ngx_http_copy_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;

ngx_int_t ngx_http_copy_filter_init(ngx_conf_t *cf)
{
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_copy_filter;
    return NGX_OK;
}

//ngx_http_postpone_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;

ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf)
{
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_postpone_filter;
    return NGX_OK;
}
注意:
    ngx_http_top_body_filter是全局的。而ngx_http_next_body_filter静态的,当前filter文件中的,用于缓存全局变量,而在执行ngx_http_copy_filter完成时再把静态变量赋给全局的。
    ngx_http_write_filter_module是最后一个模块,因此不再设置ngx_http_next_body_filter了。
    这样实现了一个output filter链表,由Filter模块代码自己来加入链表,而不需修改其他代码。如nginx自己的gzip压缩处理等Filter模块就是这样被调用的。


3、结束请求

1、ngx_http_finalize_request()
    前面已经有分析了,所有发送结果都要返回这里重新进行分派,是终止连接、正常结束请求还是继续发送,视模块handler的返回值来定。

2、ngx_http_close_request()
    最终的结束请求的方法,在于其中调用的最后两个函数:
void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
{
    ngx_connection_t  *c;

    r = r->main;
    c = r->connection;

    r->count--;

    if (r->count || r->blocked) 
        return;

    ngx_http_free_request(r, rc); 
    ngx_http_close_connection(c);
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值