分析nginx是如何解析并且存储http请求的。对非法甚至恶意请求的识别能力和处理方式。可以发现nginx采用状态机来解析http协议,有一定容错能力,但并不全面
相关配置
跟解码有关的配置
merge_slashes | |
语法 | merge_slashes on | off |
默认值 | on |
上下文 | http server |
说明 | 支持解析请求行时,合并相邻的斜线。例如,一个请求 http://www.example.com/foo//bar/ 将生成如下$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_t headers;
- ngx_table_elt_t *host;
- ngx_table_elt_t *connection;
- 。。。
- ngx_str_t user;
- ngx_str_t passwd;
- 。。。
- ngx_array_t cookies;
- ngx_str_t server;
- off_t content_length_n;
- time_t keep_alive_n;
- unsigned connection_type:2;
- unsigned chunked:1;
- unsigned msie:1;
- unsigned msie6:1;
- unsigned opera:1;
- unsigned gecko:1;
- unsigned chrome:1;
- unsigned safari:1;
- unsigned konqueror: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_host
ngx_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 version | HTTP/[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, 非紧邻/的.后面的部分
逻辑
- if (r->uri_ext) {
- if (r->args_start) {
- r->exten.len = r->args_start - 1 - r->uri_ext;
- } else {
- r->exten.len = r->uri_end - r->uri_ext;
- }
- r->exten.data = r->uri_ext;
- }
如果含有/.#%, 那么会给uri重新分配内存,并解析uri
- if (r->complex_uri || r->quoted_uri) {
- r->uri.data = ngx_pnalloc(r->pool, r->uri.len + 1);
- ngx_http_parse_complex_uri(r, cscf->merge_slashes)
- }
uri解析的状态机图
请求行URI特殊字符处理
Nginx不支持第3部分, 不支持@
这里指的是6 7 8部分
% | %后面必须是两个十六进制数字,否则报错 NGX_HTTP_PARSE_INVALID_REQUEST |
/ | 相邻重复的斜线,可以合并,有相关配置控制 (merge_slashes on/off控制) |
/../ | 会进入上一级目录.例如 /foo/bar/../abc 会变成 /foo/abc/../前面必须有一级,否则会报错, 不会退到第一级/前面 |
. | Uri中的点,在最后一个/后面,而且不紧跟在/后面, 会是r->uri_ext的起始位置, 结束位置在args前面,或者uri结尾 |
# | 表示uri的结尾,#后面的全部忽略。 如果没有#, 那么uri的结尾会以 ( *(CR?LF)| H)结束 |
? | 问号到#号之间认为都是参数,如果?后没有#,那么问号后都是参数 |
+ | 如果遇到+ r->plus_in_uri=1 |
\r | 后面必须接\n, 表示请求行结束 |
\n | 表示请求行结束 |
HTTP0.9的支持
支持http 0.9
如果是协议版本小于1, 那么不会读取请求头
支持的方法
方法
GET
PUT
POST
COPY
MOVE
LOCK
HEAD
MKCOL
PATCH
TRACE NGX_HTTP_NOT_ALLOWED error code 405
DELETE
UNLOCK
OPTIONS
PROPFIND
PROPPATCH
注意:这里说的支持,是说nginx解码时,能够识别这些方法。但是在后续的处理过程中不一定支持。例如,nginx遇到TRACE方法,会返回405 not allowed
未知的方法: 如果METHOD字符集符合 [A-B_]+, 会将请求放过去,交给后续处理
如果不符合[A-B_]+, 会报错误 400 bad request
解码请求头
ngx_http_process_request_headers(ngx_event_t *rev)
ngx_http_read_request_header // 从网络连接中读取内容
ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers);
请求头 对应的正则
Name [0-9a-zA-Z-]? 最大长度32, 非法字符被忽略,超过32个的从头覆盖
_是否非法,看allow_underscores配置
value [^ CRLF\0]+ 没有长度限制,以CRLF结尾
请求头解析的状态机图
非法头部处理
Header name中包含非法字符,则认为是非法头部,nginx默认抛弃这一行,另外也可由配置ignore_invalid_headers 确定
相同头部处理
策略一,第二个以上相同头部忽略 ngx_http_process_header_line
策略二,如果重复,返回400错误 ngx_http_process_unique_header_line
策略三,允许多头存在,用数组保存 ngx_http_process_multi_header_lines eg. X-Forwarded-For Cookie
策略四, 使用最靠后的头
请求头部 | 策略 | 头部类型和值 |
Connection | 策略四 | General如果http版本大于1,那么默认为keep-alive, 否则为close 。 只能有close 或keep-alive两种情况,否则报错 |
Host | 策略一 | Request headerhttp 1.0以上版本,host不能为空,否则报错 |
User-Agent | 策略一 | Request headerNginx会去识别是否如下六种(Msie msie6) opera gecko chrome Safari Konqueror |
Referer | 策略一 | Request header |
Content-Type | 策略一 | Entity header指明发给接受者的实体主体的媒体类型,或HEAD方法中指明若请求为GET时将发送的媒体类型 |
Range | 策略一 | Request header |
Transfer-Encoding | 策略一 | general |
Upgrade | 策略一 | general |
Accept-Encoding | 策略一 | Request header |
X-Real-IP | 策略一 | |
Accept | 策略一 | Request header |
Accept-Language | 策略一 | Request header |
Depth | 策略一 | |
Destination | 策略一 | |
Overwrite | 策略一 | |
Date | 策略一 | general |
Via | general | |
Keep-Alive | 策略一 | |
If-Modified-Since | 策略二 | Request header |
If-Unmodified-Since | 策略二 | Request header |
If-Match | 策略二 | Request header |
If-None-Match | 策略二 | Request header |
If-Range | 策略二 | Request header |
Expect | 策略二 | Request header |
Content-Length | 策略二 | Entity header 必须为数字,必须为正数ngx_http_process_request_header |
Authorization | 策略二 | Request header |
X-Forwarded-For | 策略三 | |
Cookie | 策略三 | |
额外的头 | 头部都会存在list里,怎么处理自己定义 |
冲突或关联头部处理
transfer_encoding content-length
在ngx_http_process_request_header中,当transfer-encoding value 为chunked content-length会失效。Transfer-encoding值只能为identity或chunked,否则报错
Connection keep-alive
如果connection 为keep-alive,那么keep-alive的值会生效
如果请求头connection没有指明为close, 且http版本大于1, 那么connection默认为keep-alive.
不支持多行请求头
由于 HTTP/1.1 协议里的规定,所以实际上 HTTP 协议支持多行请求头,它规定任何一个以空格开头的行,都是接续在前一行之后的内容。例如:
X-Random-Comment: 这是个长句子,
所以我们得换行处理一下,看着更整齐。
Nginx不支持多行请求头
Cookies处理
Nginx没有继续解析cookies值
https://github.com/cloudflare/lua-resty-cookie
解码请求体
nginx核心本身不会主动读取请求体,这个工作是交给请求处理阶段的模块来做,但是nginx核心提供了ngx_http_read_client_request_body()接口来读取请求体,另外还提供了一个丢弃请求体的接口-ngx_http_discard_request_body(),在请求执行的各个阶段中,任何一个阶段的模块如果对请求体感兴趣或者希望丢掉客户端发过来的请求体,可以分别调用这两个接口来完成。这两个接口是nginx核心提供的处理请求体的标准接口,如果希望配置文件中一些请求体相关的指令(比如client_body_in_file_only,client_body_buffer_size等)能够预期工作,以及能够正常使用nginx内置的一些和请求体相关的变量(比如$request_body和$request_body_file),一般来说所有模块都必须调用这些接口来完成相应操作,如果需要自定义接口来处理请求体,也应尽量兼容nginx默认的行为。
请求体的读取一般发生在nginx的content handler中,一些nginx内置的模块,比如proxy模块,fastcgi模块,uwsgi模块等,这些模块的行为必须将客户端过来的请求体(如果有的话)以相应协议完整的转发到后端服务进程,所有的这些模块都是调用了ngx_http_read_client_request_body()接口来完成请求体读取。值得注意的是这些模块会把客户端的请求体完整的读取后才开始往后端转发数据。
ngx_http_discard_request_body
使用接口
可用变量
以下仅为举例,不全
$http_xxxx 类型的变量, xxxx为header name 连接符变成下划线,大写字母变成小写字母
X-Real-IP 变量为 $http_x_real_ip
类似的有
$args_XXXX
$cookie_XXXX
$uri
$request_body
这个变量包含请求体。这个变量出现在proxy或fastcgi_pass所在的location
$request_body_file
Client请求体临时文件
转自:http://blog.csdn.net/liujiyong7/article/details/44833475
相关推荐
源码分析对于理解Nginx-RTMP-Module的工作原理和定制化需求至关重要。主要涉及以下几个部分: 1. **ngx_rtmp_core_module.c/h**:核心模块,负责基本的连接管理和事件处理。 2. **ngx_rtmp_handler.c/h**:处理...
【标题】:“毕业设计源码泽枫影视设计与实现.zip”这一标题暗示了这是一个与影视设计和实现相关的毕业设计项目,包含源代码。这可能是某位学生或团队为完成其计算机科学或相关专业的毕业设计而创建的一个软件系统,...
电视直播源码是用于构建电视直播应用的核心代码,它涵盖了从获取直播流、解码、传输到用户设备显示等一系列过程的技术实现。在开发电视直播应用时,这些源码扮演着至关重要的角色,因为它们直接决定了应用程序的性能...
Java的BBC系统源码分析 在Java编程领域,BBC(Broadcasting Corporation)系统源码提供了一个深入了解大型分布式系统设计和实现的机会。这个源码库可能包含了处理广播内容、用户交互、流媒体服务等多个核心模块,...
3. **流媒体服务器源码分析** - 源码中的关键模块包括:网络通信模块、媒体处理模块、会话管理模块、负载均衡模块等。 - 网络通信模块处理客户端连接、数据传输和错误恢复。 - 媒体处理模块涉及媒体文件的读取、...
直播盒子源码是一种用于构建直播应用的技术基础,它包含了实现直播功能所需的所有关键组件和逻辑。这个源码带有详细教程,对于那些想要深入理解和开发直播应用的IT从业者来说,是一份非常宝贵的资源。 首先,我们要...
此外,还可以借助开源项目如Nginx或FFmpeg,通过C#的interop技术与之交互,实现流媒体服务功能。 2. **编码器组件**:编码器是将原始媒体文件转换为适合在网络上传输的格式的关键工具。在C#中,可以使用Media ...
#### 五、Netty源码分析实战案例 1. **ChannelHandlerContext与ChannelHandlerAdaptor详解**: - 分析`ChannelHandlerContext`的生命周期及其与`ChannelHandler`之间的交互方式。 - 深入理解`...
在网页上实现大华视频监控摄像头在线是一项技术性较强的工作,涉及到网络通信、视频编码、浏览器插件以及前端开发等多个方面。以下将详细介绍这个过程的关键知识点: 1. **摄像头在线原理**: 大华视频监控摄像头...
4. 源码分析:可能涉及视频处理相关的源码解析,帮助开发者深入理解内部机制。 5. 实战技巧:可能分享了博主在实际项目中遇到的问题及解决方案,为读者提供实战经验。 通过阅读这个压缩包中的"nginx.txt"文件,读者...
它包含了用户界面的布局、网络请求的处理、视频流的编码与解码、实时互动功能的实现等模块。通过阅读源码,开发者可以深入理解如何实现视频预览、推流、拉流、美颜效果、礼物系统、弹幕互动等功能,并为自己的项目...
2. **后端服务**:后端源码主要处理用户请求、验证身份、管理直播间、存储用户数据等,使用如Node.js的Express或Java的Spring Boot等框架实现。 3. **数据库设计**:数据库脚本和配置用于存储用户信息、直播记录、...
ZXing是一个开放源码的、用Java实现的多种格式的1D/2D条码图像处理库,包含了联系到其他语言的端口。ZXing可以实现使用手机的内置摄像头完成条形码的扫描及解码。 2.4 Nginx Nginx是一个异步框架的网页服务器,也...
在本文档中,我们将深入探讨媒体处理的基本概念、常见编码格式、开源库和工具的应用,以及如何通过源码分析提升媒体处理效率。 一、媒体处理基础知识 媒体处理涉及音频、视频和图像等多媒体内容的编码、解码、编辑...
在`qieangel2013-livego-84a5949`这个压缩包中,可能包含了一个名为`livego`的项目源码,该项目可能是作者实现的一个Go语言直播服务框架。代码中可能包含了服务器端接收RTMP流、处理推流、转码、存储、分发等功能的...
在本资源中,我们主要探讨的是使用VC++实现网络视频直播的实例程序源码。VC++,即Visual C++,是Microsoft开发的一款强大的C++集成开发环境,它提供了丰富的库支持,包括MFC(Microsoft Foundation Classes)和...
通过深入分析大湿手机直播系统源码,开发者不仅可以了解PHP在实时系统中的应用,还能学习到如何处理高并发、实时通信、数据库优化等问题,为构建自己的直播系统提供宝贵的实践经验。在实践中不断学习和提升,才能更...
在分析XtreMedia源码时,我们可以深入理解其工作原理和实现机制。 1. **流媒体技术** - XtreMedia使用HTTP Live Streaming (HLS) 和 Progressive Download 技术来提供音频和视频流服务。HLS是一种基于HTTP的协议,...
4. **数据分析**:收集用户行为数据,进行分析,以指导产品迭代和营销策略。 通过深入理解这些知识点,开发者可以构建出一个高效、稳定且用户体验优良的直播网站。同时,不断跟进直播技术的发展,如低延迟直播、VR/...
该视频聊天室源码是一个完整的解决方案,包含了服务端、客户端以及网站程序的组成部分,用于构建一个实时的在线视频交流平台。下面将详细讲解这个源码中的关键知识点。 1. **服务端开发**: - **网络协议**:...