summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/netops.c6
-rw-r--r--src/transports/http.c177
2 files changed, 104 insertions, 79 deletions
diff --git a/src/netops.c b/src/netops.c
index 6777ee51b..c1e74546f 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -581,17 +581,13 @@ int gitno_extract_url_parts(
const char *url,
const char *default_port)
{
- char *colon, *dblslash, *slash, *at, *end;
+ char *colon, *slash, *at, *end;
const char *start;
/*
- *
* ==> [user[:pass]@]hostname.tld[:port]/resource
*/
- dblslash = strstr(url, "://");
- if (dblslash) url = dblslash+3;
-
colon = strchr(url, ':');
slash = strchr(url, '/');
at = strchr(url, '@');
diff --git a/src/transports/http.c b/src/transports/http.c
index ab42a3c08..aca8c5d8b 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -59,7 +59,7 @@ typedef struct {
git_smart_subtransport parent;
transport_smart *owner;
gitno_socket socket;
- const char *path;
+ char *path;
char *host;
char *port;
char *user_from_url;
@@ -125,15 +125,9 @@ static int gen_request(
size_t content_length)
{
http_subtransport *t = OWNING_SUBTRANSPORT(s);
+ const char *path = t->path ? t->path : "/";
- if (!t->path)
- t->path = "/";
-
- /* If we were redirected, make sure to respect that here */
- if (s->redirect_url)
- git_buf_printf(buf, "%s %s HTTP/1.1\r\n", s->verb, s->redirect_url);
- else
- git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, t->path, s->service_url);
+ git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, path, s->service_url);
git_buf_puts(buf, "User-Agent: git/1.0 (libgit2 " LIBGIT2_VERSION ")\r\n");
git_buf_printf(buf, "Host: %s\r\n", t->host);
@@ -209,7 +203,7 @@ static int on_header_ready(http_subtransport *t)
}
else if (!strcasecmp("Location", git_buf_cstr(name))) {
if (!t->location) {
- t->location= git__strdup(git_buf_cstr(value));
+ t->location = git__strdup(git_buf_cstr(value));
GITERR_CHECK_ALLOC(t->location);
}
}
@@ -255,6 +249,93 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
return 0;
}
+static void free_connection_data(http_subtransport *t)
+{
+ if (t->host) {
+ git__free(t->host);
+ t->host = NULL;
+ }
+
+ if (t->port) {
+ git__free(t->port);
+ t->port = NULL;
+ }
+
+ if (t->user_from_url) {
+ git__free(t->user_from_url);
+ t->user_from_url = NULL;
+ }
+
+ if (t->pass_from_url) {
+ git__free(t->pass_from_url);
+ t->pass_from_url = NULL;
+ }
+
+ if (t->path) {
+ git__free(t->path);
+ t->path = NULL;
+ }
+}
+
+static int set_connection_data_from_url(
+ http_subtransport *t, const char *url, const char *service_suffix)
+{
+ int error = 0;
+ const char *default_port = NULL;
+ char *original_host = NULL;
+
+ if (!git__prefixcmp(url, prefix_http)) {
+ url = url + strlen(prefix_http);
+ default_port = "80";
+ }
+
+ if (!git__prefixcmp(url, prefix_https)) {
+ url += strlen(prefix_https);
+ default_port = "443";
+ t->use_ssl = 1;
+ }
+
+ if (!default_port) {
+ giterr_set(GITERR_NET, "Unrecognized URL prefix");
+ return -1;
+ }
+
+ /* preserve original host name for checking */
+ original_host = t->host;
+ t->host = NULL;
+
+ free_connection_data(t);
+
+ error = gitno_extract_url_parts(
+ &t->host, &t->port, &t->user_from_url, &t->pass_from_url,
+ url, default_port);
+
+ 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))
+ t->path = git__strndup(path, pathlen - suffixlen);
+ else
+ t->path = git__strdup(path);
+
+ /* Allow '/'-led urls, or a change of protocol */
+ if (original_host != NULL) {
+ if (strcmp(original_host, t->host) && t->location[0] != '/') {
+ giterr_set(GITERR_NET, "Only same-host redirects are supported");
+ error = -1;
+ }
+
+ git__free(original_host);
+ }
+ }
+
+ return error;
+}
+
+
static int on_headers_complete(http_parser *parser)
{
parser_context *ctx = (parser_context *) parser->data;
@@ -303,28 +384,13 @@ static int on_headers_complete(http_parser *parser)
parser->status_code == 307) &&
t->location) {
- char *host=NULL, *port=NULL, *user=NULL, *pass=NULL;
-
if (s->redirect_count >= 7) {
giterr_set(GITERR_NET, "Too many redirects");
return t->parse_error = PARSE_ERROR_GENERIC;
}
- if (gitno_extract_url_parts(&host, &port, &user, &pass, t->location, "") < 0) {
- giterr_set(GITERR_NET, "Redirect to unparseable url '%s'", t->location);
+ if (set_connection_data_from_url(t, t->location, s->service_url) < 0)
return t->parse_error = PARSE_ERROR_GENERIC;
- }
- git__free(port);
- git__free(user);
- git__free(pass);
-
- /* Allow '/'-led urls, or a change of protocol */
- if (strcmp(t->host, host) && t->location[0] != '/') {
- git__free(host);
- giterr_set(GITERR_NET, "Only same-host redirects are supported");
- return t->parse_error = PARSE_ERROR_GENERIC;
- }
- git__free(host);
/* Set the redirect URL on the stream. This is a transfer of
* ownership of the memory. */
@@ -835,50 +901,31 @@ static int http_action(
git_smart_service_t action)
{
http_subtransport *t = (http_subtransport *)subtransport;
- const char *default_port = NULL;
int ret;
if (!stream)
return -1;
if (!t->host || !t->port || !t->path) {
- if (!git__prefixcmp(url, prefix_http)) {
- url = url + strlen(prefix_http);
- default_port = "80";
- }
-
- if (!git__prefixcmp(url, prefix_https)) {
- url += strlen(prefix_https);
- default_port = "443";
- t->use_ssl = 1;
- }
-
- if (!default_port)
- return -1;
-
- if ((ret = gitno_extract_url_parts(&t->host, &t->port,
- &t->user_from_url, &t->pass_from_url, url, default_port)) < 0)
+ if ((ret = set_connection_data_from_url(t, url, NULL)) < 0)
return ret;
-
- t->path = strchr(url, '/');
}
if (http_connect(t) < 0)
return -1;
- switch (action)
- {
- case GIT_SERVICE_UPLOADPACK_LS:
- return http_uploadpack_ls(t, stream);
+ switch (action) {
+ case GIT_SERVICE_UPLOADPACK_LS:
+ return http_uploadpack_ls(t, stream);
- case GIT_SERVICE_UPLOADPACK:
- return http_uploadpack(t, stream);
+ case GIT_SERVICE_UPLOADPACK:
+ return http_uploadpack(t, stream);
- case GIT_SERVICE_RECEIVEPACK_LS:
- return http_receivepack_ls(t, stream);
+ case GIT_SERVICE_RECEIVEPACK_LS:
+ return http_receivepack_ls(t, stream);
- case GIT_SERVICE_RECEIVEPACK:
- return http_receivepack(t, stream);
+ case GIT_SERVICE_RECEIVEPACK:
+ return http_receivepack(t, stream);
}
*stream = NULL;
@@ -906,25 +953,7 @@ static int http_close(git_smart_subtransport *subtransport)
t->url_cred = NULL;
}
- if (t->host) {
- git__free(t->host);
- t->host = NULL;
- }
-
- if (t->port) {
- git__free(t->port);
- t->port = NULL;
- }
-
- if (t->user_from_url) {
- git__free(t->user_from_url);
- t->user_from_url = NULL;
- }
-
- if (t->pass_from_url) {
- git__free(t->pass_from_url);
- t->pass_from_url = NULL;
- }
+ free_connection_data(t);
return 0;
}