Posted on 2014-03-08 12:55:57 http
http-parser是一个用C代码编写的HTTP消息解析器。可以解析HTTP请求或者回应消息。 这个解析器常常在高性能的HTTP应用中使用。 在解析的过程中,它不会调用任何系统调用,不会在HEAP上申请内存,不会缓存数据,并且可以在任意时刻打断解析过程,而不会产生任何影响。 对于每个HTTP消息(在WEB服务器中就是每个请求),它只需要40字节的内存占用(解析器本身的基本数据结构),不过最终的要看你实际的代码架构。
特性:
解析器可以处理以下类型的HTTP消息:
每个HTTP请求使用一个http_parser
对象。使用http_parser_init
来初始化结构体,并且设置解析时的回调。下面的代码可能看起来像是解析HTTP请求:
// 设置回调
http_parser_settings settings;
settings.on_url = my_url_callback;
settings.on_header_field = my_header_field_callback;
/* ... */
// 为结构体申请内存
http_parser *parser = malloc(sizeof(http_parser));
// 初始化解析器
http_parser_init(parser, HTTP_REQUEST);
// 设置保存调用者的数据,用于在callback内使用
parser->data = my_socket;
当接收到数据后,解析器开始执行,并检查错误:
size_t len = 80*1024; // 需要接受的数据大小80K
size_t nparsed; // 已经解析完成的数据大小
char buf[len]; // 接收缓存
ssize_t recved; // 实际接收到的数据大小
// 接受数据
recved = recv(fd, buf, len, 0);
// 如果接收到的字节数小于0,说明从socket读取出错
if (recved < 0) {
/* Handle error. */
}
/* Start up / continue the parser.
* Note we pass recved==0 to signal that EOF has been recieved.
*/
// 开始解析
// @parser 解析器对象
// @&settings 解析时的回调函数
// @buf 要解析的数据
// @receved 要解析的数据大小
nparsed = http_parser_execute(parser, &settings, buf, recved);
// 如果解析到websocket请求
if (parser->upgrade) {
/* handle new protocol */
// 如果解析出错,即解析完成的数据大小不等于传递给http_parser_execute的大小
} else if (nparsed != recved) {
/* Handle error. Usually just close the connection. */
}
HTTP需要知道数据流在那里结束。
举个例子,一些服务器发送响应数据的时候,HTTP头部不带有Content-Length
字段,希望客户端持续从socket中读取数据,知道遇到EOF
为止。
在调用http_parser_execute
时,传递最后一个参数为0,用来通知http_parser,解析已经结束。
在http_parser遇到EOF并处理的过程中,仍然可能会遇到错误,所以应该在callback中处理这些错误。
注意:
上面的意思是说,如果需要多次调用http_parser_execute
的时候,就是因为无法一次完成对HTTP服务器/客户端数据的接收。
所以需要在每次接收到一些数据之后,调用一次http_parser_execute
,当从socket接收到EOF
时,应该结束解析,同时通知http_parser解析结束。
一些可扩展的信息字段,例如status_code
、method
和HTTP版本号
,它们都存储在解析器的数据结构中。
这些数据被临时的存储在http_parser
中,并且会在每个连接到来后被重置(当多个连接的HTTP数据使用同一个解析器时);
如果需要保留这些数据,必须要在on_headers_complete
返回之前保存它門。
注意:
应该为每个HTTP连接的数据,单独初始化一个解析器的时候,不会存在上述问题.
解析器会解析HTTP请求和相应中的transfer-encoding
字段。
就是说,chunked
编码会在调用on_body
之前被解析。
HTTP支持将连接升级为不同的协议. 例如目前日益普遍的WebSocket协议的请求数据:
GET /demo HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
WebSocket-Protocol: sample
在WebSocket请求头部传输完毕后,就下来传输的数据是非HTTP协议的数据了。
关于WebSocket协议的详细内容见: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
要支持这种类似与WebSocket的协议,解析器会把它当作一个不带HTTP主体数据的包(只含有头部).然后调用on_headers_complete
和on_message_complete
回调。所以不论怎样,当检测到HTTP头部的数据结束时,http_parser_execute
会停止解析,并且返回。
建议用户在http_parser_execute
函数返回后,检查parset->upgrade
字段,是否被设置为1
.在http_parset_execute
的返回值中,非HTTP类型的数据(除去HTTP头部的数据)的范围,会被设置为从一个offset
参数处开始。
当调用http_parser_execute
时,在http_parset_settings
中设置的回调会执行。
解析器维护了自身状态数据,并且这些数据不会被保存,所以没有必要将这些状态数据缓存。
如果你真需要保存这些状态数据,可以在回调中保存。
有两种类型的回调:
通知 typedef int (*http_cb) (http_parser *);
包括:on_message_begin
, on_headers_complete
, on_message_complete
数据 typedef int (*http_data_cb) (http_parser *, const char at, size_t length);
包括;(只限与请求) on_uri
, (通用) on_header_field
, on_header_value
, on_body
用户的回调函数应该返回0
表示成功。返回非0
的值,会告诉解析器发生了错误,解析器会立刻退出。
如果你解析chunks编码的HTTP消息(例如:从socket中读read()HTTP请求行,解析,然后再次读到一半的头部消息后,再次解析,等等),你的数据类型的回调就会被调用不止一次。 HTTP解析器保证,参数中传递的数据指针,只在回调函数内有效(即回调调用结束,数据指针无效). 因为http-parser返回解析结果的方式为:在需要解析的数据中,依靠指针和数据长度来供用户代码读取 如果可以的话,你也可以将read()到的数据,保存到在HEAP上申请的内存中,以避免非必要的数据拷贝。
比较笨的方法是:每读取一次将读取到的数据传递给http_parset_execute函数
.
注意:对于将一个完整的HTTP报文分开多次解析,应该使用同一个parser对象!
但是实际上的情况更复杂:
首先根据HTTP协议头部的规则,应该持续从socket读取数据,直到读到了\r\n\r\n
,表示头部报文结束。
这时可以传递给http_parser解析,或者根据下面的规则,继续读取实体部分的数据。
如果报文中使用Content-Length
指定传输实体的大小,接下来不论HTTP客户/服务器都因该根据读取到Content-Length
指定的实体大小
对于分块传输的实体,传输编码为chunked
。即Transfer-Encoding: chunked
。
分快传输的编码,一般只适用于HTTP内容响应(HTTP请求也可以指定传输编码为chunked,但不是所有HTTP服务器都支持)。
这时可以读取定量的数据(如4096字节) ,交给parser解析。然后重复此过程,直到chunk编码结束。
内容参考: HTTP权威指南
I’d venurte that this article has saved me more time than any other.
sildenafil 20 generic for viagra canadian drugstore viagra how viagra works viagra alternative 100mg viagra cost
gay teen dating forums gay movie about online dating japanese gay dating sim
Vente De Propecia Generique
can i buy levitra at walgreens Lsrfey plaquenil eye
buy ivermectin stromectol ivermectin 0.5
modafinil usa provigil pill
viagra buy online female viagra online canada https://viagranameed.com/
stromectol 3 mg tablet generic stromectol 12 mg stromectol 12 mg tablets