web-dev-qa-db-fra.com

Meilleurs moyens d’analyser une URL en utilisant C?

J'ai une URL comme celle-ci:

http://192.168.0.1:8080/servlet/rece

Je veux analyser l'URL pour obtenir les valeurs:

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

Comment je fais ça?

33
Jiang Bian

Écrivez un analyseur personnalisé ou utilisez l'une des fonctions de remplacement de chaîne pour remplacer le séparateur ':', puis utilisez sscanf().

1
dirkgently

Personnellement, je vole le module HTParse.cdu W3C (il est utilisé dans le navigateur lynx Web, par exemple). Ensuite, vous pouvez faire des choses comme:

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

L’important dans l’utilisation d’une bibliothèque bien établie et déboguée est de ne pas tomber dans les pièges Typiques de l’analyse d’URL (de nombreuses regexps échouent lorsque l’hôte est une adresse IP, par exemple spécialement une adresse IPv6).

24
bortzmeyer

Avec un expression régulière si vous voulez le moyen le plus simple. Sinon, utilisez FLEX / BISON .

Vous pouvez aussi utiliser une bibliothèque d’analyses URI

10
dsm

Peut-être en retard, ... Ce que j’ai utilisé, c’est - la fonction http_parser_parse_url() et les macros requises séparées de l’analyseur Joyent/HTTP lib - qui a bien fonctionné, ~600LOC.

9
vyom

J'ai écrit un code simple, utilisez sscanf. Je veux avoir un moyen de base pour l'analyser.

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"
9
Jiang Bian

Celui-ci a une taille réduite et fonctionne parfaitement pour moi http://draft.scyphus.co.jp/lang/c/url_parser.html . Juste deux fichiers (* .c, * .h). 
J'ai dû adapter le code [1]. 

[1] Remplacez tous les appels de fonction de http_parsed_url_free (purl) à parsed_url_free (purl).

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

Libcurl a maintenant la fonction curl_url_get() qui permet d'extraire l'hôte, le chemin, etc.

Exemple de code: 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
JohnMudd

Cet élément C pourrait être utile. Il implémente une solution C pure avec sscanf.

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

Il utilise

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

J'ai écrit ça

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

Test

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

En dehors

Protocol: ftp
Site: 192.168.0.1
Port: 8080
Path: /servlet/rece
0
X Stylish