[英]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.