在nginx中request的buffer size我们能够通过两个命令进行设置,分别是large_client_header_buffers和client_header_buffer_size。这两个是有所不同的。
在解析request中,如果已经读取的request line 或者 request header大于lient_header_buffer_size的话,此时就会重新分配一块大的内存,然后将前面未完成解析的部分拷贝到当前的大的buf中,然后再进入解析处理,这部分的buf也就是large_client_header_buffers,也叫做large hader的处理。接下来我会通过代码来详细的分析这个过程。
 
首先来看client_header_buffer_size,他的默认值是1024,用这个值来初始化header_in(在ngx_http_init_request中)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26        if (c->buffer == NULL) {    //创建buffer            c->buffer = ngx_create_temp_buf(c->pool,                                            cscf->client_header_buffer_size);            if (c->buffer == NULL) {                ngx_http_close_connection(c);                return;            }        } if (r->header_in == NULL) {    //可以看到header_in就是上面创建的buffer,大小为client_header_buffer_size.            r->header_in = c->buffer;        } 
 
然后我们来看当已经接收的request line或者request header大于设置的client_header_buffer_size的时候,nginx如果处理,这里nginx判断接收的数据大小在两个地方,一个是在处理request line,一个是处理request header时候。首先来看的是处理request line的时候,下面这段代码是在ngx_http_process_request_line中的,到达下面这里说明request line只解析了一部分,因此这里需要判断是否分配的buf已经全部使用了,如果全部使用则需要进入large header的处理部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36    //如果pos等于 end,说明buf已经完全使用。            if (r->header_in->pos == r->header_in->end) {    //进入large header处理部分.                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;    //返回414给客户端.                    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;                }            } 
 
第二个地方就是处理request head,这部分是在ngx_http_process_request_headers中进行的,流程和上面的类似。
1 2 3 4 5 6 7 8 9 10 11 12                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;                    } 
 
从上面两段代码我们可以看到处理large header的部分都是在ngx_http_alloc_large_header_buffer中。因此接下来我们就来详细的分析这个函数。
首先来看这个函数的声明
1 2 3 4 5 6    static ngx_int_t    ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,        ngx_uint_t request_line) 
 
可以看到它的第二个函数表示了是在处理request line还是说是request header。我们来一段段的分析这个函数。
下面这段首先判断如果是在处理完request_line并且状态为0,则说明用户的request line的第一行是空(注释里面写的比较详细),此时我们需要忽略这个回车换行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14        if (request_line && r->state == 0) {            /\* the client fills up the buffer with "\r\n" \*/ r->request_length += r->header_in->end – r->header_in->start; r->header_in->pos = r->header_in->start;            r->header_in->last = r->header_in->start; return NGX_OK;        } 
 
然后接下来这部分就是判断已经解析完毕的request line或者header的大小是否大于large_client_header_buffers的大小,如果大于则说明当前的request 太长,所以直接返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18        old = request_line ? r->request_start : r->header_name_start; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);    //state不为0,则说明request未解析完毕,此时如果已经解析完毕的部分大小太大,则直接返回.        if (r->state != 0            && (size_t) (r->header_in->pos – old)                                         >= cscf->large_client_header_buffers.size)        {            return NGX_DECLINED;        } 
 
接下来这部分就是准备分配新的内存供request使用。这里有一个http_connection的概念,在nginx中,这个主要用于pipeline请求和keepalive请求,等以后详细分析pipeline和keepalive的时候会涉及到这个东西,现在只需要知道这个东西主要是为了buf的重用来设计的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62    //取得http_connection.        hc = r->http_connection;    //如果有已经被free,也就是空闲的buf,则我们就不用重新分配        if (hc->nfree) {    //直接取得buf。            b = hc->free[–hc->nfree]; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                           "http large header free: %p %uz",                           b->pos, b->end – b->last); } else if (hc->nbusy < cscf->large_client_header_buffers.num) {    //否则如果large_client_header_buffers的没有被使用完毕,则我们重新alloc新的buf.            if (hc->busy == NULL) {                hc->busy = ngx_palloc(r->connection->pool,                      cscf->large_client_header_buffers.num \* sizeof(ngx_buf_t \*));                if (hc->busy == NULL) {                    return NGX_ERROR;                }            }    //创建新的buf            b = ngx_create_temp_buf(r->connection->pool,                                    cscf->large_client_header_buffers.size);            if (b == NULL) {                return NGX_ERROR;            } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                           "http large header alloc: %p %uz",                           b->pos, b->end – b->last); } else {    //否则直接返回。            return NGX_DECLINED;        } 
 
下面这段就开始复制request buf.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46    //这里nbusy作为一个计数,用来限制large_client_header_buffers中限制的buf个数        hc->busy[hc->nbusy++] = b; if (r->state == 0) {            /*             * r->state == 0 means that a header line was parsed successfully             * and we do not need to copy incomplete header line and             * to relocate the parser header pointers             */ r->request_length += r->header_in->end – r->header_in->start; r->header_in = b; return NGX_OK;        } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                       "http large header copy: %d", r->header_in->pos – old);    //设置大小        r->request_length += old – r->header_in->start;    //指向新的buf        new = b->start;    //开始复制        ngx_memcpy(new, old, r->header_in->pos – old);    //更新buf        b->pos = new + (r->header_in->pos – old);        b->last = new + (r->header_in->pos – old); 
 
最后一部分就是更新对应的指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76        if (request_line) {            r->request_start = new; if (r->request_end) {                r->request_end = new + (r->request_end – old);            } r->method_end = new + (r->method_end – old); r->uri_start = new + (r->uri_start – old);            r->uri_end = new + (r->uri_end – old); if (r->schema_start) {                r->schema_start = new + (r->schema_start – old);                r->schema_end = new + (r->schema_end – old);            } if (r->host_start) {                r->host_start = new + (r->host_start – old);                if (r->host_end) {                    r->host_end = new + (r->host_end – old);                }            } if (r->port_start) {                r->port_start = new + (r->port_start – old);                r->port_end = new + (r->port_end – old);            } if (r->uri_ext) {                r->uri_ext = new + (r->uri_ext – old);            } if (r->args_start) {                r->args_start = new + (r->args_start – old);            } if (r->http_protocol.data) {                r->http_protocol.data = new + (r->http_protocol.data – old);            } } else {            r->header_name_start = new;            r->header_name_end = new + (r->header_name_end – old);            r->header_start = new + (r->header_start – old);            r->header_end = new + (r->header_end – old);        } r->header_in = b;