nginx&http 第三章 ngx 请求处理的 11 个阶段 --ngx_http_process_request& ngx_http_handler

ngx_http_process_request

如果设置了定时器则删除,既然所有的请求已经接收完毕,就不会再发生超时了
重设连接的读写回调函数
重设请求读事件回调函数
调用 ngx_http_handler 处理 HTTP 请求的 11 个阶段
调用 ngx_http_run_posted_requests 处理 posted_requests 队列中的 POST 请
/*
ngx_http_process_request方法负责在接收完HTTP头部后,第一次与各个HTTP模块共同按阶段处理请求,而对于ngx_http_request_handler方法,
如果ngx_http_process_request没能处理完请求,这个请求上的事件再次被触发,那就将由此方法继续处理了。
*/
//ngx_http_process_request_headers头部行解析完毕后调用函数ngx_http_process_request_header
void
ngx_http_process_request(ngx_http_request_t *r) 
{
    ngx_connection_t  *c;

    c = r->connection;

#if (NGX_HTTP_SSL)

    if (r->http_connection->ssl) {
        long                      rc;
        X509                     *cert;
        ngx_http_ssl_srv_conf_t  *sscf;

        if (c->ssl == NULL) {
            ngx_log_error(NGX_LOG_INFO, c->log, 0,
                          "client sent plain HTTP request to HTTPS port");
            ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
            return;
        }

        sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);

        if (sscf->verify) {
            rc = SSL_get_verify_result(c->ssl->connection);

            if (rc != X509_V_OK
                && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
            {
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client SSL certificate verify error: (%l:%s)",
                              rc, X509_verify_cert_error_string(rc));

                ngx_ssl_remove_cached_session(sscf->ssl.ctx,
                                       (SSL_get0_session(c->ssl->connection)));

                ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
                return;
            }

            if (sscf->verify == 1) {
                cert = SSL_get_peer_certificate(c->ssl->connection);

                if (cert == NULL) {
                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                  "client sent no required SSL certificate");

                    ngx_ssl_remove_cached_session(sscf->ssl.ctx,
                                       (SSL_get0_session(c->ssl->connection)));

                    ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
                    return;
                }

                X509_free(cert);
            }
        }
    }

#endif
    /*
    由于现在已经开始准备调用各HTTP模块处理请求了,因此不再存在接收HTTP请求头部超时的问题,那就需要从定时器中把当前连接的读事件移除了。
    检查读事件对应的timer_set标志位,力1时表示读事件已经添加到定时器中了,这时需要调用ngx_del_timer从定时器中移除读事件;
     */
    if (c->read->timer_set) {//ngx_http_read_request_header中读取不到数据的时候返回NGX_AGIN,会添加定时器和读事件表示继续等待客户端数据到来
        ngx_del_timer(c->read, NGX_FUNC_LINE);
    }

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
    r->stat_reading = 0;
    (void) ngx_atomic_fetch_add(ngx_stat_writing, 1);
    r->stat_writing = 1;
#endif

/*
从现在开始不会再需要接收HTTP请求行或者头部,所以需要重新设置当前连接读/写事件的回调方法。在这一步骤中,将同时把读事件、写事件的回调
方法都设置为ngx_http_request_handler方法,请求的后续处理都是通过ngx_http_request_handler方法进行的。
 */
    c->read->handler = ngx_http_request_handler; //由读写事件触发ngx_http_request_handler  //由epoll读事件在ngx_epoll_process_events触发
    c->write->handler = ngx_http_request_handler;   //由epoll写事件在ngx_epoll_process_events触发

/*
设置ngx_http_request_t结构体的read_event_handler方法gx_http_block_reading。当再次有读事件到来时,将会调用ngx_http_block_reading方法
处理请求。而这里将它设置为ngx_http_block_reading方法,这个方法可认为不做任何事,它的意义在于,目前已经开始处理HTTP请求,除非某个HTTP模块重新
设置了read_event_handler方法,否则任何读事件都将得不到处理,也可似认为读事件被阻 塞了。
*/
    r->read_event_handler = ngx_http_block_reading; //表示暂时不要读取客户端请求    

    /* ngx_http_process_request和ngx_http_request_handler这两个方法的共通之处在于,它们都会先按阶段调用各个HTTP模块处理请求,再处理post请求 */
    ngx_http_handler(r); //这里面会执行ngx_http_core_run_phases,执行11个阶段

/*
HTTP框架无论是调用ngx_http_process_request方法(首次从业务上处理请求)还是ngx_http_request_handler方法(TCP连接上后续的事件触发时)处理
请求,最后都有一个步骤,就是调用ngx_http_run_posted_requests方法处理post请求

11个阶段执行完毕后,调用ngx_http_run_posted_requests方法执行post请求,这里一般都是对subrequest进行处理
*/
    ngx_http_run_posted_requests(c); /*  */
}

2、处理 HTTP 请求的准备工作 -- ngx_http_handler

在函数中,重新设置了读事件回调,那么请求的写事件回调是在 ngx_http_handler 函数中重设的

//ngx_http_process_request->ngx_http_handler->ngx_http_core_run_phases
//ngx_http_run_posted_requests->ngx_http_handler
void
ngx_http_handler(ngx_http_request_t *r) /* 执行11个阶段的指定阶段 */
{
    ngx_http_core_main_conf_t  *cmcf;

    r->connection->log->action = NULL;

    r->connection->unexpected_eof = 0;

/*
    检查ngx_http_request_t结构体的internal标志位,如果internal为0,则从头部phase_handler执行;如果internal标志位为1,则表示请求当前需要做内部跳转,
将要把结构体中的phase_handler序号置为server_rewrite_index。注意ngx_http_phase_engine_t结构体中的handlers动态数组中保存了请求需要经历的所有
回调方法,而server_rewrite_index则是handlers数组中NGX_HTTP_SERVER_REWRITE_PHASE处理阶段的第一个ngx_http_phase_handler_t回调方法所处的位置。
    究竟handlers数组是怎么使用的呢?事实上,它要配合着ngx_http_request_t结构体的phase_handler序号使用,由phase_handler指定着请求将要执行
的handlers数组中的方法位置。注意,handlers数组中的方法都是由各个HTTP模块实现的,这就是所有HTTP模块能够共同处理请求的原因。 
 */
    if (!r->internal) {
        
        switch (r->headers_in.connection_type) {
        case 0:
            r->keepalive = (r->http_version > NGX_HTTP_VERSION_10); //指明在1.0以上版本默认是长连接
            break;

        case NGX_HTTP_CONNECTION_CLOSE:
            r->keepalive = 0;
            break;

        case NGX_HTTP_CONNECTION_KEEP_ALIVE:
            r->keepalive = 1;
            break;
        }
    
        r->lingering_close = (r->headers_in.content_length_n > 0
                              || r->headers_in.chunked); 
        /*
       当internal标志位为0时,表示不需要重定向(如刚开始处理请求时),将phase_handler序号置为0,意味着从ngx_http_phase_engine_t指定数组
       的第一个回调方法开始执行(了解ngx_http_phase_engine_t是如何将各HTTP模块的回调方法构造成handlers数组的)。
          */
        r->phase_handler = 0;

    } else {
/* 
在这一步骤中,把phase_handler序号设为server_rewrite_index,这意味着无论之前执行到哪一个阶段,马上都要重新从NGX_HTTP_SERVER_REWRITE_PHASE
阶段开始再次执行,这是Nginx的请求可以反复rewrite重定向的基础。
*/
        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
        r->phase_handler = cmcf->phase_engine.server_rewrite_index;
    }

    r->valid_location = 1;
#if (NGX_HTTP_GZIP)
    r->gzip_tested = 0;
    r->gzip_ok = 0;
    r->gzip_vary = 0;
#endif

    r->write_event_handler = ngx_http_core_run_phases;
    ngx_http_core_run_phases(r);  
}

然后这个函数通过请求的 internal 字段判断是否从 0 号回调开始执行最后,就要进入请求的 11 个阶段的处理了 -- ngx_http_core_run_phases

/*  
    每个ngx_http_phases阶段对应的checker函数,处于同一个阶段的checker函数相同,见ngx_http_init_phase_handlers
    NGX_HTTP_SERVER_REWRITE_PHASE  -------  ngx_http_core_rewrite_phase
    NGX_HTTP_FIND_CONFIG_PHASE     -------  ngx_http_core_find_config_phase
    NGX_HTTP_REWRITE_PHASE         -------  ngx_http_core_rewrite_phase
    NGX_HTTP_POST_REWRITE_PHASE    -------  ngx_http_core_post_rewrite_phase
    NGX_HTTP_ACCESS_PHASE          -------  ngx_http_core_access_phase
    NGX_HTTP_POST_ACCESS_PHASE     -------  ngx_http_core_post_access_phase
    NGX_HTTP_TRY_FILES_PHASE       -------  NGX_HTTP_TRY_FILES_PHASE
    NGX_HTTP_CONTENT_PHASE         -------  ngx_http_core_content_phase
    其他几个阶段                   -------  ngx_http_core_generic_phase

    HTTP框架为11个阶段实现的checker方法  赋值见           ngx_http_init_phase_handlers
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃    阶段名称                  ┃    checker方法                   ┃
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃   NGX_HTTP_POST_READ_PHASE   ┃    ngx_http_core_generic_phase   ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP SERVER REWRITE PHASE ┃ngx_http_core_rewrite_phase       ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP FIND CONFIG PHASE    ┃ngx_http_core find config_phase   ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP REWRITE PHASE        ┃ngx_http_core_rewrite_phase       ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP POST REWRITE PHASE   ┃ngx_http_core_post_rewrite_phase  ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP PREACCESS PHASE      ┃ngx_http_core_generic_phase       ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP ACCESS PHASE         ┃ngx_http_core_access_phase        ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP POST ACCESS PHASE    ┃ngx_http_core_post_access_phase   ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP TRY FILES PHASE      ┃ngx_http_core_try_files_phase     ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP CONTENT PHASE        ┃ngx_http_core_content_phase       ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP LOG PHASE            ┃ngx_http_core_generic_phase       ┃
┗━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛
*/
/*
通常来说,在接收完HTTP头部后,是无法在一次Nginx框架的调度中处理完一个请求的。在第一次接收完HTTP头部后,HTTP框架将调度
ngx_http_process_request方法开始处理请求,如果某个checker方法返回了NGX_OK,则将会把控制权交还给Nginx框架。当这个请求
上对应的事件再次触发时,HTTP框架将不会再调度ngx_http_process_request方法处理请求,而是由ngx_http_request_handler方法
开始处理请求。例如recv虽然把头部行内容读取完毕,并能解析完成,但是可能有携带请求内容,内容可能没有读完
*/
//通过执行当前r->phase_handler所指向的阶段的checker函数
//ngx_http_process_request->ngx_http_handler->ngx_http_core_run_phases
void
ngx_http_core_run_phases(ngx_http_request_t *r) //执行该请求对于的阶段的checker(),并获取返回值
{
    ngx_int_t                   rc;
    ngx_http_phase_handler_t   *ph;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    ph = cmcf->phase_engine.handlers;

    while (ph[r->phase_handler].checker) { //处于同一ngx_http_phases阶段的所有ngx_http_phase_handler_t的checker指向相同的函数,见ngx_http_init_phase_handlers
/*
handler方法其实仅能在checker方法中被调用,而且checker方法由HTTP框架实现,所以可以控制各HTTP模块实现的处理方法在不同的阶段中采用不同的调用行为

ngx_http_request_t结构体中的phase_handler成员将决定执行到哪一阶段,以及下一阶段应当执行哪个HTTP模块实现的内容。可以看到请求的phase_handler成员
会被重置,而HTTP框架实现的checker穷法也会修改phase_handler成员的值

当checker方法的返回值非NGX_OK时,意味着向下执行phase_engine中的各处理方法;反之,当任何一个checker方法返回NGX_OK时,意味着把控制权交还
给Nginx的事件模块,由它根据事件(网络事件、定时器事件、异步I/O事件等)再次调度请求。然而,一个请求多半需要Nginx事件模块多次地调度HTTP模
块处理,也就是在该函数外设置的读/写事件的回调方法ngx_http_request_handler
*/
        // 所有的处理阶段回调函数构成了一个链表
        // NGX_HTTP_SERVER_REWRITE_PHASE    ngx_http_core_rewrite_phase
        // NGX_HTTP_FIND_CONFIG_PHASE        ngx_http_core_find_config_phase
        // NGX_HTTP_REWRITE_PHASE            ngx_http_core_rewrite_phase
        // NGX_HTTP_POST_REWRITE_PHASE        ngx_http_core_post_rewrite_phase
        // NGX_HTTP_PREACCESS_PHASE            ngx_http_core_generic_phase
        // NGX_HTTP_POST_READ_PHASE            ngx_http_limit_conn_handler
        // NGX_HTTP_ACCESS_PHASE            ngx_http_core_access_phase
        // NGX_HTTP_POST_ACCESS_PHASE        ngx_http_core_post_access_phase
        // NGX_HTTP_CONTENT_PHASE            ngx_http_core_content_phase
        // NGX_HTTP_TRY_FILES_PHASE            ngx_http_core_try_files_phase
        
        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

 /* 直接返回NGX OK会使待HTTP框架立刻把控制权交还给epoll事件框架,不再处理当前请求,唯有这个请求上的事件再次被触发才会继续执行。*/
        if (rc == NGX_OK) { //执行phase_handler阶段的hecker  handler方法后,返回值为NGX_OK,则直接退出,否则继续循环执行checker handler
            return;
        }
    }
}

 

posted @ 2020-02-25 17:54  codestacklinuxer  阅读(610)  评论(0编辑  收藏  举报