summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-10-22 09:49:54 +0100
committerEdward Thomson <ethomson@edwardthomson.com>2018-11-28 15:10:02 +0000
commite6e399ab367f300f76903099462b8e06846fccc3 (patch)
treeef520bf63dd10113740fd1d3acd9df757656eafd /src
parente6f1931aae5a2349b6eeb11968f7e6a54df75397 (diff)
downloadlibgit2-e6e399ab367f300f76903099462b8e06846fccc3.tar.gz
http transport: use HTTP proxies when requested
The HTTP transport should understand how to apply proxies when configured with `GIT_PROXY_SPECIFIED` and `GIT_PROXY_SPECIFIED`. When a proxy is configured, the HTTP transport will now connect to the proxy (instead of directly to the git server), and will request the properly-formed URL of the git server endpoint.
Diffstat (limited to 'src')
-rw-r--r--src/transports/http.c113
1 files changed, 80 insertions, 33 deletions
diff --git a/src/transports/http.c b/src/transports/http.c
index 82b938807..7df139b07 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -73,6 +73,11 @@ typedef struct {
gitno_connection_data gitserver_data;
bool connected;
+ /* Proxy */
+ git_proxy_options proxy;
+ char *proxy_url;
+ gitno_connection_data proxy_data;
+
/* Parser structures */
http_parser parser;
http_parser_settings settings;
@@ -203,7 +208,16 @@ static int gen_request(
const char *path = t->gitserver_data.path ? t->gitserver_data.path : "/";
size_t i;
- git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, path, s->service_url);
+ if (t->proxy.type == GIT_PROXY_SPECIFIED)
+ git_buf_printf(buf, "%s %s://%s:%s%s%s HTTP/1.1\r\n",
+ s->verb,
+ t->gitserver_data.use_ssl ? "https" : "http",
+ t->gitserver_data.host,
+ t->gitserver_data.port,
+ path, s->service_url);
+ else
+ 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_http__user_agent(buf);
@@ -560,42 +574,56 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len)
return 0;
}
-static int apply_proxy_config(http_subtransport *t)
+static int apply_proxy_config_to_stream(http_subtransport *t)
{
- int error;
- git_proxy_t proxy_type;
-
- if (!git_stream_supports_proxy(t->gitserver_stream))
+ /* Only set the proxy configuration on the curl stream. */
+ if (!git_stream_supports_proxy(t->gitserver_stream) ||
+ t->proxy.type == GIT_PROXY_NONE)
return 0;
- proxy_type = t->owner->proxy.type;
+ return git_stream_set_proxy(t->gitserver_stream, &t->proxy);
+}
- if (proxy_type == GIT_PROXY_NONE)
+static int load_proxy_config(http_subtransport *t)
+{
+ int error;
+
+ switch (t->owner->proxy.type) {
+ case GIT_PROXY_NONE:
return 0;
- if (proxy_type == GIT_PROXY_AUTO) {
- char *url;
- git_proxy_options opts = GIT_PROXY_OPTIONS_INIT;
+ case GIT_PROXY_AUTO:
+ git__free(t->proxy_url);
+ t->proxy_url = NULL;
+
+ git_proxy_init_options(&t->proxy, GIT_PROXY_OPTIONS_VERSION);
- if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->gitserver_data.use_ssl, &url)) < 0)
+ if ((error = git_remote__get_http_proxy(t->owner->owner,
+ !!t->gitserver_data.use_ssl, &t->proxy_url)) < 0)
return error;
- opts.credentials = t->owner->proxy.credentials;
- opts.certificate_check = t->owner->proxy.certificate_check;
- opts.payload = t->owner->proxy.payload;
- opts.type = GIT_PROXY_SPECIFIED;
- opts.url = url;
- error = git_stream_set_proxy(t->gitserver_stream, &opts);
- git__free(url);
+ t->proxy.type = GIT_PROXY_SPECIFIED;
+ t->proxy.url = t->proxy_url;
+ t->proxy.credentials = t->owner->proxy.credentials;
+ t->proxy.certificate_check = t->owner->proxy.certificate_check;
+ t->proxy.payload = t->owner->proxy.payload;
+ break;
- return error;
+ case GIT_PROXY_SPECIFIED:
+ memcpy(&t->proxy, &t->owner->proxy, sizeof(git_proxy_options));
+ break;
+
+ default:
+ assert(0);
+ return -1;
}
- return git_stream_set_proxy(t->gitserver_stream, &t->owner->proxy);
+ return gitno_connection_data_from_url(&t->proxy_data, t->proxy.url, NULL);
}
static int http_connect(http_subtransport *t)
{
+ gitno_connection_data *connection_data;
int error;
if (t->connected &&
@@ -610,25 +638,27 @@ static int http_connect(http_subtransport *t)
t->connected = 0;
}
- if (t->gitserver_data.use_ssl) {
- error = git_tls_stream_new(&t->gitserver_stream,
- t->gitserver_data.host, t->gitserver_data.port);
- } else {
+ connection_data = (t->proxy.type == GIT_PROXY_SPECIFIED) ?
+ &t->proxy_data : &t->gitserver_data;
+
#ifdef GIT_CURL
- error = git_curl_stream_new(&t->gitserver_stream,
- t->gitserver_data.host, t->gitserver_data.port);
+ error = git_curl_stream_new(&t->gitserver_stream,
+ t->gitserver_data.host, t->gitserver_data.port);
#else
+ if (connection_data->use_ssl)
+ error = git_tls_stream_new(&t->gitserver_stream,
+ connection_data->host, connection_data->port);
+ else
error = git_socket_stream_new(&t->gitserver_stream,
- t->gitserver_data.host, t->gitserver_data.port);
+ connection_data->host, connection_data->port);
#endif
- }
if (error < 0)
return error;
GITERR_CHECK_VERSION(t->gitserver_stream, GIT_STREAM_VERSION, "git_stream");
- if ((error = apply_proxy_config(t)) < 0)
+ if ((error = apply_proxy_config_to_stream(t)) < 0)
return error;
error = git_stream_connect(t->gitserver_stream);
@@ -1020,11 +1050,22 @@ static int http_action(
http_subtransport *t = (http_subtransport *)subtransport;
int ret;
- if (!stream)
- return -1;
+ assert(stream);
+ /*
+ * If we've seen a redirect then preserve the location that we've
+ * been given. This is important to continue authorization against
+ * the redirect target, not the user-given source; the endpoint may
+ * have redirected us from HTTP->HTTPS and is using an auth mechanism
+ * that would be insecure in plaintext (eg, HTTP Basic).
+ */
if ((!t->gitserver_data.host || !t->gitserver_data.port || !t->gitserver_data.path) &&
- (ret = gitno_connection_data_from_url(&t->gitserver_data, url, NULL)) < 0)
+ (ret = gitno_connection_data_from_url(&t->gitserver_data, url, NULL)) < 0)
+ return ret;
+
+ assert(t->gitserver_data.host && t->gitserver_data.port && t->gitserver_data.path);
+
+ if ((ret = load_proxy_config(t)) < 0)
return ret;
if ((ret = http_connect(t)) < 0)
@@ -1084,6 +1125,12 @@ static int http_close(git_smart_subtransport *subtransport)
gitno_connection_data_free_ptrs(&t->gitserver_data);
memset(&t->gitserver_data, 0x0, sizeof(gitno_connection_data));
+ gitno_connection_data_free_ptrs(&t->proxy_data);
+ memset(&t->proxy_data, 0x0, sizeof(gitno_connection_data));
+
+ git__free(t->proxy_url);
+ t->proxy_url = NULL;
+
return 0;
}