Files
zTC1/mico-os/libraries/utilities/url/url.c

294 lines
7.0 KiB
C

/* -*- encoding: utf-8; -*- */
/* -*- c-mode -*- */
/* File-name: <url.c> */
/* Author: <Xsoda> */
/* Create: <Friday December 20 12:38:02 2013> */
/* Time-stamp: <Wednesday December 25, 10:10:57 2013> */
/* Mail: <Xsoda@Live.com> */
#include "common.h"
#include "debug.h"
#include "url.h"
#define url_log(M, ...) custom_log("URL", M, ##__VA_ARGS__)
#define HAVE_STRNDUP (0)
static char *str_hosttype[] = { "host ipv4", "host ipv6", "host domain", NULL };
#if HAVE_STRNDUP
static char *strndup(const char *str, int n)
{
char *dst;
if (!str) return NULL;
if (n < 0) n = strlen(str);
if (n == 0) return NULL;
if ((dst = (char *)malloc(n + 1)) == NULL)
return NULL;
memcpy(dst, str, n);
dst[n] = 0;
return dst;
}
#else
extern char* strndup(const char* str, size_t n);
#endif
static int host_is_ipv4(char *str)
{
if (!str) return 0;
while (*str)
{
if ((*str >= '0' && *str <= '9') || *str == '.')
str++;
else
return 0;
}
return 1;
}
void parse_query(url_field_t *url, char *query)
{
char *chr;
chr = strchr(query, '=');
while (chr)
{
if (url->query)
url->query = realloc(url->query, (url->query_num + 1) * sizeof(*url->query));
else
url->query = malloc(sizeof(*url->query));
url->query[url->query_num].name = strndup(query, chr - query);
query = chr + 1;
chr = strchr(query, '&');
if (chr)
{
url->query[url->query_num].value = strndup(query, chr - query);
url->query_num++;
query = chr + 1;
chr = strchr(query, '=');
}
else
{
url->query[url->query_num].value = strndup(query, -1);
url->query_num++;
break;
}
}
}
url_field_t *url_parse (const char *str)
{
const char *pch;
char *query;
url_field_t *url;
query = NULL;
if ((url = (url_field_t *)malloc(sizeof(url_field_t))) == NULL)
return NULL;
memset(url, 0, sizeof(url_field_t));
if (str && str[0])
{
url->href = strndup(str, -1);
pch = strchr(str, ':'); /* parse schema */
if (pch && pch[1] == '/' && pch[2] == '/')
{
url->schema = strndup(str, pch - str);
str = pch + 3;
}
else
goto __fail;
pch = strchr(str, '@'); /* parse user info */
if (pch)
{
pch = strchr(str, ':');
if (pch)
{
url->username = strndup(str, pch - str);
str = pch + 1;
pch = strchr(str, '@');
if (pch)
{
url->password = strndup(str, pch - str);
str = pch + 1;
}
else
goto __fail;
}
else
goto __fail;
}
if (str[0] == '[') /* parse host info */
{
str++;
pch = strchr(str, ']');
if (pch)
{
url->host = strndup(str, pch - str);
str = pch + 1;
if (str[0] == ':')
{
str++;
pch = strchr(str, '/');
if (pch)
{
url->port = strndup(str, pch - str);
str = pch + 1;
}
else
{
url->port = strndup(str, -1);
str = str + strlen(str);
}
}
url->host_type = HOST_IPV6;
}
else
goto __fail;
}
else
{
const char *pch_slash;
pch = strchr(str, ':');
pch_slash = strchr(str, '/');
if (pch && (!pch_slash || (pch_slash && pch<pch_slash)))
{
url->host = strndup(str, pch - str);
str = pch + 1;
pch = strchr(str, '/');
if (pch)
{
url->port = strndup(str, pch - str);
str = pch + 1;
}
else
{
url->port = strndup(str, -1);
str = str + strlen(str);
}
}
else
{
pch = strchr(str, '/');
if (pch)
{
url->host = strndup(str, pch - str);
str = pch + 1;
}
else
{
url->host = strndup(str, -1);
str = str + strlen(str);
}
}
url->host_type = host_is_ipv4(url->host) ? HOST_IPV4 : HOST_DOMAIN;
}
if (str[0]) /* parse path, query and fragment */
{
pch = strchr(str, '?');
if (pch)
{
url->path = strndup(str, pch - str);
str = pch + 1;
pch = strchr(str, '#');
if (pch)
{
query = strndup(str, pch - str);
str = pch + 1;
url->fragment = strndup(str, -1);
}
else
{
query = strndup(str, -1);
str = str + strlen(str);
}
parse_query(url, query);
free(query);
}
else
{
pch = strchr(str, '#');
if (pch)
{
url->path = strndup(str, pch - str);
str = pch + 1;
url->fragment = strndup(str, -1);
str = str + strlen(str);
}
else
{
url->path = strndup(str, -1);
str = str + strlen(str);
}
}
}
}
else
{
__fail:
url_free(url);
return NULL;
}
return url;
}
void url_free(url_field_t *url)
{
if (!url) return;
if (url->href) free(url->href);
if (url->schema) free(url->schema);
if (url->username) free(url->username);
if (url->password) free(url->password);
if (url->host) free(url->host);
if (url->port) free(url->port);
if (url->path) free(url->path);
if (url->query)
{
int i;
for (i = 0; i < url->query_num; i++)
{
free(url->query[i].name);
free(url->query[i].value);
}
free(url->query);
}
if (url->fragment) free(url->fragment);
free(url);
}
void url_field_print(url_field_t *url)
{
if (!url) return;
url_log(" href: '%s'", url->href);
url_log(" schema: '%s'", url->schema);
if (url->username)
url_log(" username: '%s'", url->username);
if (url->password)
url_log(" password: '%s'", url->password);
url_log(" host: '%s' (%s)", url->host, str_hosttype[url->host_type]);
if (url->port)
url_log(" port: '%s'", url->port);
if (url->path)
url_log(" path: '%s'", url->path);
if (url->query_num > 0)
{
int i;
url_log(" query");
for (i = 0; i < url->query_num; i++)
{
url_log(" * %s : %s", url->query[i].name, url->query[i].value);
}
}
if (url->fragment)
url_log(" fragment: '%s'", url->fragment);
}
#if 0
int main()
{
url_field_t *url = url_parse("schema://usr:pwd@localhost:port/path?a=b&c=d&e=f#foo");
url_field_print(url);
url_free(url);
}
#endif