【发布时间】:2023-03-17 14:13:01
【问题描述】:
我想知道,是否有可能找出响应流中标头结束的位置?
问题的背景如下,我在c中使用套接字从网站获取内容,内容以gzip编码。我想直接从流中读取内容并使用 zlib 对 gzip 内容进行编码。但是我怎么知道gzip内容开始了,http头已经完成了。
我粗略地尝试了两种方法,在我看来,它们给了我一些奇怪的结果。首先,我读入整个流,并在终端中打印出来,我的 http 标头以“\r\n\r\n”结尾,就像我预期的那样,但是第二次,我只检索一次响应以获取标头然后使用 while 循环读取内容,此处标题以没有“\r\n\r\n”结尾。
为什么?哪种方式才是阅读内容的正确方式?
我只是给你代码,这样你就可以看到我是如何从服务器获得响应的。
//first way (gives rnrn)
char *output, *output_header, *output_content, **output_result;
size_t size;
FILE *stream;
stream = open_memstream (&output, &size);
char BUF[BUFSIZ];
while(recv(socket_desc, BUF, (BUFSIZ - 1), 0) > 0)
{
fprintf (stream, "%s", BUF);
}
fflush(stream);
fclose(stream);
output_result = str_split(output, "\r\n\r\n");
output_header = output_result[0];
output_content = output_result[1];
printf("Header:\n%s\n", output_header);
printf("Content:\n%s\n", output_content);
.
//second way (doesnt give rnrn)
char *content, *output_header;
size_t size;
FILE *stream;
stream = open_memstream (&content, &size);
char BUF[BUFSIZ];
if((recv(socket_desc, BUF, (BUFSIZ - 1), 0) > 0)
{
output_header = BUF;
}
while(recv(socket_desc, BUF, (BUFSIZ - 1), 0) > 0)
{
fprintf (stream, "%s", BUF); //i would just use this as input stream to zlib
}
fflush(stream);
fclose(stream);
printf("Header:\n%s\n", output_header);
printf("Content:\n%s\n", content);
两者都给出相同的结果,将它们打印到终端,但第二个应该打印出更多的中断,至少我期望,因为它们在拆分字符串时会丢失。
我是 c 新手,所以我可能会监督一些简单的事情。
【问题讨论】:
-
标题总是以空行结束。它由 RFC 定义。内容可以用内容长度编码,也可以用分块编码,这在处理上有很大的不同。
-
你能解释一下为什么第二个有效吗?我的意思是我可以更改缓冲区大小,但仍将仅获取标题。服务器有什么特殊行为吗?
-
看来您的第二个示例在某些时候可能完全是偶然和运气。您只是连续两次从套接字读取。偶然的时机可能是第一个
recv()获得标题,第二个获得正文。但你不能指望这一点。您必须解析收到的数据并查找空白行。 -
以分块形式,内容被分段传输。首先,您需要检查什么是“传输编码”标头值(是的,不区分大小写)。如果它被“分块”,你就有麻烦了。您将得到一个字符串,而不是简单的内容长度,它包含下一段的长度,然后是数据,然后是下一个长度,依此类推。如果长度为 0,这是最后一部分,在它之后可能会有额外的头...如果您需要详细信息,您需要检查 RFC2616。