我有一个像这样的URL:
http://192.168.0.1:8080/servlet/rece
我想解析URL以获取值:
IP: 192.168.0.1
Port: 8080
page: /servlet/rece
我该怎么做?
HTParse.c
有许多依赖项,你能否解释一下如何轻松地从项目中“窃取”它?也许在2009年这是不可能的 ;) - Carson Reinke我使用sscanf编写了一个简单的代码,可以解析非常基本的URL。
#include <stdio.h>
int main(void)
{
const char text[] = "http://192.168.0.2:8888/servlet/rece";
char ip[100];
int port = 80;
char page[100];
sscanf(text, "http://%99[^:]:%99d/%99[^\n]", ip, &port, page);
printf("ip = \"%s\"\n", ip);
printf("port = \"%d\"\n", port);
printf("page = \"%s\"\n", page);
return 0;
}
./urlparse
ip = "192.168.0.2"
port = "8888"
page = "servlet/rece"
也许会晚一些,但我想分享一下我的解决方案——我使用了 http_parser_parse_url()
函数和从 Joyent/HTTP parser 库中分离出来的必需宏 - 这很有效率,只用了 ~600
行代码。
Libcurl现在有一个curl_url_get()
函数可以提取主机、路径等信息。
示例代码:https://curl.haxx.se/libcurl/c/parseurl.html
/* extract host name from the parsed URL */
uc = curl_url_get(h, CURLUPART_HOST, &host, 0);
if(!uc) {
printf("Host name: %s\n", host);
curl_free(host);
}
[1]将所有函数调用中的http_parsed_url_free(purl)改为parsed_url_free(purl)
//Rename the function called
//http_parsed_url_free(purl);
parsed_url_free(purl);
基于sscanf()
的纯解决方案:
//Code
#include <stdio.h>
int
main (int argc, char *argv[])
{
char *uri = "http://192.168.0.1:8080/servlet/rece";
char ip_addr[12], path[100];
int port;
int uri_scan_status = sscanf(uri, "%*[^:]%*[:/]%[^:]:%d%s", ip_addr, &port, path);
printf("[info] URI scan status : %d\n", uri_scan_status);
if( uri_scan_status == 3 )
{
printf("[info] IP Address : '%s'\n", ip_addr);
printf("[info] Port: '%d'\n", port);
printf("[info] Path : '%s'\n", path);
}
return 0;
}
[protocol_name]://[ip_address]:[port][/path]
类型的URI定制的。如果想了解URI语法中存在的组件,可以前往RFC 3986。"%*[^:]%*[:/]%[^:]:%d%s"
%*[^:]
帮助忽略协议/方案(例如http、https、ftp等)
它基本上捕获从开头到第一次遇到:
字符的字符串。由于我们在%
字符后面使用了*
,因此捕获的字符串将被忽略。
%*[:/]
帮助忽略协议和IP地址之间的分隔符,即://
%[^:]
帮助捕获分隔符后面的字符串,直到遇到:
。这个捕获的字符串就是IP地址。
:%d
帮助捕获:
字符右侧的数字(在捕获IP地址期间遇到的数字)。在这里捕获的数字基本上是您的端口号。
%s
如您所知,将帮助您捕获剩余的字符串,这些字符串仅是您正在查找的资源的路径。
我写了这个
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
const char* protocol = 0;
const char* site = 0;
const char* port = 0;
const char* path = 0;
} URL_INFO;
URL_INFO* split_url(URL_INFO* info, const char* url)
{
if (!info || !url)
return NULL;
info->protocol = strtok(strcpy((char*)malloc(strlen(url)+1), url), "://");
info->site = strstr(url, "://");
if (info->site)
{
info->site += 3;
char* site_port_path = strcpy((char*)calloc(1, strlen(info->site) + 1), info->site);
info->site = strtok(site_port_path, ":");
info->site = strtok(site_port_path, "/");
}
else
{
char* site_port_path = strcpy((char*)calloc(1, strlen(url) + 1), url);
info->site = strtok(site_port_path, ":");
info->site = strtok(site_port_path, "/");
}
char* URL = strcpy((char*)malloc(strlen(url) + 1), url);
info->port = strstr(URL + 6, ":");
char* port_path = 0;
char* port_path_copy = 0;
if (info->port && isdigit(*(port_path = (char*)info->port + 1)))
{
port_path_copy = strcpy((char*)malloc(strlen(port_path) + 1), port_path);
char * r = strtok(port_path, "/");
if (r)
info->port = r;
else
info->port = port_path;
}
else
info->port = "80";
if (port_path_copy)
info->path = port_path_copy + strlen(info->port ? info->port : "");
else
{
char* path = strstr(URL + 8, "/");
info->path = path ? path : "/";
}
int r = strcmp(info->protocol, info->site) == 0;
if (r && info->port == "80")
info->protocol = "http";
else if (r)
info->protocol = "tcp";
return info;
}
测试
int main()
{
URL_INFO info;
split_url(&info, "ftp://192.168.0.1:8080/servlet/rece");
printf("Protocol: %s\nSite: %s\nPort: %s\nPath: %s\n", info.protocol, info.site, info.port, info.path);
return 0;
}
出口
Protocol: ftp
Site: 192.168.0.1
Port: 8080
Path: /servlet/rece
https://github.com/luismartingil/per.scripts/tree/master/c_parse_http_url
它使用
// Parsing the tmp_source char*
if (sscanf(tmp_source, "http://%99[^:]:%i/%199[^\n]", ip, &port, page) == 3) { succ_parsing = 1;}
else if (sscanf(tmp_source, "http://%99[^/]/%199[^\n]", ip, page) == 2) { succ_parsing = 1;}
else if (sscanf(tmp_source, "http://%99[^:]:%i[^\n]", ip, &port) == 2) { succ_parsing = 1;}
else if (sscanf(tmp_source, "http://%99[^\n]", ip) == 1) { succ_parsing = 1;}
(...)
编写自定义解析器或使用其中一个字符串替换函数来替换分隔符 ':',然后使用 sscanf()
。