diff options
Diffstat (limited to 'src/url.c')
-rw-r--r-- | src/url.c | 112 |
1 files changed, 79 insertions, 33 deletions
@@ -18,11 +18,12 @@ # include <config.h> #endif #include "pies.h" +#include <netdb.h> #include <string.h> #include <errno.h> #include <limits.h> -/* proto://[user[:password]@][host[:port]/]path[;arg=str[;arg=str...] +/* scheme://[user[:password]@][host[:port]/]path[;arg=str[;arg=str...] */ static int @@ -59,17 +60,17 @@ url_parse_args (struct pies_url *url, char **str) static int url_parse_path (struct pies_url *url, char **str) { - char *p; - - p = strchr (*str, ';'); - if (!p) - p = *str + strlen (*str); - if (alloc_string(&url->path, *str, p)) - return 1; - *str = p; - if (*p) - ++ * str; - return url_parse_args (url, str); + char *p; + + p = strchr (*str, ';'); + if (!p) + p = *str + strlen (*str); + if (alloc_string (&url->path, *str, p)) + return 1; + *str = p; + if (*p) + ++*str; + return url_parse_args (url, str); } /* On input str points at the beginning of host part */ @@ -81,12 +82,29 @@ url_parse_host (struct pies_url *url, char **str) if (s[len] == ':') { + char *start = s + len + 1; char *q; - unsigned long n = strtoul (s + len + 1, &q, 10); - if ((*q && !strchr("/;:", *q)) || n > USHRT_MAX) + unsigned long n = strtoul (start, &q, 10); + if (n > USHRT_MAX) return 1; - url->port = n; - *str = q + strcspn(q, "/"); + if ((*q && !strchr ("/;:", *q))) + { + char *proto = url->proto_s ? url->proto_s : "tcp"; + size_t size = strcspn (start, "/;:"); + struct servent *serv; + + alloc_string_len (&url->port_s, start, size); + serv = getservbyname (url->port_s, proto); + if (!serv) + return 1; + url->port = ntohs (serv->s_port); + *str = start + size; + } + else + { + url->port = n; + *str = q; + } } else *str = s + len; @@ -106,22 +124,22 @@ url_parse_user (struct pies_url *url, char **str) { size_t len = strcspn (*str, ":;@/"); char *p = *str + len; - + switch (*p) { case ';': case ':': len = strcspn (p + 1, "@/:"); - if (p[len+1] == '@') + if (p[len + 1] == '@') { - if (alloc_string_len(&url->passwd, p + 1, len)) + if (alloc_string_len (&url->passwd, p + 1, len)) return 1; if (alloc_string (&url->user, *str, p)) return 1; *str = p + len + 2; } break; - + case '@': if (alloc_string (&url->user, *str, p)) return 1; @@ -132,27 +150,53 @@ url_parse_user (struct pies_url *url, char **str) } static int -url_parse_proto (struct pies_url *url, const char *str) +url_parse_scheme (struct pies_url *url, const char *str) { + size_t len; char *p; - + if (!str) { errno = EINVAL; return 1; } - - p = strchr (str, ':'); - if (!p) + + len = strcspn (str, ":+"); + if (!str[len]) { errno = EINVAL; return 1; } - - alloc_string (&url->proto, str, p); + alloc_string_len (&url->scheme, str, len); + + str += len; + + if (*str == '+') + { + struct protoent *proto; + + len = strcspn (++str, ":"); + if (str[len] == 0) + { + errno = EINVAL; + return 1; + } + alloc_string_len (&url->proto_s, str, len); + str += len; + proto = getprotobyname (url->proto_s); + if (!proto) + { + errno = EINVAL; + return 1; + } + url->proto = proto->p_proto; + } + else + url->proto = 0; + /* Skip slashes */ - for (p++; *p == '/'; p++) + for (p = (char*) str + 1; *p == '/'; p++) ; return url_parse_user (url, &p); } @@ -164,15 +208,17 @@ pies_url_destroy (struct pies_url **purl) struct pies_url *url = *purl; free (url->string); - free (url->proto); + free (url->scheme); free (url->host); + free (url->port_s); + free (url->proto_s); free (url->path); free (url->user); free (url->passwd); for (i = 0; i < url->argc; i++) free (url->argv[i]); free (url->argv); - free(url); + free (url); *purl = NULL; } @@ -181,12 +227,12 @@ pies_url_create (struct pies_url **purl, const char *str) { int rc; struct pies_url *url; - + url = malloc (sizeof (*url)); if (!url) return 1; - memset (url, 0, sizeof(*url)); - rc = url_parse_proto (url, str); + memset (url, 0, sizeof (*url)); + rc = url_parse_scheme (url, str); if (rc) pies_url_destroy (&url); else |