现在的位置: 首页 > 综合 > 正文

nginx源码分析(7)——请求处理

2013年10月04日 ⁄ 综合 ⁄ 共 16719字 ⁄ 字号 评论关闭

        在建立连接过程中,对于nginx监听到的每个客户端连接,都会将它的读事件的handler设置为ngx_http_init_request函数,这个函数就是请求处理的入口。在处理请求时,主要就是要解析http请求,比如:uri,请求行等,然后再根据请求生成响应。下面看一下nginx处理的具体过程。

1. ngx_http_init_request

        在ngx_http_init_connection函数中,将连接的读事件的handler设置为这个函数,在客户端发送请求时会被调用。

    /* ngx_event_t的data域存放事件对应的连接句柄 */
    c = rev->data;

    /* 在ngx_init_connection中对读事件添加了timer,超时直接返回*/
    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");

        ngx_http_close_connection(c);
        return;
    }

    /* 连接处理的request的计数 */
    c->requests++;

    /* ngx_http_connection_t */
    hc = c->data;

    if (hc == NULL) {
        hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));
        if (hc == NULL) {
            ngx_http_close_connection(c);
            return;
        }
    }

    r = hc->request;

    if (r) {
        ngx_memzero(r, sizeof(ngx_http_request_t));

        r->pipeline = hc->pipeline;

        if (hc->nbusy) {
            r->header_in = hc->busy[0];
        }

    } else {
    	/* 为request分配空间 */
        r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t));
        if (r == NULL) {
            ngx_http_close_connection(c);
            return;
        }

        hc->request = r;
    }

    c->data = r;
    r->http_connection = hc;

    c->sent = 0;
    r->signature = NGX_HTTP_MODULE;

        上面一段代码完成获取连接、请求并进行一部分初始化工作,比如会为新的请求分配内存。

    /**
     * ngx_listening_t的servers存放监听同一端口的server,但它们的监听的地址可以不同。
     * 
     * 		      port
     * 		   /   |   \
     * 	        addr1 addr2 addr3 	   
     *           |     |     |
     *          conf1 conf2  conf3
     */
    port = c->listening->servers;

    r->connection = c;

    if (port->naddrs > 1) {

        /*
         * there are several addresses on this port and one of them
         * is an "*:port" wildcard so getsockname() in ngx_http_server_addr()
         * is required to determine a server address
         */

    	/* 获取连接c的socket绑定的本地地址 */
        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
            ngx_http_close_connection(c);
            return;
        }

        /* 根据连接c的socket地址匹配port->addrs,找到对应的address:port */
        switch (c->local_sockaddr->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            sin6 = (struct sockaddr_in6 *) c->local_sockaddr;

            addr6 = port->addrs;

            /* the last address is "*" */

            for (i = 0; i < port->naddrs - 1; i++) {
                if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
                    break;
                }
            }

            addr_conf = &addr6[i].conf;

            break;
#endif

        default: /* AF_INET */
            sin = (struct sockaddr_in *) c->local_sockaddr;

            addr = port->addrs;

            /* the last address is "*" */

            for (i = 0; i < port->naddrs - 1; i++) {
                if (addr[i].addr == sin->sin_addr.s_addr) {
                    break;
                }
            }

            addr_conf = &addr[i].conf;

            break;
        }

    } else {

        switch (c->local_sockaddr->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            addr6 = port->addrs;
            addr_conf = &addr6[0].conf;
            break;
#endif

        default: /* AF_INET */
            addr = port->addrs;
            addr_conf = &addr[0].conf;
            break;
        }
    }

    /* virtual hosts based on the address:port */
    r->virtual_names = addr_conf->virtual_names;

    /* the default server configuration for the address:port */
    cscf = addr_conf->default_server;

    /* 初始化为default server的配置,后续虚拟主机匹配成功会采用对应的配置 */
    r->main_conf = cscf->ctx->main_conf;
    r->srv_conf = cscf->ctx->srv_conf;
    r->loc_conf = cscf->ctx->loc_conf;

        注释中解释的很清楚,这段代码是为地址addr:port匹配server config,从而确定该请求的配置。由于nginx支持虚拟主机,所以这里确定了r->virtual_names是该addr:port对应的虚拟主机数组,后面会根据请求的HOST匹配对应的虚拟主机从而确定最终的配置。nginx的每个请求都有执行环境,这个环境就是ngx_request_t请求的main_conf、srv_conf和loc_conf。请求的执行环境就是nginx各个模块的配置信息,根据这些信息的不同请求的处理效果是不一样的。待解释完虚拟主机匹配后,再详细说明执行环境查找。

    rev->handler = ngx_http_process_request_line;
    r->read_event_handler = ngx_http_block_reading;

        将连接读事件的handler设置为ngx_http_process_request_line,在本方法的最后会直接调用rev->handler(rev)。为什么这么做?

        我的猜测是,在客户端第一次请求时,该连接的读事件的handler是ngx_init_request,用于处理话请求,后续请求直接复用,所以不需要执行ngx_init_request,所以需要将rev->handler设置成ngx_http_process_request_line,最后直接调用handler是为了在ngx_init_request中处理第一个请求。不知道这样对不对?

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    c->log->file = clcf->error_log->file;
    if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
        c->log->log_level = clcf->error_log->log_level;
    }

    /* initialise the temporary buffer for the request's connection */
    if (c->buffer == NULL) {
        c->buffer = ngx_create_temp_buf(c->pool,
                                        cscf->client_header_buffer_size);
        if (c->buffer == NULL) {
            ngx_http_close_connection(c);
            return;
        }
    }

    /* raw request header string will be stored in the connection's buffer */
    if (r->header_in == NULL) {
        r->header_in = c->buffer;
    }

    /* initialise the memory pool of the request */
    r->pool = ngx_create_pool(cscf->request_pool_size, c->log);
    if (r->pool == NULL) {
        ngx_http_close_connection(c);
        return;
    }

        初始化连接的日志信息,为连接分配临时buffer,将request的header_in指向该临时buffer,后面会看到header_in用于存放请求头信息。然后为该请求分配内存池。

    if (ngx_list_init(&r->headers_out.headers, r->pool, 20,
                      sizeof(ngx_table_elt_t))
        != NGX_OK)
    {
        ngx_destroy_pool(r->pool);
        ngx_http_close_connection(c);
        return;
    }

    // ?
    r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
    if (r->ctx == NULL) {
        ngx_destroy_pool(r->pool);
        ngx_http_close_connection(c);
        return;
    }

        为http响应header分配空间,request的ctx属性目前不知道干什么用的。。。

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    /**
     * 为所有变量在此请求中分配空间
     * Allocate memory space for the variable values of the request.
     * The type of variables array is ngx_http_variable_value_t.
     */
    r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
                                        * sizeof(ngx_http_variable_value_t));
    if (r->variables == NULL) {
        ngx_destroy_pool(r->pool);
        ngx_http_close_connection(c);
        return;
    }

        nginx中的变量的生命周期是基于请求的,也就是说请求之间的变量时独立的。request的variables相当于变量的值,cmcf->variables相当于变量的定义。为了处理变量,nginx实现了一个小型的脚本引擎,也就是一个解释器。在解析配置文件时生成了代码,在处理请求时去执行这个代码,具体就是在ngx_http_rewrite_module注册的phase handler中处理的,后面介绍nginx变量机制时再详细说明。

        这里就是为请求分配所有变量的占用空间。

    c->single_connection = 1;
    c->destroyed = 0;

    /* 主请求 */
    r->main = r;
    r->count = 1;

    /* Store start time of the request */
    tp = ngx_timeofday();
    r->start_sec = tp->sec;
    r->start_msec = tp->msec;

    /* HTTP method, e.g. POST, GET, PUT */
    r->method = NGX_HTTP_UNKNOWN;

    r->headers_in.content_length_n = -1;
    r->headers_in.keep_alive_n = -1;
    r->headers_out.content_length_n = -1;
    r->headers_out.last_modified_time = -1;

    r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;

    /* 子请求个数的限制 */
    r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1;

    r->http_state = NGX_HTTP_READING_REQUEST_STATE;

    ctx = c->log->data;
    ctx->request = r;
    ctx->current_request = r;
    r->log_handler = ngx_http_log_error_handler;

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

    /* Start processing request */
    rev->handler(rev);

        对连接和请求的属性进行初始化,后面讲解subrequest时再具体分析r->main和r->subrequests。最后调用rev->handler(rev)实际就是调用ngx_http_process_request_line。

2. ngx_http_process_request_line

        这个函数是用来处理请求行的,会不断调用ngx_http_read_request_header从socket读取头部并保存在request的header_in字段中,实际上header_in是一个缓冲区,就是指向连接的临时缓冲区。

    c = rev->data;
    r = c->data;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                   "http process request line");

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        c->timedout = 1;
        ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
        return;
    }

        从rev中获取连接以及请求,并判断是否超时。

        http请求行格式是:

GET /index.php HTTP/1.1

        接下来的for循环就是试图从socket中读取足够的信息,然后解析出HTTP Method、URI以及HTTP版本等信息。

        if (rc == NGX_AGAIN) {

           /**
            * 读取请求行,保存到r->header_in缓冲区
            */
            n = ngx_http_read_request_header(r);

            if (n == NGX_AGAIN || n == NGX_ERROR) {
                return;
            }
        }

        读取request line并保存在header_in缓冲区。

        /**
         * 解析请求行,解析后的信息的是以r->uri_start,r->uri_end,r->arg_start等
         * 一些指针存储的,这些指针指向r->header_in
         */
        rc = ngx_http_parse_request_line(r, r->header_in);

        解析请求行,ngx_http_request_t中比如uri_start、uri_end、arg_start、request_start、request_end等指针用于请求行的解析,识别各个属性在header_in缓冲区中的指针的位置。ngx_http_parse_request_line在ngx_http_parse.c中,用于解析请求行,实际上就是一个状态机的实现,所有的状态包括:

    enum {
        sw_start = 0,
        sw_method,
        sw_spaces_before_uri,
        sw_schema,
        sw_schema_slash,
        sw_schema_slash_slash,
        sw_host,
        sw_port,
        sw_host_http_09,
        sw_after_slash_in_uri,
        sw_check_uri,
        sw_check_uri_http_09,
        sw_uri,
        sw_http_09,
        sw_http_H,
        sw_http_HT,
        sw_http_HTT,
        sw_http_HTTP,
        sw_first_major_digit,
        sw_major_digit,
        sw_first_minor_digit,
        sw_minor_digit,
        sw_spaces_after_digit,
        sw_almost_done
    } state;

        每个状态表示解析到哪一步,根据输入字符决定下一状态。这里不纠结于状态机的实现,只要记住在本方法调用完后请求行解析完毕,所有信息保存在request的字段中;要不就是解析没有完成,进行下一次迭代;要不就是解析出错。

        解析成功后,会根据ngx_http_request_t中用于解析的指针去初始化request中的属性,比如uri、args等。如果使用的是complex uri会进入其解析过程。

            /* the request line has been parsed successfully */

            r->request_line.len = r->request_end - r->request_start;
            r->request_line.data = r->request_start;


            if (r->args_start) {
                r->uri.len = r->args_start - 1 - r->uri_start;
            } else {
                r->uri.len = r->uri_end - r->uri_start;
            }

        初始化request_line属性,是一个ngx_str_t,然后初始化uri的长度。

           if (r->complex_uri || r->quoted_uri) {

                r->uri.data = ngx_pnalloc(r->pool, r->uri.len + 1);
                if (r->uri.data == NULL) {
                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                    return;
                }

                cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

                rc = ngx_http_parse_complex_uri(r, cscf->merge_slashes);

                if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) {
                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                  "client sent invalid request");
                    ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                    return;
                }

            } else {
                r->uri.data = r->uri_start;
            }

        初始化uri的data字段,如果使用complex uri就进入其解析过程,否则直接赋值为uri_start。

            /* 未解析的uri */
            r->unparsed_uri.len = r->uri_end - r->uri_start;
            r->unparsed_uri.data = r->uri_start;

            r->valid_unparsed_uri = r->space_in_uri ? 0 : 1;

            /* http method */
            r->method_name.len = r->method_end - r->request_start + 1;
            r->method_name.data = r->request_line.data;


            if (r->http_protocol.data) {
                r->http_protocol.len = r->request_end - r->http_protocol.data;
            }


            if (r->uri_ext) {
                if (r->args_start) {
                    r->exten.len = r->args_start - 1 - r->uri_ext;
                } else {
                    r->exten.len = r->uri_end - r->uri_ext;
                }

                r->exten.data = r->uri_ext;
            }

            /* 请求参数 */
            if (r->args_start && r->uri_end > r->args_start) {
                r->args.len = r->uri_end - r->args_start;
                r->args.data = r->args_start;
            }

        接下来对其他的属性初始化。

            /* 解析并验证host */
            if (r->host_start && r->host_end) {

                host = r->host_start;
                n = ngx_http_validate_host(r, &host,
                                           r->host_end - r->host_start, 0);

                if (n == 0) {
                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                  "client sent invalid host in request line");
                    ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                    return;
                }

                if (n < 0) {
                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                    return;
                }

                /* 初始化request header的server字段 */
                r->headers_in.server.len = n;
                r->headers_in.server.data = host;
            }

        解析并验证host,然后初始化request header的server字段。

            if (r->http_version < NGX_HTTP_VERSION_10) {

            	/**
            	 * 根据请求的host,即虚拟主机名,去查找对应的server
            	 */
                if (ngx_http_find_virtual_server(r, r->headers_in.server.data,
                                                 r->headers_in.server.len)
                    == NGX_ERROR)
                {
                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                    return;
                }

                ngx_http_process_request(r);
                return;
            }

        如果使用的http协议版本小于1.0,那么不支持header以及请求体,所以接下来直接调用ngx_http_process_request处理请求。前面已经介绍过根据请求的addr:port确定了该请求的虚拟主机集合,接下来就要根据请求的host确定具体是哪个虚拟主机来处理该请求,通过ngx_http_find_virtual_server处理,r->headers_in.server存放的就是host。这个函数处理的很简单,因为已经将该addr:port对应的虚拟主机集合组织成map,首先是根据host从这个map中get,如果有对应的虚拟主机直接返回。如果没有,但是nginx提供正则表达式支持,则逐一进行匹配直到找一个为止。找到host对应的虚拟主机后,最重要的是将request的执行环境设置为该虚拟主机对应的配置。ngx_http_process_request后面会详说。对于http0.9然后会直接返回,而1.0或1.1还有没有处理完。

            /* Initialise list for request headers */
            if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
                              sizeof(ngx_table_elt_t))
                != NGX_OK)
            {
                ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                return;
            }


            /* Initialise array for request cookies  */
            if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
                               sizeof(ngx_table_elt_t *))
                != NGX_OK)
            {
                ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                return;
            }

            c->log->action = "reading client request headers";

        因为http1.0和http1.1支持header和cookie,这里先为它们分配空间,后面再解析这些数据。

            /* process request headers */
            rev->handler = ngx_http_process_request_headers;
            ngx_http_process_request_headers(rev);

            return;

        设置读事件rev的handler为ngx_http_process_request_headers,然后调用ngx_http_process_request_headers进行header解析。

        下面先看看for循环的最后部分,主要是错误处理和缓冲区扩容。

        if (rc != NGX_AGAIN) {

            /* there was error while a request line parsing */

            ngx_log_error(NGX_LOG_INFO, c->log, 0,
                          ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]);
            ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
            return;
        }

        请求解析出错,这里会终结这个请求,并log。

        /* NGX_AGAIN: a request line parsing is still incomplete */

        if (r->header_in->pos == r->header_in->end) {

            rv = ngx_http_alloc_large_header_buffer(r, 1);

            if (rv == NGX_ERROR) {
                ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                return;
            }

            if (rv == NGX_DECLINED) {
                r->request_line.len = r->header_in->end - r->request_start;
                r->request_line.data = r->request_start;

                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client sent too long URI");
                ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
                return;
            }
        }

        rc等于NGX_AGAIN,说起request line没有处理完毕,如果header_in大小不够,则调用ngx_http_alloc_large_header_buffer进行扩容。

3. ngx_http_process_request_headers

        这个函数处理request header。

    c = rev->data;
    r = c->data;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                   "http process request header line");

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        c->timedout = 1;
        ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
        return;
    }

        获取连接和请求,并判断超时。接下来for循环会一次解析一个header。

           if (r->header_in->pos == r->header_in->end) {

                rv = ngx_http_alloc_large_header_buffer(r, 0);

                if (rv == NGX_ERROR) {
                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                    return;
                }

                if (rv == NGX_DECLINED) {
                    p = r->header_name_start;

                    r->lingering_close = 1;

                    if (p == NULL) {
                        ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                      "client sent too large request");
                        ngx_http_finalize_request(r,
                                            NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
                        return;
                    }

                    len = r->header_in->end - p;

                    if (len > NGX_MAX_ERROR_STR - 300) {
                        len = NGX_MAX_ERROR_STR - 300;
                        p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
                    }

                    ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                  "client sent too long header line: \"%*s\"",
                                  len, r->header_name_start);

                    ngx_http_finalize_request(r,
                                            NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
                    return;
                }
            }

            n = ngx_http_read_request_header(r);

            if (n == NGX_AGAIN || n == NGX_ERROR) {
                return;
            }

        首先还是先判断缓冲区大小是否够用,如果不够用就扩容,扩容失败就会退出。然后调用ngx_http_read_request_header读取请求并存到header_in缓冲区。

        rc = ngx_http_parse_header_line(r, r->header_in,
                                        cscf->underscores_in_headers);

        调用ngx_http_parse_header_line解析header,其内部实现和ngx_http_parse_request_line一样,都是状态机,这个函数会一次解析一个header,实际上就是一行。
        如果解析成功,即rc等NGX_OK,会执行:

            if (r->invalid_header && cscf->ignore_invalid_headers) {

                /* there was error while a header line parsing */

                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client sent invalid header line: \"%*s\"",
                              r->header_end - r->header_name_start,
                              r->header_name_start);
                continue;
            }

        解析到不合法的header,log然后解析下一个header。否则,说明成功解析了一个header,会进行header的初始化。

            /* r->header_hash是当前解析得到的header的hash值 */
            h->hash = r->header_hash;

            h->key.len = r->header_name_end - r->header_name_start;
            h->key.data = r->header_name_start;
            h->key.data[h->key.len] = '\0';

            h->value.len = r->header_end - r->header_start;
            h->value.data = r->header_start;
            h->value.data[h->value.len] = '\0';

            h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
            if (h->lowcase_key == NULL) {
                ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                return;
            }

            if (h->key.len == r->lowcase_index) {
                ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);

            } else {
                ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
            }

         把解析出的header添加到request的headers_in.header链表中,然后对其初始化,包括:header的name、value等。

            hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
                               h->lowcase_key, h->key.len);

            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
                return;
            }

        在http模块的初始化函数ngx_http_block中,会调用ngx_http_init_headers_in_hash将所有可能的header初始化成hash map,然后保存至ngx_http_core_main_conf_t的headers_in_hash字段中。在ngx_http_request.c中,定义的ngx_http_headers_in数组就是所有可能的header。这里会查看解析出的header是否在这个map,如果在的话会调用对应的handler进行初始化。

        如果rc等于NGX_HTTP_PARSE_HEADER_DONE,说明header解析完毕,接下来会执行:

        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */

            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http header done");

            r->request_length += r->header_in->pos - r->header_in->start;

            r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;

            /* 根据host匹配虚拟主机,并对一些header初始化 */
            rc = ngx_http_process_request_header(r);

            if (rc != NGX_OK) {
                return;
            }

            ngx_http_process_request(r);

            return;
        }

        会调用ngx_http_process_request_header函数解析虚拟主机,并对一些header初始化。然后调用ngx_http_process_request进行后续的请求处理。ngx_http_process_request_headers的最后部分就是错误处理,这里不详述,下面看一下请求的处理部分。

4. ngx_http_process_request

        这个函数驱动请求的处理,并为处理做些准备。

    /* remove timer of read event of the connection */
    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }

        删除掉之前设置的读事件的timer。

    c->read->handler = ngx_http_request_handler;
    c->write->handler = ngx_http_request_handler;
    r->read_event_handler = ngx_http_block_reading;

        设置读写事件的handler为ngx_http_request_handler,这个函数貌似是处理subrequest的,还不敢确定。

    ngx_http_handler(r);

    // 处理subrequest
    ngx_http_run_posted_requests(c);

        调用ngx_http_handler继续处理请求,ngx_http_run_posted_requests函数是处理子请求的。

5. ngx_http_handler

        为跑一遍所有phase hander做准备。

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

    r->connection->unexpected_eof = 0;

    /**
     * 初始化r->phase_handler
     */
    if (!r->internal) {
        switch (r->headers_in.connection_type) {
        case 0:
            r->keepalive = (r->http_version > NGX_HTTP_VERSION_10);
            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->phase_handler = 0;

    } else {
        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
        r->phase_handler = cmcf->phase_engine.server_rewrite_index;
    }

        初始化request的phase_handler,实际上就是第一个执行的phase handler在handlers数组中的下标。

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

        设置request的write_event_handler为ngx_http_core_run_phases,然后再调用这个函数把请求对应的phase handler执行一遍。下面看这个函数。

6. ngx_http_core_run_phases

        nginx把请求的处理划分成11个阶段,其中一些阶段可以自定义添加handler,这个函数就是执行请求对应对应所有的phase handler。对应nginx对phase handler的处理会在之后的文章中分析。

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    ph = cmcf->phase_engine.handlers;

        ngx_http_core_main_conf_t的phase_engine的handlers就是所有的phase handler组成的数组。

    /* 遍历phase上注册的所有handler,这里是以r->phase_handler为索引组成的链表 */
    while (ph[r->phase_handler].checker) {

        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

        if (rc == NGX_OK) {
            return;
        }
    }

        遍历phase上注册的所有handler,这里是以r->phase_handler为索引组成的链表。在调用每个handler的checker时会更新request的phase_handler,从而实现一个handler的链表。

        在跑完所有的phase handler之后,这个请求就被处理完毕。实际的响应内容的输出,是在content phase的handler中调用filter输出实现的。下一篇文章会介绍nginx的phase handler的处理,后面还会介绍filter实现。

抱歉!评论已关闭.