如何正确解析传入的HTTP请求

时间:2010-09-13 07:09:05

标签: c++ http parsing winsock

我使用WinSck创建了一个C ++应用程序,它有一个很小的(只需处理一些我需要的功能)http服务器实现。这用于使用http请求与外界通信。它有效,但有时请求处理不正确,因为解析失败。现在我非常确定请求是否正确形成,因为它们是由主要的Web浏览器发送的,例如firefox / chrome或perl / C#(具有http modules / dll)。

经过一些调试后,我发现问题实际上是在接收消息时。当消息不只是一个部分(它不是在一个recv()调用中读取)时,有时解析失败。我已经经历了很多关于如何解决这个问题的尝试,但似乎没有什么可靠的。

我现在做的是我读入数据,直到找到表示标题结尾的"\r\n\r\n"序列。如果在发现此类序列之前WSAGetLastError()报告的内容不是10035(连接已关闭/失败),则会丢弃该消息。当我知道我有整个标题时,我会解析它并查找有关体长的信息。但是我不确定这些信息是否是强制性的(我认为不是),如果没有这样的信息我应该怎么做 - 这是否意味着没有身体?另一个问题是我不知道我是否应该在身体后面寻找"\r\n\r\n"(如果它的长度大于零)。

有人知道如何可靠地解析http消息吗?

注意:我知道那里有http服务器的实现。出于各种原因我想要自己的。是的,重新发明轮子很糟糕,我也知道。

4 个答案:

答案 0 :(得分:8)

如果您已经开始编写自己的解析器,我将采用Zed Shaw方法:使用Ragel状态机编译器并基于此构建解析器。如果你小心的话,Ragel可以处理以块为单位的输入。

老实说,我只是使用something like this

您的首选资源应该是RFC 2616,它描述了HTTP 1.1,您可以使用它来构建解析器。祝你好运!

答案 1 :(得分:3)

您可以尝试查看他们的代码以了解他们如何处理HTTP消息。

或者您可以查看the spec,您应该使用message length个字段。只有错误的浏览器显然会在最后发送额外的CRLF。

答案 2 :(得分:0)

无论如何,HTTP请求在请求头的末尾和请求数据之前都有“\ r \ n \ r \ n”,即使请求是“GET / HTTP / 1.0 \ r \ n \ r \ n”

如果方法是“POST”,则应在“\ r \ n \ r \ n”之后读取多个字节,如Content-Length字段中所指定。

所以伪代码是:

read_until(buf, "\r\n\r\n");
if(buf.starts_with("POST")
{
   contentLength = regex("^Content-Length: (\d+)$").find(buf)[1];
   read_all(buf, contentLength);
}

仅在内容包含内容后,才会在内容后面显示“\ r \ n \ r \ n”。内容可以是二进制数据,它没有任何终止序列,获取其大小的一种方法是使用Content-Length字段。

答案 3 :(得分:-1)

HTTP GET / HEAD请求没有正文,POST请求也没有正文。你必须检查它是GET / HEAD,如果是,那么你没有发送任何内容(正文/消息)。如果它是POST,请按照specs say about parsing a message of known/unknown length进行操作,如@gbjbaanb所说。