Лучшие способы анализа URL с помощью C? - PullRequest
33 голосов
/ 07 апреля 2009

У меня есть такой URL:

http://192.168.0.1:8080/servlet/rece

Я хочу разобрать URL, чтобы получить значения:

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

Как мне это сделать?

Ответы [ 9 ]

24 голосов
/ 07 апреля 2009

Лично я краду модуль HTParse.c из W3C (он используется, например, в веб-браузере lynx ). Затем вы можете делать такие вещи, как:

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

Важным моментом использования хорошо отлаженной и отлаженной библиотеки является то, что вы не попадаете в типичную ловушки при разборе URL (многие регулярные выражения завершаются ошибкой, когда хост является IP-адресом, например, особенно IPv6).

10 голосов
/ 07 апреля 2009

Я написал простой код, использующий sscanf. Я хочу иметь базовый способ анализа.

cat urlparse.c
#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"
10 голосов
/ 07 апреля 2009

С регулярным выражением , если вы хотите легкий путь. В противном случае используйте FLEX / BISON .

Вы также можете использовать библиотеку URI

9 голосов
/ 29 ноября 2013

Может быть поздно, ... то, что я использовал, - функция http_parser_parse_url() и необходимые макросы, отделенные от анализатор Joyent / HTTP lib - который работал хорошо, ~600 LOC.

2 голосов
/ 23 августа 2013

Этот уменьшенный размер и отлично сработал для меня http://draft.scyphus.co.jp/lang/c/url_parser.html. Всего два файла (* .c, * .h).
Мне пришлось адаптировать код [1].

[1] Изменить все вызовы функций с http_parsed_url_free (purl) на parsed_url_free (purl)

   //Rename the function called
   //http_parsed_url_free(purl);
   parsed_url_free(purl);
1 голос
/ 07 апреля 2009

Напишите собственный анализатор или используйте одну из функций замены строк для замены разделителя ':', а затем используйте sscanf().

0 голосов
/ 06 декабря 2018

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);
}
0 голосов
/ 18 августа 2018

Я написал это

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

Out

Protocol: ftp
Site: 192.168.0.1
Port: 8080
Path: /servlet/rece
0 голосов
/ 17 сентября 2013

Эта суть C может быть полезна. Он реализует решение на чистом C с помощью sscanf.

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