nginx源码分析之http解码实现

分析nginx是如何解析并且存储http请求的。对非法甚至恶意请求的识别能力和处理方式。可以发现nginx采用状态机来解析http协议,有一定容错能力,但并不全面

相关配置

跟解码有关的配置

merge_slashes

语法merge_slashes on | off

默认值on

上下文http server

说明支持解析请求行时,合并相邻的斜线。例如,,一个请求 将生成如下$uri 值: on: /foo/bar/ off: /foo//bar/要知道,静态location匹配是一个字符串比较,所以如果merge_slashes关闭, 一个类似/foo//bar/的请求将不会匹配location /foo/bar/.在HttpCoreModule中

underscores_in_headers

语法underscores_in_headers on | off

默认值Off

上下文http server

说明允许或者不允许headers中的下划线

ignore_invalid_headers

语法ignore_invalid_headers on | off

默认值On

上下文http server

说明控制是否有无效name的header应该被忽略。 有效的名字是由数字 字母 连字符- 可能有下划线组成, 前后都不能有空格。如果该指令在sever级别被指定,它的值仅当server是默认的那个才使用。 指定的值被应用到所有监听同样的地址和端口的虚拟主机上。

请求体有关配置

client_body_buffer_size

语法client_body_buffer_size size

默认值8k|16k

上下文http server locatioin

说明指定client request body buffer大小如果request body大小超过buffer大小,那么整个请求体会写入临时文件。默认大小是page 大小2倍。 根据不同平台,可能为8K或者16K。当content-length请求头指定了比buffer size较小的值,那么nginx会使用较小的那个。结果就是,nginx将不会给每个请求分配一个这个size大小的buffer

client_body_in_single_buffer

语法client_body_in_single_buffer on | off

默认值Off

上下文http server location

说明该指令制定是否保持这整个body在一个client request buffer中。 当使用变量$request_body来减少copy操作时,这个指令是推荐的。注意到,当请求体不能保存在一个buffer中时(看client_body_buffer_size),这个body将存到磁盘上。

client_body_in_file_only

语法client_body_in_file_only on | clean | off

默认值off

上下文http server location

说明这个指令强制nginx总是将请求体存入临时磁盘文件,甚至即使这个请求体size为0请注意,如果指令是on,文件在请求完成后也不会移除该指令可以用于debug,和嵌入的perl模块中$r->request_body_file 方法

数据结构

解码的所有结果都保存在request结构里

ngx_http_request_t {ngx_but_t *header_in; // buf,保存请求Ngx_http_headers_in_t headers_in; //链表,保存请求中的请求头Ngx_http_headers_out_t headers_out; //链表,保存response中的响应头。。。}

保存请求头的结构

//Ngx_http_headers_in_t 结构

typedef struct {ngx_list_theaders;ngx_table_elt_t*host;ngx_table_elt_t*connection;。。。ngx_str_tuser;ngx_str_tpasswd;。。。ngx_array_tcookies;ngx_str_tserver;off_tcontent_length_n;time_tkeep_alive_n;unsignedconnection_type:2;unsignedchunked:1;unsignedmsie:1;unsignedmsie6:1;unsignedopera:1;unsignedgecko:1;unsignedchrome:1;unsignedsafari:1;unsignedkonqueror:1;} ngx_http_headers_in_t;解码流程

ngx_http_process_request_line(ngx_event_t *rev) //请求行 解码总入口ngx_http_process_request_headers(ngx_event_t *rev) //请求头解码入口所有请求头的handler在ngx_http_request.c:ngx_http_headers_in中 例如:Host头的handler是 ngx_http_process_hostngx_http_process_host功能是,验证host有效性,查找virtual server,找到对应的server配置。请求初始化ngx_http_request_t *ngx_http_create_request(ngx_connection_t *c)r->header_in = hc->nbusy ? hc->busy[0] : c->buffer;r->http_state = NGX_HTTP_READING_REQUEST_STATE;解码请求行ngx_http_process_request_line(ngx_event_t *rev){  ngx_http_read_request_header(r); //从连接中读取内容,放到header_in buf中,返回读取字节数,或错误码      ngx_http_parse_request_line(r, r->header_in);  // 状态机解析请求行,将method schema host port uri protocol version 分离出来  }  解析状态机图如下:  

CR=’\r’LF=’\n’

请求行 对应的正则

请求行对应的正则

Method([A-Z_]+)

Schema([a-zA-Z]+)

Host (\[[a-zA-Z0-9:._~!$&\\(\)*+,;=-]*\]|[a-zA-Z0-9.-]*)

Port[0-9]*)?

Uri.%/?#+ 不能是’\0’ /(([^CRLF.%/?#+\0 ]+/)*(([^CRLF.%/?#+\0 ]+[%?#]|.%/?#)[^ CRLFH\0]*)?)?(?=CR|LF| +H)

Protocol versionHTTP/[1-9]+\.[0-9]+(?=( *)CR?LF)

ngx_http_process_request_uri //解析uri的函数,对自特殊字符进行了一些处理

定义:

Complex_uri: uri with “/.#” Quoted_uri: uri with “%”Plus_in_uri: uri with “+”Space_in_uri: uri with “ ”

Uri_ext: 最后一截uri, 非紧邻/的.后面的部分

发光并非太阳的专利,你也可以发光

nginx源码分析之http解码实现

相关文章:

你感兴趣的文章:

标签云: