nginx的請求接收流程(二)


在ngx_http_process_request_line函數中,解析完請求行之后,如果請求行的uri里面包含了域名部分,則將其保持在請求結構的headers_in成員的server字段,headers_in用來保存所有請求頭,它的類型為ngx_http_headers_in_t:

[cpp]  view plain copy
 
  1. <span style="font-size: 18px; ">typedef struct {  
  2.     ngx_list_t                        headers;  
  3.   
  4.     ngx_table_elt_t                  *host;  
  5.     ngx_table_elt_t                  *connection;  
  6.     ngx_table_elt_t                  *if_modified_since;  
  7.     ngx_table_elt_t                  *if_unmodified_since;  
  8.     ngx_table_elt_t                  *user_agent;  
  9.     ngx_table_elt_t                  *referer;  
  10.     ngx_table_elt_t                  *content_length;  
  11.     ngx_table_elt_t                  *content_type;  
  12.   
  13.     ngx_table_elt_t                  *range;  
  14.     ngx_table_elt_t                  *if_range;  
  15.   
  16.     ngx_table_elt_t                  *transfer_encoding;  
  17.     ngx_table_elt_t                  *expect;  
  18.   
  19. #if (NGX_HTTP_GZIP)  
  20.     ngx_table_elt_t                  *accept_encoding;  
  21.     ngx_table_elt_t                  *via;  
  22. #endif  
  23.   
  24.     ngx_table_elt_t                  *authorization;  
  25.   
  26.     ngx_table_elt_t                  *keep_alive;  
  27.   
  28. #if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)  
  29.     ngx_table_elt_t                  *x_forwarded_for;  
  30. #endif  
  31.   
  32. #if (NGX_HTTP_REALIP)  
  33.     ngx_table_elt_t                  *x_real_ip;  
  34. #endif  
  35.   
  36. #if (NGX_HTTP_HEADERS)  
  37.     ngx_table_elt_t                  *accept;  
  38.     ngx_table_elt_t                  *accept_language;  
  39. #endif  
  40.   
  41. #if (NGX_HTTP_DAV)  
  42.     ngx_table_elt_t                  *depth;  
  43.     ngx_table_elt_t                  *destination;  
  44.     ngx_table_elt_t                  *overwrite;  
  45.     ngx_table_elt_t                  *date;  
  46. #endif  
  47.   
  48.     ngx_str_t                         user;  
  49.     ngx_str_t                         passwd;  
  50.     ngx_array_t                       cookies;  
  51.   
  52.     ngx_str_t                         server;  
  53.     off_t                             content_length_n;  
  54.     time_t                            keep_alive_n;  
  55.   
  56.     unsigned                          connection_type:2;  
  57.     unsigned                          msie:1;  
  58.     unsigned                          msie6:1;  
  59.     unsigned                          opera:1;  
  60.     unsigned                          gecko:1;  
  61.     unsigned                          chrome:1;  
  62.     unsigned                          safari:1;  
  63.     unsigned                          konqueror:1;  
  64. } ngx_http_headers_in_t;</span>  

接着,該函數會檢查進來的請求是否使用的是http0.9,如果是的話則使用從請求行里得到的域名,調用ngx_http_find_virtual_server()函數來查找用來處理該請求的虛擬服務器配置,之前通過端口和地址找到的默認配置不再使用,找到相應的配置之后,則直接調用ngx_http_process_request()函數處理該請求,因為http0.9是最原始的http協議,它里面沒有定義任何請求頭,顯然就不需要讀取請求頭的操作。

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">            if (r->host_start && r->host_end) {  
  2.   
  3.                 host = r->host_start;  
  4.                 n = ngx_http_validate_host(r, &host,  
  5.                                            r->host_end - r->host_start, 0);  
  6.   
  7.                 if (n == 0) {  
  8.                     ngx_log_error(NGX_LOG_INFO, c->log, 0,  
  9.                                   "client sent invalid host in request line");  
  10.                     ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);  
  11.                     return;  
  12.                 }  
  13.   
  14.                 if (n < 0) {  
  15.                     ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);  
  16.                     return;  
  17.                 }  
  18.   
  19.                 r->headers_in.server.len = n;  
  20.                 r->headers_in.server.data = host;  
  21.             }  
  22.   
  23.             if (r->http_version < NGX_HTTP_VERSION_10) {  
  24.   
  25.                 if (ngx_http_find_virtual_server(r, r->headers_in.server.data,  
  26.                                                  r->headers_in.server.len)  
  27.                     == NGX_ERROR)  
  28.                 {  
  29.                     ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);  
  30.                     return;  
  31.                 }  
  32.   
  33.                 ngx_http_process_request(r);  
  34.                 return;  
  35.             }</span>  

當然,如果是1.0或者更新的http協議,接下來要做的就是讀取請求頭了,首先nginx會為請求頭分配空間,ngx_http_headers_in_t結構的headers字段為一個鏈表結構,它被用來保存所有請求頭,初始為它分配了20個節點,每個節點的類型為ngx_table_elt_t,保存請求頭的name/value值對,還可以看到ngx_http_headers_in_t結構有很多類型為ngx_table_elt_t*的指針成員,而且從它們的命名可以看出是一些常見的請求頭名字,nginx對這些常用的請求頭在ngx_http_headers_in_t結構里面保存了一份引用,后續需要使用的話,可以直接通過這些成員得到,另外也事先為cookie頭分配了2個元素的數組空間,做完這些內存准備工作之后,該請求對應的讀事件結構的處理函數被設置為ngx_http_process_request_headers,並隨后馬上調用了該函數。

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">            if (ngx_list_init(&r->headers_in.headers, r->pool, 20,  
  2.                               sizeof(ngx_table_elt_t))  
  3.                 != NGX_OK)  
  4.             {  
  5.                 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);  
  6.                 return;  
  7.             }  
  8.   
  9.             if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,  
  10.                                sizeof(ngx_table_elt_t *))  
  11.                 != NGX_OK)  
  12.             {  
  13.                 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);  
  14.                 return;  
  15.             }  
  16.   
  17.             c->log->action = "reading client request headers";  
  18.   
  19.             rev->handler = ngx_http_process_request_headers;  
  20.             ngx_http_process_request_headers(rev);</span>  

ngx_http_process_request_headers函數循環的讀取所有的請求頭,並保存和初始化和請求頭相關的結構,下面詳細分析一下該函數:
因為nginx對讀取請求頭有超時限制,ngx_http_process_request_headers函數作為讀事件處理函數,一並處理了超時事件,如果讀超時了,nginx直接給該請求返回408錯誤:

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">    if (rev->timedout) {  
  2.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");  
  3.         c->timedout = 1;  
  4.         ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);  
  5.         return;  
  6.     }</span>  

讀取和解析請求頭的邏輯和處理請求行差不多,總的流程也是循環的調用ngx_http_read_request_header()函數讀取數據,然后再調用一個解析函數來從讀取的數據中解析請求頭,直到解析完所有請求頭,或者發生解析錯誤為主。當然由於涉及到網絡io,這個流程可能發生在多個io事件的上下文中。

接着來細看該函數,先調用了ngx_http_read_request_header()函數讀取數據,如果當前連接並沒有數據過來,再直接返回,等待下一次讀事件到來,如果讀到了一些數據則調用ngx_http_parse_header_line()函數來解析,同樣的該解析函數實現為一個有限狀態機,邏輯很簡單,只是根據http協議的解析一個請求頭的name/vale對,每次調用該函數最多解析出一個請求頭,該函數返回4種不同返回值,表示不同解析結果:

1,返回NGX_OK,表示解析出了一行請求頭,這時還要判斷解析出的請求頭名字里面是否有非法字符,名字里面合法的字符包括字母,數字和連字符(-),另外如果設置了underscores_in_headers指令為on,則下划線也是合法字符,但是nginx默認下划線不合法,當請求頭里面包含了非法的字符,nginx默認只是忽略這一行請求頭;如果一切都正常,nginx會將該請求頭及請求頭名字的hash值保存在請求結構體的headers_in成員的headers鏈表,而且對於一些常見的請求頭,如Host,Connection,nginx采用了類似於配置指令的方式,事先給這些請求頭分配了一個處理函數,當解析出一個請求頭時,會檢查該請求頭是否有設置處理函數,有的話則調用之,nginx所有有處理函數的請求頭都記錄在ngx_http_headers_in全局數組中:

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">typedef struct {  
  2.     ngx_str_t                         name;  
  3.     ngx_uint_t                        offset;  
  4.     ngx_http_header_handler_pt        handler;  
  5. } ngx_http_header_t;  
  6.   
  7. ngx_http_header_t  ngx_http_headers_in[] = {  
  8.     { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host),  
  9.                  ngx_http_process_host },  
  10.   
  11.     { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),  
  12.                  ngx_http_process_connection },  
  13.   
  14.     { ngx_string("If-Modified-Since"),  
  15.                  offsetof(ngx_http_headers_in_t, if_modified_since),  
  16.                  ngx_http_process_unique_header_line },  
  17.   
  18.     { ngx_string("If-Unmodified-Since"),  
  19.                  offsetof(ngx_http_headers_in_t, if_unmodified_since),  
  20.                  ngx_http_process_unique_header_line },  
  21.   
  22.     { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent),  
  23.                  ngx_http_process_user_agent },  
  24.   
  25.   
  26.     { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer),  
  27.                  ngx_http_process_header_line },  
  28.   
  29.     { ngx_string("Content-Length"),  
  30.                  offsetof(ngx_http_headers_in_t, content_length),  
  31.                  ngx_http_process_unique_header_line },  
  32.   
  33.     { ngx_string("Content-Type"),  
  34.                  offsetof(ngx_http_headers_in_t, content_type),  
  35.                  ngx_http_process_header_line },  
  36.   
  37.     { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range),  
  38.                  ngx_http_process_header_line },  
  39.   
  40.     { ngx_string("If-Range"),  
  41.                  offsetof(ngx_http_headers_in_t, if_range),  
  42.                  ngx_http_process_unique_header_line },  
  43.   
  44.     { ngx_string("Transfer-Encoding"),  
  45.                  offsetof(ngx_http_headers_in_t, transfer_encoding),  
  46.                  ngx_http_process_header_line },  
  47.   
  48.     { ngx_string("Expect"),  
  49.                  offsetof(ngx_http_headers_in_t, expect),  
  50.                  ngx_http_process_unique_header_line },  
  51.   
  52. #if (NGX_HTTP_GZIP)  
  53.     { ngx_string("Accept-Encoding"),  
  54.                  offsetof(ngx_http_headers_in_t, accept_encoding),  
  55.                  ngx_http_process_header_line },  
  56.   
  57.     { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via),  
  58.                  ngx_http_process_header_line },  
  59. #endif  
  60.   
  61.     { ngx_string("Authorization"),  
  62.                  offsetof(ngx_http_headers_in_t, authorization),  
  63.                  ngx_http_process_unique_header_line },  
  64.   
  65.     { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive),  
  66.                  ngx_http_process_header_line },  
  67.   
  68.   
  69. #if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)  
  70.     { ngx_string("X-Forwarded-For"),  
  71.                  offsetof(ngx_http_headers_in_t, x_forwarded_for),  
  72.                  ngx_http_process_header_line },  
  73. #endif  
  74.   
  75. #if (NGX_HTTP_REALIP)  
  76.     { ngx_string("X-Real-IP"),  
  77.                  offsetof(ngx_http_headers_in_t, x_real_ip),  
  78.                  ngx_http_process_header_line },  
  79. #endif  
  80.   
  81. #if (NGX_HTTP_HEADERS)  
  82.     { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept),  
  83.                  ngx_http_process_header_line },  
  84.   
  85.     { ngx_string("Accept-Language"),  
  86.                  offsetof(ngx_http_headers_in_t, accept_language),  
  87.                  ngx_http_process_header_line },  
  88. #endif  
  89.   
  90. #if (NGX_HTTP_DAV)  
  91.     { ngx_string("Depth"), offsetof(ngx_http_headers_in_t, depth),  
  92.                  ngx_http_process_header_line },  
  93.   
  94.     { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination),  
  95.                  ngx_http_process_header_line },  
  96.   
  97.     { ngx_string("Overwrite"), offsetof(ngx_http_headers_in_t, overwrite),  
  98.                  ngx_http_process_header_line },  
  99.   
  100.     { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date),  
  101.                  ngx_http_process_header_line },  
  102. #endif  
  103.   
  104.     { ngx_string("Cookie"), 0, ngx_http_process_cookie },  
  105.   
  106.     { ngx_null_string, 0, NULL }  
  107. };</span>  

ngx_http_headers_in數組當前包含了25個常用的請求頭,每個請求頭都設置了一個處理函數,當前其中一部分請求頭設置的是公共的處理函數,這里有2個公共的處理函數,ngx_http_process_header_line和ngx_http_process_unique_header_line。

先來看一下處理函數的函數指針定義:
typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r,
    ngx_table_elt_t *h, ngx_uint_t offset);
它有3個參數,r為對應的請求結構,h為該請求頭在headers_in.headers鏈表節點的指針,offset為該請求頭的引用在ngx_http_headers_in_t結構中的偏移。
再來看ngx_http_process_header_line函數:

 

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">static ngx_int_t  
  2. ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,  
  3.     ngx_uint_t offset)  
  4. {  
  5.     ngx_table_elt_t  **ph;  
  6.   
  7.     ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset);  
  8.   
  9.     if (*ph == NULL) {  
  10.         *ph = h;  
  11.     }  
  12.   
  13.     return NGX_OK;  
  14. }</span>  

這個函數只是簡單將該請求頭在ngx_http_headers_in_t結構中保存一份引用。ngx_http_process_unique_header_line功能類似,不同點在於該函數會檢查這個請求頭是否是重復的,如果是的話,則給該請求返回400錯誤。

ngx_http_headers_in數組中剩下的請求頭都有自己特殊的處理函數,這些特殊的函數根據對應的請求頭有一些特殊的處理,下面我們拿Host頭的處理函數ngx_http_process_host做一下介紹:

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">static ngx_int_t  
  2. ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,  
  3.     ngx_uint_t offset)  
  4. {  
  5.     u_char   *host;  
  6.     ssize_t   len;  
  7.   
  8.     if (r->headers_in.host == NULL) {  
  9.         r->headers_in.host = h;  
  10.     }  
  11.   
  12.     host = h->value.data;  
  13.     len = ngx_http_validate_host(r, &host, h->value.len, 0);  
  14.   
  15.     if (len == 0) {  
  16.         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,  
  17.                       "client sent invalid host header");  
  18.         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);  
  19.         return NGX_ERROR;  
  20.     }  
  21.   
  22.     if (len < 0) {  
  23.         ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);  
  24.         return NGX_ERROR;  
  25.     }  
  26.   
  27.     if (r->headers_in.server.len) {  
  28.         return NGX_OK;  
  29.     }  
  30.   
  31.     r->headers_in.server.len = len;  
  32.     r->headers_in.server.data = host;  
  33.   
  34.     return NGX_OK;  
  35. }</span>  

此函數的目的也是保存Host頭的快速引用,它會對Host頭的值做一些合法性檢查,並從中解析出域名,保存在headers_in.server字段,實際上前面在解析請求行時,headers_in.server可能已經被賦值為從請求行中解析出來的域名,根據http協議的規范,如果請求行中的uri帶有域名的話,則域名以它為准,所以這里需檢查一下headers_in.server是否為空,如果不為空則不需要再賦值。

其他請求頭的特殊處理函數,不再做介紹,大致都是根據該請求頭在http協議中規定的意義及其值設置請求的一些屬性,必備后續使用。

對一個合法的請求頭的處理大致為如上所述;

2,返回NGX_AGAIN,表示當前接收到的數據不夠,一行請求頭還未結束,需要繼續下一輪循環。在下一輪循環中,nginx首先檢查請求頭緩沖區header_in是否已滿,如夠滿了,則調用ngx_http_alloc_large_header_buffer()函數分配更多緩沖區,下面分析一下ngx_http_alloc_large_header_buffer函數:

[cpp]  view plain copy
 
  1. <span style="font-size:18px;">static ngx_int_t  
  2. ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,  
  3.     ngx_uint_t request_line)  
  4. {  
  5.     u_char                    *old, *new;  
  6.     ngx_buf_t                 *b;  
  7.     ngx_http_connection_t     *hc;  
  8.     ngx_http_core_srv_conf_t  *cscf;  
  9.   
  10.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,  
  11.                    "http alloc large header buffer");  
  12.   
  13.     /* 
  14.      * 在解析請求行階段,如果客戶端在發送請求行之前發送了大量回車換行符將 
  15.      * 緩沖區塞滿了,針對這種情況,nginx只是簡單的重置緩沖區,丟棄這些垃圾 
  16.      * 數據,不需要分配更大的內存。 
  17.      */  
  18.     if (request_line && r->state == 0) {  
  19.   
  20.         /* the client fills up the buffer with "\r\n" */  
  21.   
  22.         r->request_length += r->header_in->end - r->header_in->start;  
  23.   
  24.         r->header_in->pos = r->header_in->start;  
  25.         r->header_in->last = r->header_in->start;  
  26.   
  27.         return NGX_OK;  
  28.     }  
  29.   
  30.     /* 保存請求行或者請求頭在舊緩沖區中的起始地址 */  
  31.     old = request_line ? r->request_start : r->header_name_start;  
  32.   
  33.     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);  
  34.   
  35.     /* 如果一個大緩沖區還裝不下請求行或者一個請求頭,則返回錯誤 */  
  36.     if (r->state != 0  
  37.         && (size_t) (r->header_in->pos - old)  
  38.                                      >= cscf->large_client_header_buffers.size)  
  39.     {  
  40.         return NGX_DECLINED;  
  41.     }  
  42.   
  43.     hc = r->http_connection;  
  44.   
  45.     /* 首先在ngx_http_connection_t結構中查找是否有空閑緩沖區,有的話,直接取之 */  
  46.     if (hc->nfree) {  
  47.         b = hc->free[--hc->nfree];  
  48.   
  49.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,  
  50.                        "http large header free: %p %uz",  
  51.                        b->pos, b->end - b->last);  
  52.   
  53.     /* 檢查給該請求分配的請求頭緩沖區個數是否已經超過限制,默認最大個數為4個 */  
  54.     } else if (hc->nbusy < cscf->large_client_header_buffers.num) {  
  55.   
  56.         if (hc->busy == NULL) {  
  57.             hc->busy = ngx_palloc(r->connection->pool,  
  58.                   cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));  
  59.             if (hc->busy == NULL) {  
  60.                 return NGX_ERROR;  
  61.             }  
  62.         }  
  63.   
  64.         /* 如果還沒有達到最大分配數量,則分配一個新的大緩沖區 */  
  65.         b = ngx_create_temp_buf(r->connection->pool,  
  66.                                 cscf->large_client_header_buffers.size);  
  67.         if (b == NULL) {  
  68.             return NGX_ERROR;  
  69.         }  
  70.   
  71.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,  
  72.                        "http large header alloc: %p %uz",  
  73.                        b->pos, b->end - b->last);  
  74.   
  75.     } else {  
  76.         /* 如果已經達到最大的分配限制,則返回錯誤 */  
  77.         return NGX_DECLINED;  
  78.     }  
  79.   
  80.     /* 將從空閑隊列取得的或者新分配的緩沖區加入已使用隊列 */  
  81.     hc->busy[hc->nbusy++] = b;  
  82.   
  83.     /* 
  84.      * 因為nginx中,所有的請求頭的保存形式都是指針(起始和結束地址), 
  85.      * 所以一行完整的請求頭必須放在連續的內存塊中。如果舊的緩沖區不能 
  86.      * 再放下整行請求頭,則分配新緩沖區,並從舊緩沖區拷貝已經讀取的部分請求頭, 
  87.      * 拷貝完之后,需要修改所有相關指針指向到新緩沖區。 
  88.      * status為0表示解析完一行請求頭之后,緩沖區正好被用完,這種情況不需要拷貝 
  89.      */  
  90.     if (r->state == 0) {  
  91.         /* 
  92.          * r->state == 0 means that a header line was parsed successfully 
  93.          * and we do not need to copy incomplete header line and 
  94.          * to relocate the parser header pointers 
  95.          */  
  96.   
  97.         r->request_length += r->header_in->end - r->header_in->start;  
  98.   
  99.         r->header_in = b;  
  100.   
  101.         return NGX_OK;  
  102.     }  
  103.   
  104.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,  
  105.                    "http large header copy: %d", r->header_in->pos - old);  
  106.   
  107.     r->request_length += old - r->header_in->start;  
  108.   
  109.     new = b->start;  
  110.   
  111.     /* 拷貝舊緩沖區中不完整的請求頭 */  
  112.     ngx_memcpy(new, old, r->header_in->pos - old);  
  113.   
  114.     b->pos = new + (r->header_in->pos - old);  
  115.     b->last = new + (r->header_in->pos - old);  
  116.   
  117.     /* 修改相應的指針指向新緩沖區 */  
  118.     if (request_line) {  
  119.         r->request_start = new;  
  120.   
  121.         if (r->request_end) {  
  122.             r->request_end = new + (r->request_end - old);  
  123.         }  
  124.   
  125.         r->method_end = new + (r->method_end - old);  
  126.   
  127.         r->uri_start = new + (r->uri_start - old);  
  128.         r->uri_end = new + (r->uri_end - old);  
  129.   
  130.         if (r->schema_start) {  
  131.             r->schema_start = new + (r->schema_start - old);  
  132.             r->schema_end = new + (r->schema_end - old);  
  133.         }  
  134.   
  135.         if (r->host_start) {  
  136.             r->host_start = new + (r->host_start - old);  
  137.             if (r->host_end) {  
  138.                 r->host_end = new + (r->host_end - old);  
  139.             }  
  140.         }  
  141.   
  142.         if (r->port_start) {  
  143.             r->port_start = new + (r->port_start - old);  
  144.             r->port_end = new + (r->port_end - old);  
  145.         }  
  146.   
  147.         if (r->uri_ext) {  
  148.             r->uri_ext = new + (r->uri_ext - old);  
  149.         }  
  150.   
  151.         if (r->args_start) {  
  152.             r->args_start = new + (r->args_start - old);  
  153.         }  
  154.   
  155.         if (r->http_protocol.data) {  
  156.             r->http_protocol.data = new + (r->http_protocol.data - old);  
  157.         }  
  158.   
  159.     } else {  
  160.         r->header_name_start = new;  
  161.         r->header_name_end = new + (r->header_name_end - old);  
  162.         r->header_start = new + (r->header_start - old);  
  163.         r->header_end = new + (r->header_end - old);  
  164.     }  
  165.   
  166.     r->header_in = b;  
  167.   
  168.     return NGX_OK;  
  169. }</span>  

當ngx_http_alloc_large_header_buffer函數返回NGX_DECLINED)時,表示客戶端發送了過大的一行請求頭,或者是整個請求頭部超過了限制,nginx會返回494錯誤,注意到nginx再返回494錯誤之前將請求的lingering_close標識置為了1,這樣做的目的是在返回響應之丟棄掉客戶端發過來的其他數據;

3,返回NGX_HTTP_PARSE_INVALID_HEADER,表示請求頭解析過程中遇到錯誤,一般為客戶端發送了不符合協議規范的頭部,此時nginx返回400錯誤。

4,返回NGX_HTTP_PARSE_HEADER_DONE,表示所有請求頭已經成功的解析,這時請求的狀態被設置為NGX_HTTP_PROCESS_REQUEST_STATE,意味着結束了請求讀取階段,正式進入了請求處理階段,但是實際上請求可能含有請求體,nginx在請求讀取階段並不會去讀取請求體,這個工作交給了后續的請求處理階段的模塊,這樣做的目的是nginx本身並不知道這些請求體是否有用,如果后續模塊並不需要的話,一方面請求體一般較大,如果全部讀取進內存,則白白耗費大量的內存空間,另一方面即使nginx將請求體寫進磁盤,但是涉及到磁盤io,會耗費比較多時間。所以交由后續模塊來決定讀取還是丟棄請求體是最明智的辦法。

讀取完請求頭之后,nginx調用了ngx_http_process_request_header()函數,這個函數主要做了兩個方面的事情,一是調用ngx_http_find_virtual_server()函數查找虛擬服務器配置;二是對一些請求頭做一些協議的檢查。比如對那些使用http1.1協議但是卻沒有發送Host頭的請求,nginx給這些請求返回400錯誤。還有nginx現在的版本並不支持chunked格式的輸入,如果某些請求申明自己使用了chunked格式的輸入(請求帶有值為chunked的transfer_encoding頭部),nginx給這些請求返回411錯誤。等等。
最后調用ngx_http_process_request()函數處理請求;
至此,nginx接收請求接收流程就介紹完畢。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM