Nginx原始碼閱讀(ngx_http_process_request_line)
阿新 • • 發佈:2018-12-21
ngx_http_process_request_line()
static void ngx_http_process_request_line(ngx_event_t *rev) { ssize_t n; ngx_int_t rc, rv; ngx_str_t host; ngx_connection_t *c; ngx_http_request_t *r; 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; // 設定當前連線的超時標誌位為1 ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); return; } // NGX_AGAIN表示接收緩衝區header_in中沒有未解析的資料 rc = NGX_AGAIN; for ( ;; ) { // 若header_in中沒有未解析的資料 if (rc == NGX_AGAIN) { // 把核心套接字緩衝區的資料複製到header_in中 n = ngx_http_read_request_header(r); // NGX_AGAIN表示若需要繼續接收資料,NGX_ERROR表示客戶端關閉連線或連線錯誤 if (n == NGX_AGAIN || n == NGX_ERROR) { return; } } // 若header_in中有未解析的資料,用狀態機解析資料 rc = ngx_http_parse_request_line(r, r->header_in); // 若請求行被正確解析 if (rc == NGX_OK) { /* the request line has been parsed successfully */ r->request_line.len = r->request_end - r->request_start; r->request_line.data = r->request_start; r->request_length = r->header_in->pos - r->request_start; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); 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 (ngx_http_process_request_uri(r) != NGX_OK) { return; } if (r->host_start && r->host_end) { host.len = r->host_end - r->host_start; host.data = r->host_start; rc = ngx_http_validate_host(&host, r->pool, 0); if (rc == NGX_DECLINED) { 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 (rc == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { return; } r->headers_in.server = host; } if (r->http_version < NGX_HTTP_VERSION_10) { if (r->headers_in.server.len == 0 && ngx_http_set_virtual_server(r, &r->headers_in.server) == NGX_ERROR) { return; } ngx_http_process_request(r); return; } // 初始化連結串列,為接收http請求頭做好準備 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; } c->log->action = "reading client request headers"; // 修改當前連線的讀事件的回撥函式為ngx_http_process_request_headers()並呼叫該函式 rev->handler = ngx_http_process_request_headers; ngx_http_process_request_headers(rev); return; } // 若ngx_http_parse_request_line()返回錯誤 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; } /* NGX_AGAIN: a request line parsing is still incomplete */ // 若ngx_http_parse_request_line()返回NGX_AGAIN,需要判斷是緩衝區大小不夠,還是已讀資料不夠 // 若緩衝區已經用盡 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; } } } }
ngx_http_read_request_header()
static ssize_t ngx_http_read_request_header(ngx_http_request_t *r) { ssize_t n; ngx_event_t *rev; ngx_connection_t *c; ngx_http_core_srv_conf_t *cscf; c = r->connection; // 當前請求對應的連線 rev = c->read; // 當前連線對應的讀事件 n = r->header_in->last - r->header_in->pos; // 若當前請求的接收緩衝區header_in中有未解析的資料,直接返回 if (n > 0) { return n; } // 若當前讀事件已就緒 if (rev->ready) { // 迴圈呼叫recv()將核心套接字緩衝區中的資料複製到header_in中 n = c->recv(c, r->header_in->last, r->header_in->end - r->header_in->last); } else { n = NGX_AGAIN; } if (n == NGX_AGAIN) { if (!rev->timer_set) { cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); // 將讀事件加入到定時器中 ngx_add_timer(rev, cscf->client_header_timeout); } // 將讀事件加入到epoll中 if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } return NGX_AGAIN; } // 若客戶端關閉連線 if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client prematurely closed connection"); } // 若客戶端關閉連線或連線錯誤 if (n == 0 || n == NGX_ERROR) { c->error = 1; c->log->action = "reading client request headers"; ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } r->header_in->last += n; return n; }
ngx_http_process_request_headers()
static void ngx_http_process_request_headers(ngx_event_t *rev) { u_char *p; size_t len; ssize_t n; ngx_int_t rc, rv; ngx_table_elt_t *h; ngx_connection_t *c; ngx_http_header_t *hh; ngx_http_request_t *r; ngx_http_core_srv_conf_t *cscf; ngx_http_core_main_conf_t *cmcf; 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; // 設定當前連線的超時標誌位為1 ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); return; } cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); rc = NGX_AGAIN; for ( ;; ) { if (rc == NGX_AGAIN) { // 若緩衝區已經用盡 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; } 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; } } // 把核心套接字緩衝區的資料複製到header_in中 n = ngx_http_read_request_header(r); // NGX_AGAIN表示若需要繼續接收資料,NGX_ERROR表示客戶端關閉連線或連線錯誤 if (n == NGX_AGAIN || n == NGX_ERROR) { return; } } /* the host header could change the server configuration context */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); // 若header_in中有未解析的資料,用狀態機解析資料 rc = ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers); // 返回NGX_OK,表示解析出了一行請求頭 if (rc == NGX_OK) { r->request_length += r->header_in->pos - r->header_name_start; 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; } /* a header line has been parsed successfully */ h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } 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); } 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; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http header: \"%V: %V\"", &h->key, &h->value); continue; } // 返回NGX_HTTP_PARSE_HEADER_DONE,表示解析出了整個請求頭 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_name_start; // 設定請求狀態為NGX_HTTP_PROCESS_REQUEST_STATE r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; /* ngx_http_process_request_header() { ... ngx_http_set_virtual_server() { ... ngx_http_find_virtual_server() ... } } ngx_http_process_request_header()主要做了兩個方面的事情: 一是呼叫ngx_http_find_virtual_server()查詢虛擬伺服器配置; 二是對一些請求頭做一些協議的檢查 */ rc = ngx_http_process_request_header(r); if (rc != NGX_OK) { return; } // 處理http請求 ngx_http_process_request(r); return; } // 返回NGX_AGAIN,表示需要繼續接收資料 if (rc == NGX_AGAIN) { /* a header line parsing is still not complete */ continue; } /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ // 返回NGX_HTTP_PARSE_INVALID_HEADER,表示請求頭解析過程中遇到錯誤 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent invalid header line"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } }
---------------------
作者:hz5034
來源:CSDN
原文:https://blog.csdn.net/hz5034/article/details/81055155
版權宣告:本文為博主原創文章,轉載請附上博文連結!