cgi.h:資料結構定義 (Node 鏈結串列節點、Index 容器)。get_input.c:進入點,依 REQUEST_METHOD 分派 GET/POST 解析。analyze.c:POST 內容類型判斷,派送至 analy_a (urlencoded) 或 analy_m (multipart)。analy_a.c:解析 name=value&name2=value2 格式,處理 + (空白)、%XX (URL 編碼)。analy_m.c:解析 multipart/form-data,依 boundary 分割欄位。fun1.c:十六進位字元轉數值 (URL 解碼核心)。get_value.c:依 name 查詢 value。free_input.c:釋放動態記憶體。
typedef struct Node {
char *name; // 欄位名
char *value; // 欄位值
struct Node *next;
} Node;
typedef struct Index {
Node *head; // 鏈結串列頭
char *buffer; // 原始輸入緩衝區 (供釋放用)
} Index;
REQUEST_METHOD。QUERY_STRING 取得資料 → analy_a()。CONTENT_LENGTH 位元組從 stdin → 依 CONTENT_TYPE 派送。Index*,呼叫端負責 free_input()。buffer:將 =、&、+、%XX 替換為結束符/空白/解碼字元。name 指向 buffer 內對應位置,value 同理。name="..." 雙引號內容作為欄位名。\r\n 之後,直到下一個 boundary 前 (扣除結尾 \r\n)。
char fun1(char ch) {
if (ch < 'A') return ch - '0'; // '0'~'9'
else if (ch < 'a') return ch - 'A' + 10; // 'A'~'F'
else return ch - 'a' + 10; // 'a'~'f'
}
#include "cgi.h"
int main() {
Index *input = get_input();
if (!input) return 0;
char *username = get_value(input->head, "username");
char *password = get_value(input->head, "password");
printf("Content-Type: text/html\n\n");
printf("");
printf("Username: %s
", username ? username : "(empty)");
printf("Password: %s
", password ? password : "(empty)");
printf("");
free_input(input);
return 0;
}
| 限制 | 說明 |
|---|---|
| 緩衝區就地修改 | 原始資料遭破壞,無法二次使用 |
| 無檔案上傳支援 | multipart 解析未處理檔案內容儲存 |
| 緩衝區大小受限 | POST 大資料需分塊讀取,目前一次性讀入 |
| 編碼假設 | 預設 ASCII/UTF-8,未處理多位元組字元邊界 |
現代 C/C++ 專案建議使用成熟函式庫:
cgicc (C++)CivetWeb 內建表單解析fcgi_stdio