[英]Parsing HTTP GET - C
我正在尝试解析HTTP GET请求,并一直使用strtok()
这样做,但是在尝试使用strcpy()
时遇到了问题。
我可以很好地解析文件路径和文件名,但似乎无法解析远程主机DNS名称。 下面的代码应标记一个字符串并获取DNS名称,然后将其存储在名为host
的char[]
。
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int c = 0, c2 = 0;
char *tk, *tk2, *tk3, *tk4;
char buf[64], buf2[64], buf3[64], buf4[64];
char host[1024], path[64], file[64];
strcpy(buf, "GET /~yourloginid/index.htm HTTP/1.1\r\nHost: remote.cba.csuohio.edu\r\n\r\n");
tk = strtok(buf, "\r\n");
while(tk != NULL)
{
if(c == 1)
{
tk2 = strtok(tk, " ");
while(tk2 != NULL)
{
if(c2 == 1)
{
printf("%s\n", tk2);
strcpy(host, tk2);
// printf("%s\n", host);
}
++c2;
tk2 = strtok(NULL, " ");
}
}
++c;
tk = strtok(NULL, "\r\n");
}
return 0;
}
请耐心等待,因为我是一名新C程序员,所以这段代码可能很难看。 每次尝试运行程序时,都会出现“ Segmentation fault (core dumped)
错误,并且我相信这与strcpy()
。 我可以很好地打印出标记化的字符串,但似乎无法将其复制到char[]
。
抱歉, strtok(3)函数根本无法解析HTTP。 尽管如此,我将尝试解释您的代码中发生了什么。
tk=="GET /~yourloginid/index.html HTTP/1.1"
进入循环,并且缓冲区已更改为"GET /~yourloginid/index.htm HTTP/1.1\\0\\nHost: ..."
。 由于c==0
,所以您不会进入if块,因此将使c
变量递增,并且tk=strtok(NULL, "\\r\\n");
再次调用以获得第二行。 tk=="Host: remote.cba.scuohio.edu\\r\\n..."
进入循环,因为strtok(3)跳过了字符串的第一个\\0
,跳过了所有\\r
和\\n
字符,并且得到了(strtok现在在该部分之后放了第二个\\0
,导致tk=="Host: remote.cba.scuohio.edu\\0\\n..."
。当c==1
这次,您进入了if块,并调用strtok(tk, " ");
;,这使strtok(3) 忘记了要解析的字符串的范围,并在Host: remote.cba.csuohio.edu"
上开始了新的解析Host: remote.cba.csuohio.edu"
(当您向其传递第一个非null参数时),它将返回tk=="Host:"
,在"host:"
后放置\\0
第二次进入内部循环时,您将复制该值host
变量。 tk==NULL
作为上次调用tk=strtok(NULL, " ");
它返回了NULL
(在内部循环中),strtok将继续返回NULL
直到您再次初始化它,并传递第一个非null参数。 strtok(3)对作为第一个参数(在其上写入信息)传递的字符串进行操作并对其进行修改。 此外,它还有一个全局隐藏变量来标记您要解析的字符串的结尾,以便在解析完成后能够返回NULL
。 如果将对strtok(3)的调用嵌套,您将获得未定义的行为,因为当您再次初始化函数时,如果传递第一个非null参数,则会释放该函数的内部状态。 那就是你失败的原因。
调用strtok(3)有很多弊端,它不能嵌套在多个嵌套循环中,因为它存储与解析内容有关的内部状态。 强烈建议不要使用它。 如果希望它可嵌套,则必须切换到strtok_r(3) 。 该函数有一个额外的参数,可让您在外部保存strtok的内部状态,因此您可以使多个strtok并行工作。
此外,strtok将解析好"GET_/~yourlogin..."
不是"GET___/~yourlogin..."
(我已使用下划线表示空格,以显示方法名和uri之间的多个空格),并且后者不允许HTTP。 出于同样的原因,您可以获得"Host:remote.cba.csuohio.edu"
作为有效的头字段(但是,强烈建议不要使用此方法),并且您将无法正确解析该字段。 另外,“ Host:
标头字段可能不是HTTP标头的第一行,因此如果您不小心,可以跳过它。
如果要解析HTTP,我可以推荐的第一个阅读材料是RFC-2616“超文本传输协议-HTTP / 1.1” ,这是实现者必须遵循的强制性文件。 当心,这是一个密集而庞大的文档。
在我看来,您要复制到buf中的字符串比在buf的定义语句中分配的64个字符长。
Trekator是对的。
替换为:
strcpy(buf, "GET /~yourloginid/index.htm HTTP/1.1\r\nHost: remote.cba.csuohio.edu\r\n\r\n");
有:
char buf[] = "GET /~yourloginid/index.htm HTTP/1.1\r\nHost: remote.cba.csuohio.edu\r\n\r\n";
如果可能会溢出目标缓冲区,则最好使用strncpy
。
一些忠告:
(1)如果您使用变量名比'tk2'等更多信息,您会发现自己的生活要容易得多。
(2)您可以使用strstr()
查找不修改原始字符串的cr-nl,并且它没有strtok()
的嵌套问题。
(3)通常,您不能指望Host:始终是第二行,因此寻找它的更通用方法更可靠。
(4)确保事物适合其目的地是“安全编程101”。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main()
{
int lnum = 0;
char buf[] = "GET /~yourloginid/index.htm HTTP/1.1\r\nHost: remote.cba.c
suohio.edu\r\n\r\n";
char * line;
char * crnl;
char * colon;
char * arg;
char host[1024] = "(not found)";
for (line = buf;
(crnl = strstr(line, "\r\n")) != NULL;
line = crnl + 2) {
++lnum;
if (lnum == 1) {
/* "GET" line is always first */
continue;
}
if (crnl == line) { /* empty line marks end */
break;
}
if (((colon = strchr(line, ':')) == NULL) || (colon > crnl)) {
fprintf(stderr, "no colon in header line?\n");
break;
}
if (strncasecmp(line, "Host", colon - line) == 0) {
for (arg = colon + 1; isspace(*arg); ++arg) {}
if ((crnl - arg) >= sizeof(host)) {
fprintf(stderr, "hostname too big\n");
} else {
strncpy(host, arg, crnl - arg);
host[crnl - arg] = '\0';
}
}
}
printf("host was '%s'\n", host);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.