如何正确解析传入的HTTP请求 我用WiSCK创建了一个C++应用程序,它有一个小的(只处理我需要的几个特性)HTTP服务器。这用于使用http请求与外部世界通信。它可以工作,但有时请求没有得到正确处理,因为解析失败。现在我很确定请求的格式是正确的,因为它们是由firefox/chrome或perl/C#(具有http模块/dll)等主要web浏览器发送的

如何正确解析传入的HTTP请求 我用WiSCK创建了一个C++应用程序,它有一个小的(只处理我需要的几个特性)HTTP服务器。这用于使用http请求与外部世界通信。它可以工作,但有时请求没有得到正确处理,因为解析失败。现在我很确定请求的格式是正确的,因为它们是由firefox/chrome或perl/C#(具有http模块/dll)等主要web浏览器发送的,c++,http,parsing,winsock,C++,Http,Parsing,Winsock,经过一些调试后,我发现问题实际上在于接收消息。当消息包含多个部分时(没有在一个recv()call中读取),有时解析会失败。关于如何解决这个问题,我经历了无数次尝试,但似乎没有什么是足够可靠的 我现在要做的是读入数据,直到找到指示标头结尾的“\r\n\r\n”序列。如果WSAGetLastError()在发现该序列之前报告了10035以外的内容(连接关闭/失败),我将丢弃该消息。当我知道我有整个头,我解析它,并寻找有关身体长度的信息。然而,我不确定这些信息是否是强制性的(我认为不是),如果没有这

经过一些调试后,我发现问题实际上在于接收消息。当消息包含多个部分时(没有在一个
recv()
call中读取),有时解析会失败。关于如何解决这个问题,我经历了无数次尝试,但似乎没有什么是足够可靠的

我现在要做的是读入数据,直到找到指示标头结尾的
“\r\n\r\n”
序列。如果
WSAGetLastError()
在发现该序列之前报告了10035以外的内容(连接关闭/失败),我将丢弃该消息。当我知道我有整个头,我解析它,并寻找有关身体长度的信息。然而,我不确定这些信息是否是强制性的(我认为不是),如果没有这些信息,我该怎么办——这是否意味着没有尸体?另一个问题是,我不知道是否应该在主体之后查找
“\r\n\r\n”
(如果其长度大于零)

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


注意:我知道有一些http服务器的实现。出于各种原因,我想要我自己的。是的,重新发明轮子是不好的,我也知道。

你可以看看他们的代码,看看他们是如何处理HTTP消息的


或者你可以看看,有些字段你应该使用。显然,只有有缺陷的浏览器才会在最后发送额外的CRLF。

如果您打算编写自己的解析器,我会采取这样的方法:使用状态机编译器并基于此构建解析器。如果你小心的话,Ragel可以处理成块的输入

老实说,不过,我会用


您的go-to资源应该是,它描述了HTTP 1.1,您可以使用它来构造解析器。祝你好运

HTTP
GET
/
HEAD
请求没有正文,而
POST
请求也可以没有正文。您必须检查它是否是
获取
/
标题
,如果是,则您没有发送内容(正文/消息)。如果是
POST
,请按照@gbjbaanb所说的那样执行。

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

若方法为“POST”,则应读取“内容长度”字段中指定的“\r\n\r\n”之后的字节数

所以伪代码是:

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”时,内容后面才会有“\r\n”。内容可以是二进制数据,它没有任何终止序列,获取其大小的一种方法是使用内容长度字段。

get和HEAD请求可以有一个主体。因此,不必检查方法名。@Julian,HTTP规范中没有明确指定是否可以在GET/HEAD请求中包含正文。我在本地对它进行了测试,它可以与apache一起使用,但我以前从未在现实世界的实现中看到过这一点,我正在阅读,现在,感谢您指出这一点。是否在实践中使用了某些内容以及是否允许使用这些内容是两个独立的问题。重要的是,请求解析对于所有方法都是一样的。(与响应解析相反,HEAD是特殊的)。请参阅--这就是我们修改RFC2616的原因。不,它不依赖于方法名。有关详细信息,请参阅。另外,请记住,HTTP 1.1请求也不需要使用
内容长度
头。他们可以使用
传输编码:chunked
,在这种情况下,消息长度在消息数据本身内部进行编码;有关当前的草案文本,请参见。这看起来不错,谢谢。如果有帮助的话,我很乐意接受你的回答。http解析器和最终链接+1。那个源代码可以生成快速的代码,我真的印象深刻。这太糟糕了。说到Ragel,你可以看看HttpMachine()。另外,如果用C语言编写,状态机是用Ragel编译的,我认为它应该很容易适应C++。三个以上的.rl(Ragel sources)文件不是与C#绑定的,而是通用的(因此已经做了很多工作)。除非您这样做是为了好玩,请查看下面Jack提供的http解析器链接。它看起来很漂亮,而且不想劫持你的插座。@Matt Joiner:我看过了,它看起来确实很好。但是我真的需要写我自己的,它只支持所有http特性的一小部分,同时知道一些特殊的命令。如果我需要一个完整的http服务器,我肯定不会自己编写。请记住,提供的代码很小,不会对您提出任何要求。您可以通过自定义它提供的几个回调,以任何方式停止、忽略和包装它。我同情自己动手的愿望,但这将为您节省数小时的调试时间和以后由于不可预见的输入而产生的bug。