nginx服务器请求建立链接的过程
通过对nginx服务器的工作进程进行调试,可以发现在请求html页面时,在调用http模块过程中堆栈记录的信息如下:
(gdb) BT
#0 ngx_http_read_request_header (r=0x1bf3fc0) at src/http/ngx_http_request.c:1374
#1 0x0000000000447bc9 in ngx_http_process_request_line (rev=0x1c0a2f0) at src/http/ngx_http_request.c:940
#2 0x00000000004476c1 in ngx_http_wait_request_handler (rev=0x1c0a2f0) at src/http/ngx_http_request.c:499
#3 0x0000000000436f30 in ngx_epoll_process_events (cycle=0x1be8f50, timer=60000, flags=1)at src/event/modules/ngx_epoll_module.c:822
#4 0x000000000042a3d2 in ngx_process_events_and_timers (cycle=0x1be8f50) at src/event/ngx_event.c:242
#5 0x0000000000434faf in ngx_worker_process_cycle (cycle=0x1be8f50, data=0x0) at src/os/unix/ngx_process_cycle.c:753
#6 0x0000000000431f57 in ngx_spawn_process (cycle=0x1be8f50, proc=0x434ef0 <ngx_worker_process_cycle>, data=0x0, name=0x4b0f10 "worker process", respawn=-3) at src/os/unix/ngx_process.c:198
#7 0x00000000004341e3 in ngx_start_worker_processes (cycle=0x1be8f50, n=1, type=-3) at src/os/unix/ngx_process_cycle.c:358
#8 0x0000000000433966 in ngx_master_process_cycle (cycle=0x1be8f50) at src/os/unix/ngx_process_cycle.c:130
#9 0x0000000000403cb7 in main (argc=1, argv=0x7fff63b94e98) at src/core/nginx.c:359
可以查看出读取到的数据,是浏览器发出的html请求的报头
(gdb) p b->last
$59 = (unsigned char *) 0x1bf3b60 "GET / HTTP/1.1\r\nHost: 192.168.1.103\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nAccept
: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\nUpgrade-Insecure-Requests: 1\r"...
以下是在处理GET请求中的流程
(gdb) bt
#0 ngx_http_parse_request_line (r=0x256afc0, b=0x256a850) at src/http/ngx_http_parse.c:146
#1 0x0000000000447bfa in ngx_http_process_request_line (rev=0x25812f0) at src/http/ngx_http_request.c:947
#2 0x00000000004476c1 in ngx_http_wait_request_handler (rev=0x25812f0) at src/http/ngx_http_request.c:499
#3 0x0000000000436f30 in ngx_epoll_process_events (cycle=0x255ff50, timer=60000, flags=1)at src/event/modules/ngx_epoll_module.c:822
#4 0x000000000042a3d2 in ngx_process_events_and_timers (cycle=0x255ff50) at src/event/ngx_event.c:242
#5 0x0000000000434faf in ngx_worker_process_cycle (cycle=0x255ff50, data=0x0) at src/os/unix/ngx_process_cycle.c:753
#6 0x0000000000431f57 in ngx_spawn_process (cycle=0x255ff50, proc=0x434ef0 <ngx_worker_process_cycle>, data=0x0, name=0x4b0f10 "worker process", respawn=-3) at src/os/unix/ngx_process.c:198
#7 0x00000000004341e3 in ngx_start_worker_processes (cycle=0x255ff50, n=1, type=-3) at src/os/unix/ngx_process_cycle.c:358
#8 0x0000000000433966 in ngx_master_process_cycle (cycle=0x255ff50) at src/os/unix/ngx_process_cycle.c:130
#9 0x0000000000403cb7 in main (argc=1, argv=0x7fff62ed08a8) at src/core/nginx.c:359
对照代码,可以看出是在处理http协议的头部
通过debug以及review该处代码,可以看出,针对 头部协议,该处逻辑采用了状态器模式,在逻辑处理中,根据不同的逻辑,设置不同的ch状态属性,然后根据不同的状态属性,进入大不同的处理逻辑之中。这样的处理模式非常通用,在服务器开发中,应用状态器模式,在不同的心跳进行不同的处理。
ngx_int_t
ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
{u_char c, ch, *p, *m;enum {sw_start = 0,sw_method,sw_spaces_before_uri,sw_schema,sw_schema_slash,sw_schema_slash_slash,sw_host_start,sw_host,sw_host_end,sw_host_ip_literal,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;state = r->state;for (p = b->pos; p < b->last; p++) {ch = *p;switch (state) {/* HTTP methods: GET, HEAD, POST */case sw_start:r->request_start = p;if (ch == CR || ch == LF) {break;}if ((ch < 'A' || ch > 'Z') && ch != '_') {return NGX_HTTP_PARSE_INVALID_METHOD;}state = sw_method;break;case sw_method:if (ch == ' ') {r->method_end = p - 1;m = r->request_start;switch (p - m) {case 3:if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {r->method = NGX_HTTP_GET;break;}if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {r->method = NGX_HTTP_PUT;break;}break;case 4:if (m[1] == 'O') {if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {r->method = NGX_HTTP_POST;break;}if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {r->method = NGX_HTTP_COPY;break;}if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {r->method = NGX_HTTP_MOVE;break;}if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {r->method = NGX_HTTP_LOCK;break;}} else {if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {r->method = NGX_HTTP_HEAD;break;}}break;case 5:if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {r->method = NGX_HTTP_MKCOL;break;}if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {r->method = NGX_HTTP_PATCH;break;}if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {r->method = NGX_HTTP_TRACE;break;}break;case 6:if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {r->method = NGX_HTTP_DELETE;break;}if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {r->method = NGX_HTTP_UNLOCK;break;}break;case 7:if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' ')){r->method = NGX_HTTP_OPTIONS;}break;case 8:if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')){r->method = NGX_HTTP_PROPFIND;}break;case 9:if (ngx_str9cmp(m,'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')){r->method = NGX_HTTP_PROPPATCH;}break;}state = sw_spaces_before_uri;break;}if ((ch < 'A' || ch > 'Z') && ch != '_') {return NGX_HTTP_PARSE_INVALID_METHOD;}break;/* space* before URI */case sw_spaces_before_uri:if (ch == '/') {r->uri_start = p;state = sw_after_slash_in_uri;break;}c = (u_char) (ch | 0x20);if (c >= 'a' && c <= 'z') {r->schema_start = p;state = sw_schema;break;}switch (ch) {case ' ':break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_schema:c = (u_char) (ch | 0x20);if (c >= 'a' && c <= 'z') {break;}switch (ch) {case ':':r->schema_end = p;state = sw_schema_slash;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_schema_slash:switch (ch) {case '/':state = sw_schema_slash_slash;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_schema_slash_slash:switch (ch) {case '/':state = sw_host_start;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_host_start:r->host_start = p;if (ch == '[') {state = sw_host_ip_literal;break;}state = sw_host;/* fall through */case sw_host:c = (u_char) (ch | 0x20);if (c >= 'a' && c <= 'z') {break;}if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {break;}/* fall through */case sw_host_end:r->host_end = p;switch (ch) {case ':':state = sw_port;break;case '/':r->uri_start = p;state = sw_after_slash_in_uri;break;case ' ':/** use single "/" from request line to preserve pointers,* if request line will be copied to large client buffer*/r->uri_start = r->schema_end + 1;r->uri_end = r->schema_end + 2;state = sw_host_http_09;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_host_ip_literal:if (ch >= '0' && ch <= '9') {break;}c = (u_char) (ch | 0x20);if (c >= 'a' && c <= 'z') {break;}switch (ch) {case ':':break;case ']':state = sw_host_end;break;case '-':case '.':case '_':case '~':/* unreserved */break;case '!':case '$':case '&':case '\'':case '(':case ')':case '*':case '+':case ',':case ';':case '=':/* sub-delims */break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_port:if (ch >= '0' && ch <= '9') {break;}switch (ch) {case '/':r->port_end = p;r->uri_start = p;state = sw_after_slash_in_uri;break;case ' ':r->port_end = p;/** use single "/" from request line to preserve pointers,* if request line will be copied to large client buffer*/r->uri_start = r->schema_end + 1;r->uri_end = r->schema_end + 2;state = sw_host_http_09;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;/* space+ after "http://host[:port] " */case sw_host_http_09:switch (ch) {case ' ':break;case CR:r->http_minor = 9;state = sw_almost_done;break;case LF:r->http_minor = 9;goto done;case 'H':r->http_protocol.data = p;state = sw_http_H;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;/* check "/.", "//", "%", and "\" (Win32) in URI */case sw_after_slash_in_uri:if (usual[ch >> 5] & (1 << (ch & 0x1f))) {state = sw_check_uri;break;}switch (ch) {case ' ':r->uri_end = p;state = sw_check_uri_http_09;break;case CR:r->uri_end = p;r->http_minor = 9;state = sw_almost_done;break;case LF:r->uri_end = p;r->http_minor = 9;goto done;case '.':r->complex_uri = 1;state = sw_uri;break;case '%':r->quoted_uri = 1;state = sw_uri;break;case '/':r->complex_uri = 1;state = sw_uri;break;
#if (NGX_WIN32)case '\\':r->complex_uri = 1;state = sw_uri;break;
#endifcase '?':r->args_start = p + 1;state = sw_uri;break;case '#':r->complex_uri = 1;state = sw_uri;break;case '+':r->plus_in_uri = 1;break;case '\0':return NGX_HTTP_PARSE_INVALID_REQUEST;default:state = sw_check_uri;break;}break;/* check "/", "%" and "\" (Win32) in URI */case sw_check_uri:if (usual[ch >> 5] & (1 << (ch & 0x1f))) {break;}switch (ch) {case '/':
#if (NGX_WIN32)if (r->uri_ext == p) {r->complex_uri = 1;state = sw_uri;break;}
#endifr->uri_ext = NULL;state = sw_after_slash_in_uri;break;case '.':r->uri_ext = p + 1;break;case ' ':r->uri_end = p;state = sw_check_uri_http_09;break;case CR:r->uri_end = p;r->http_minor = 9;state = sw_almost_done;break;case LF:r->uri_end = p;r->http_minor = 9;goto done;
#if (NGX_WIN32)case '\\':r->complex_uri = 1;state = sw_after_slash_in_uri;break;
#endifcase '%':r->quoted_uri = 1;state = sw_uri;break;case '?':r->args_start = p + 1;state = sw_uri;break;case '#':r->complex_uri = 1;state = sw_uri;break;case '+':r->plus_in_uri = 1;break;case '\0':return NGX_HTTP_PARSE_INVALID_REQUEST;}break;/* space+ after URI */case sw_check_uri_http_09:switch (ch) {case ' ':break;case CR:r->http_minor = 9;state = sw_almost_done;break;case LF:r->http_minor = 9;goto done;case 'H':r->http_protocol.data = p;state = sw_http_H;break;default:r->space_in_uri = 1;state = sw_check_uri;p--;break;}break;/* URI */case sw_uri:if (usual[ch >> 5] & (1 << (ch & 0x1f))) {break;}switch (ch) {case ' ':r->uri_end = p;state = sw_http_09;break;case CR:r->uri_end = p;r->http_minor = 9;state = sw_almost_done;break;case LF:r->uri_end = p;r->http_minor = 9;goto done;case '#':r->complex_uri = 1;break;case '\0':return NGX_HTTP_PARSE_INVALID_REQUEST;}break;/* space+ after URI */case sw_http_09:switch (ch) {case ' ':break;case CR:r->http_minor = 9;state = sw_almost_done;break;case LF:r->http_minor = 9;goto done;case 'H':r->http_protocol.data = p;state = sw_http_H;break;default:r->space_in_uri = 1;state = sw_uri;p--;break;}break;case sw_http_H:switch (ch) {case 'T':state = sw_http_HT;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_http_HT:switch (ch) {case 'T':state = sw_http_HTT;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_http_HTT:switch (ch) {case 'P':state = sw_http_HTTP;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;case sw_http_HTTP:switch (ch) {case '/':state = sw_first_major_digit;break;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;/* first digit of major HTTP version */case sw_first_major_digit:if (ch < '1' || ch > '9') {return NGX_HTTP_PARSE_INVALID_REQUEST;}r->http_major = ch - '0';state = sw_major_digit;break;/* major HTTP version or dot */case sw_major_digit:if (ch == '.') {state = sw_first_minor_digit;break;}if (ch < '0' || ch > '9') {return NGX_HTTP_PARSE_INVALID_REQUEST;}r->http_major = r->http_major * 10 + ch - '0';break;/* first digit of minor HTTP version */case sw_first_minor_digit:if (ch < '0' || ch > '9') {return NGX_HTTP_PARSE_INVALID_REQUEST;}r->http_minor = ch - '0';state = sw_minor_digit;break;/* minor HTTP version or end of request line */case sw_minor_digit:if (ch == CR) {state = sw_almost_done;break;}if (ch == LF) {goto done;}if (ch == ' ') {state = sw_spaces_after_digit;break;}if (ch < '0' || ch > '9') {return NGX_HTTP_PARSE_INVALID_REQUEST;}r->http_minor = r->http_minor * 10 + ch - '0';break;case sw_spaces_after_digit:switch (ch) {case ' ':break;case CR:state = sw_almost_done;break;case LF:goto done;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}break;/* end of request line */case sw_almost_done:r->request_end = p - 1;switch (ch) {case LF:goto done;default:return NGX_HTTP_PARSE_INVALID_REQUEST;}}}b->pos = p;r->state = state;return NGX_AGAIN;done:b->pos = p + 1;if (r->request_end == NULL) {r->request_end = p;}r->http_version = r->http_major * 1000 + r->http_minor;r->state = sw_start;if (r->http_version == 9 && r->method != NGX_HTTP_GET) {return NGX_HTTP_PARSE_INVALID_09_METHOD;}return NGX_OK;
}