diff options
author | Ben Straub <bs@github.com> | 2013-11-04 11:42:14 -0800 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2013-11-04 11:42:14 -0800 |
commit | c227c173b84c8107a8933aeed947f16d82224377 (patch) | |
tree | de2c6457d89387222b7a331c398ce3f67aed0b41 /src/netops.c | |
parent | 56c1cda28a4b33fb305d99a2c7985a37efd3839d (diff) | |
download | libgit2-c227c173b84c8107a8933aeed947f16d82224377.tar.gz |
Use http_parser_parse_url to parse urls
Diffstat (limited to 'src/netops.c')
-rw-r--r-- | src/netops.c | 89 |
1 files changed, 43 insertions, 46 deletions
diff --git a/src/netops.c b/src/netops.c index d2acdb240..9653344fe 100644 --- a/src/netops.c +++ b/src/netops.c @@ -32,6 +32,7 @@ #include "netops.h" #include "posix.h" #include "buffer.h" +#include "http_parser.h" #ifdef GIT_WIN32 static void net_set_error(const char *str) @@ -582,7 +583,7 @@ int gitno_connection_data_from_url( const char *service_suffix) { int error = -1; - const char *default_port = NULL; + const char *default_port = NULL, *path_search_start = NULL; char *original_host = NULL; /* service_suffix is optional */ @@ -594,22 +595,18 @@ int gitno_connection_data_from_url( gitno_connection_data_free_ptrs(data); if (!git__prefixcmp(url, prefix_http)) { - url = url + strlen(prefix_http); + path_search_start = url + strlen(prefix_http); default_port = "80"; if (data->use_ssl) { giterr_set(GITERR_NET, "Redirect from HTTPS to HTTP is not allowed"); goto cleanup; } - } - - if (!git__prefixcmp(url, prefix_https)) { - url += strlen(prefix_https); + } else if (!git__prefixcmp(url, prefix_https)) { + path_search_start = url + strlen(prefix_https); default_port = "443"; data->use_ssl = true; - } - - if (url[0] == '/') + } else if (url[0] == '/') default_port = data->use_ssl ? "443" : "80"; if (!default_port) { @@ -618,18 +615,19 @@ int gitno_connection_data_from_url( } error = gitno_extract_url_parts( - &data->host, &data->port, &data->user, &data->pass, + &data->host, &data->port, &data->path, &data->user, &data->pass, url, default_port); if (url[0] == '/') { /* Relative redirect; reuse original host name and port */ + path_search_start = url; git__free(data->host); data->host = original_host; original_host = NULL; } if (!error) { - const char *path = strchr(url, '/'); + const char *path = strchr(path_search_start, '/'); size_t pathlen = strlen(path); size_t suffixlen = service_suffix ? strlen(service_suffix) : 0; @@ -663,53 +661,52 @@ void gitno_connection_data_free_ptrs(gitno_connection_data *d) int gitno_extract_url_parts( char **host, char **port, + char **path, char **username, char **password, const char *url, const char *default_port) { - char *colon, *slash, *at; - - /* - * ==> [user[:pass]@]hostname.tld[:port]/resource - */ + struct http_parser_url u = {0}; + const char *_host, *_port, *_path, *_userinfo; - /* Check for user and maybe password. Note that this deviates from RFC-1738 - * in that it allows non-encoded colons in the password field. */ - at = strchr(url, '@'); - if (at) { - colon = strchr(url, ':'); - if (colon && colon < at) { - /* user:pass */ - *username = git__substrdup(url, colon-url); - *password = git__substrdup(colon+1, at-colon-1); - GITERR_CHECK_ALLOC(*password); - } else { - *username = git__substrdup(url, at-url); - } - GITERR_CHECK_ALLOC(*username); - url = at + 1; + if (http_parser_parse_url(url, strlen(url), false, &u)) { + giterr_set(GITERR_NET, "Malformed URL '%s'", url); + return GIT_EINVALIDSPEC; } - /* Validate URL format. Colons shouldn't be in the path part. */ - slash = strchr(url, '/'); - colon = strchr(url, ':'); - if (!slash || - (colon && (slash < colon))) { - giterr_set(GITERR_NET, "Malformed URL: %s", url); - return GIT_EINVALIDSPEC; + _host = url+u.field_data[UF_HOST].off; + _port = url+u.field_data[UF_PORT].off; + _path = url+u.field_data[UF_PATH].off; + _userinfo = url+u.field_data[UF_USERINFO].off; + + if (u.field_data[UF_HOST].len) { + *host = git__substrdup(_host, u.field_data[UF_HOST].len); + GITERR_CHECK_ALLOC(*host); } - /* Check for hostname and maybe port */ - if (colon) { - *host = git__substrdup(url, colon-url); - *port = git__substrdup(colon+1, slash-colon-1); - } else { - *host = git__substrdup(url, slash-url); + if (u.field_data[UF_PORT].len) + *port = git__substrdup(_port, u.field_data[UF_PORT].len); + else *port = git__strdup(default_port); - } - GITERR_CHECK_ALLOC(*host); GITERR_CHECK_ALLOC(*port); + if (u.field_data[UF_PATH].len) { + *path = git__substrdup(_path, u.field_data[UF_PATH].len); + GITERR_CHECK_ALLOC(*path); + } + + if (u.field_data[UF_USERINFO].len) { + const char *colon = strchr(_userinfo, ':'); + if (colon && (colon - _userinfo) < u.field_data[UF_USERINFO].len) { + *username = git__substrdup(_userinfo, colon - _userinfo); + *password = git__substrdup(colon+1, u.field_data[UF_USERINFO].len - (colon+1-_userinfo)); + GITERR_CHECK_ALLOC(*password); + } else { + *username = git__substrdup(_userinfo, u.field_data[UF_USERINFO].len); + } + GITERR_CHECK_ALLOC(*username); + } + return 0; } |