¿Mejores formas de analizar una URL usando C?

Tengo una URL como esta:

http://192.168.0.1:8080/servlet/rece 

Quiero analizar la URL para obtener los valores:

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

¿Cómo puedo hacer eso?

Escriba un analizador personalizado o use una de las funciones de reemplazo de cadenas para reemplazar el separador ‘:’ y luego use sscanf() .

Personalmente, robo el módulo HTParse.c del W3C (se usa en el navegador web de lynx , por ejemplo). Entonces, puedes hacer cosas como:

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

Lo importante de utilizar una biblioteca bien establecida y depurada es que no se cae en las trampas típicas del análisis de URL (muchas expresiones regulares fallan cuando el host es una dirección IP, por ejemplo, especialmente una IPv6).

Con una expresión regular si quieres la manera fácil. De lo contrario, use FLEX / BISON .

También podría usar una biblioteca de análisis URI

Escribí un código simple usando sscanf. Quiero tener una forma básica de analizarlo.

 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" 

Puede ser tarde, … lo que he usado, es – la función http_parser_parse_url() y las macros requeridas separadas de Joyent / HTTP parser lib – que funcionó bien, ~600 LOC.

Este ha reducido el tamaño y funcionó excelente para mí http://draft.scyphus.co.jp/lang/c/url_parser.html . Solo dos archivos (* .c, * .h).
Tuve que adaptar el código [1].

[1] Cambia todas las llamadas a funciones de http_parsed_url_free (purl) a parsed_url_free (purl)

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

Este C gist podría ser útil. Implementa una solución C pura con 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;} (...) 

yo escribí esto

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

Prueba

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

Fuera

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