NO IMAGE

用C語言編寫http應用,解析URL是一個繁瑣的事兒。前幾天使用http_parser實現httpclient,發現裡面提供了一個解析URL的方法http_parser_parse_url,用起來相當方便。

http_parser_parse_url通過分析URL字串,把port、host、path、schema之類的資訊儲存在一個結構體http_parser_url中。通過看標頭檔案和原始碼,發現這個結構體僅僅是記錄了URL中各部分資訊的起始位置、長度,沒有做任何記憶體拷貝,效率上看還是不錯的。目前支援SCHEMA、PORT、HOST、PATH、QUERY、USERINFO、FRAGMENT七種資訊的提取。

http_parser_url定義如下:

struct http_parser_url {
uint16_t field_set;           /* Bitmask of (1 << UF_*) values */
uint16_t port;                /* Converted UF_PORT string */
struct {
uint16_t off;               /* Offset into buffer in which field starts */
uint16_t len;               /* Length of run in buffer */
} field_data[UF_MAX];
};

其中,field_set成員用於檢測解析到了哪種資訊(使用位與操作),field_data存放相應的URL資訊在原始URL中的起始位置和長度。

http_parser_parse_url()方法的原型:

int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);

需要說明的是is_connect引數,當傳1時,http_parser_parse_url方法將進行嚴格檢驗,如果URL中沒有port、schema將導致http_parser_parse_url方法失敗,返回非0值。一般給is_connect方法傳0即可。

下面是我使用的一段程式碼:

static int parse_url(struct http_client * httpc, const char *url)
{
struct http_parser_url u;
if(0 == http_parser_parse_url(url, strlen(url), 0, &u))
{
if(u.field_set & (1 << UF_PORT))
{
httpc->port = u.port;
}
else
{
httpc->port = 80;
}
if(httpc->host) free(httpc->host);
if(u.field_set & (1 << UF_HOST) )
{
httpc->host = (char*)malloc(u.field_data[UF_HOST].len 1);
strncpy(httpc->host, url u.field_data[UF_HOST].off, u.field_data[UF_HOST].len);
httpc->host[u.field_data[UF_HOST].len] = 0;
}
if(httpc->path) free(httpc->path);
if(u.field_set & (1 << UF_PATH))
{
httpc->path = (char*)malloc(u.field_data[UF_PATH].len 1);
strncpy(httpc->path, url u.field_data[UF_PATH].off, u.field_data[UF_PATH].len);
httpc->path[u.field_data[UF_PATH].len] = 0;
}
return 0;
}
return -1;
}

上面的程式碼是我實現的http_client中的一部分,僅供參考。