簡體   English   中英

解析HTTP GET-C

[英]Parsing HTTP GET - C

我正在嘗試解析HTTP GET請求,並一直使用strtok()這樣做,但是在嘗試使用strcpy()時遇到了問題。

我可以很好地解析文件路徑和文件名,但似乎無法解析遠程主機DNS名稱。 下面的代碼應標記一個字符串並獲取DNS名稱,然后將其存儲在名為hostchar[]

#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。 盡管如此,我將嘗試解釋您的代碼中發生了什么。

  1. 第一次,使用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"); 再次調用以獲得第二行。
  2. 第二次,您使用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變量。
  3. 第三次進入主循環時,您將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM