diff options
author | Ben Straub <bs@github.com> | 2013-10-03 06:20:20 -0700 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2013-10-03 06:20:20 -0700 |
commit | fc1f7d4f15ecc3f42dbde7fc0a30933cb89152bc (patch) | |
tree | 1446cb018eb05571b4eff101ceae937688e83a1d /src/netops.c | |
parent | de8fe729efd350ae5cb1ef25ffb08f92c6f706b9 (diff) | |
parent | ab1368766240cfe861729642abe1cddd01c0203e (diff) | |
download | libgit2-fc1f7d4f15ecc3f42dbde7fc0a30933cb89152bc.tar.gz |
Merge branch 'development' into blame
Conflicts:
include/git2.h
Diffstat (limited to 'src/netops.c')
-rw-r--r-- | src/netops.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/netops.c b/src/netops.c index c1e74546f..7a61ef820 100644 --- a/src/netops.c +++ b/src/netops.c @@ -573,6 +573,93 @@ int gitno_select_in(gitno_buffer *buf, long int sec, long int usec) return select((int)buf->socket->socket + 1, &fds, NULL, NULL, &tv); } +static const char *prefix_http = "http://"; +static const char *prefix_https = "https://"; + +int gitno_connection_data_from_url( + gitno_connection_data *data, + const char *url, + const char *service_suffix) +{ + int error = -1; + const char *default_port = NULL; + char *original_host = NULL; + + /* service_suffix is optional */ + assert(data && url); + + /* Save these for comparison later */ + original_host = data->host; + data->host = NULL; + gitno_connection_data_free_ptrs(data); + + if (!git__prefixcmp(url, prefix_http)) { + url = 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); + default_port = "443"; + data->use_ssl = true; + } + + if (url[0] == '/') + default_port = data->use_ssl ? "443" : "80"; + + if (!default_port) { + giterr_set(GITERR_NET, "Unrecognized URL prefix"); + goto cleanup; + } + + error = gitno_extract_url_parts( + &data->host, &data->port, &data->user, &data->pass, + url, default_port); + + if (url[0] == '/') { + /* Relative redirect; reuse original host name and port */ + git__free(data->host); + data->host = original_host; + original_host = NULL; + } + + if (!error) { + const char *path = strchr(url, '/'); + size_t pathlen = strlen(path); + size_t suffixlen = service_suffix ? strlen(service_suffix) : 0; + + if (suffixlen && + !memcmp(path + pathlen - suffixlen, service_suffix, suffixlen)) + data->path = git__strndup(path, pathlen - suffixlen); + else + data->path = git__strdup(path); + + /* Check for errors in the resulting data */ + if (original_host && url[0] != '/' && strcmp(original_host, data->host)) { + giterr_set(GITERR_NET, "Cross host redirect not allowed"); + error = -1; + } + } + +cleanup: + if (original_host) git__free(original_host); + return error; +} + +void gitno_connection_data_free_ptrs(gitno_connection_data *d) +{ + git__free(d->host); d->host = NULL; + git__free(d->port); d->port = NULL; + git__free(d->path); d->path = NULL; + git__free(d->user); d->user = NULL; + git__free(d->pass); d->pass = NULL; +} + int gitno_extract_url_parts( char **host, char **port, |