Melhores maneiras de analisar um URL usando C?

Eu tenho um URL como este:

http://192.168.0.1:8080/servlet/rece 

Eu quero analisar o URL para obter os valores:

 IP: 192.168.0.1 Port: 8080 page: /servlet/rece 

Como faço isso?

Escreva um analisador customizado ou use uma das funções de substituição de sequência para replace o separador ‘:’ e, em seguida, use sscanf() .

Pessoalmente, eu roubo o módulo HTParse.c do W3C (ele é usado no navegador da Web do lynx , por exemplo). Então, você pode fazer coisas como:

  strncpy(hostname, HTParse(url, "", PARSE_HOST), size) 

O importante sobre o uso de uma biblioteca bem estabelecida e depurada é que você não se enquadra nas armadilhas típicas da análise de URL (muitos regexps falham quando o host é um endereço IP, por exemplo, especialmente um endereço IPv6).

Com uma expressão regular, se você quer o caminho mais fácil. Caso contrário, use o FLEX / BISON .

Você também pode usar uma biblioteca de análise de URI

Eu escrevi um código simples, use sscanf. Eu quero ter uma maneira básica de analisá-lo.

 cat urlparse.c #include  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" 

Pode ser tarde, … o que eu usei é – a function http_parser_parse_url() e as macros necessárias separadas do Joyent / HTTP parser lib – que funcionou bem, ~600 LOC.

Este tem tamanho reduzido e funcionou muito bem para mim http://draft.scyphus.co.jp/lang/c/url_parser.html . Apenas dois arquivos (* .c, * .h).
Eu tive que adaptar o código [1].

[1] Altere todas as chamadas de function de http_parsed_url_free (purl) para parsed_url_free (purl)

  //Rename the function called //http_parsed_url_free(purl); parsed_url_free(purl); 

Este Cist pode ser útil. Implementa uma solução C pura com sscanf.

https://github.com/luismartingil/per.scripts/tree/master/c_parse_http_url

Usa

 // 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;} (...) 

eu escrevi isto

 #include  #include  #include  #include  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; } 

Teste

 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; } 

Fora

 Protocol: ftp Site: 192.168.0.1 Port: 8080 Path: /servlet/rece