Commit e6e399ab by Edward Thomson

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.
parent e6f1931a
...@@ -73,6 +73,11 @@ typedef struct { ...@@ -73,6 +73,11 @@ typedef struct {
gitno_connection_data gitserver_data; gitno_connection_data gitserver_data;
bool connected; bool connected;
/* Proxy */
git_proxy_options proxy;
char *proxy_url;
gitno_connection_data proxy_data;
/* Parser structures */ /* Parser structures */
http_parser parser; http_parser parser;
http_parser_settings settings; http_parser_settings settings;
...@@ -203,7 +208,16 @@ static int gen_request( ...@@ -203,7 +208,16 @@ static int gen_request(
const char *path = t->gitserver_data.path ? t->gitserver_data.path : "/"; const char *path = t->gitserver_data.path ? t->gitserver_data.path : "/";
size_t i; 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_buf_puts(buf, "User-Agent: ");
git_http__user_agent(buf); git_http__user_agent(buf);
...@@ -560,42 +574,56 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len) ...@@ -560,42 +574,56 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len)
return 0; return 0;
} }
static int apply_proxy_config(http_subtransport *t) static int apply_proxy_config_to_stream(http_subtransport *t)
{ {
int error; /* Only set the proxy configuration on the curl stream. */
git_proxy_t proxy_type; if (!git_stream_supports_proxy(t->gitserver_stream) ||
t->proxy.type == GIT_PROXY_NONE)
if (!git_stream_supports_proxy(t->gitserver_stream))
return 0; return 0;
proxy_type = t->owner->proxy.type; return git_stream_set_proxy(t->gitserver_stream, &t->proxy);
}
static int load_proxy_config(http_subtransport *t)
{
int error;
if (proxy_type == GIT_PROXY_NONE) switch (t->owner->proxy.type) {
case GIT_PROXY_NONE:
return 0; return 0;
if (proxy_type == GIT_PROXY_AUTO) { case GIT_PROXY_AUTO:
char *url; git__free(t->proxy_url);
git_proxy_options opts = GIT_PROXY_OPTIONS_INIT; t->proxy_url = NULL;
if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->gitserver_data.use_ssl, &url)) < 0) 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, &t->proxy_url)) < 0)
return error; return error;
opts.credentials = t->owner->proxy.credentials; t->proxy.type = GIT_PROXY_SPECIFIED;
opts.certificate_check = t->owner->proxy.certificate_check; t->proxy.url = t->proxy_url;
opts.payload = t->owner->proxy.payload; t->proxy.credentials = t->owner->proxy.credentials;
opts.type = GIT_PROXY_SPECIFIED; t->proxy.certificate_check = t->owner->proxy.certificate_check;
opts.url = url; t->proxy.payload = t->owner->proxy.payload;
error = git_stream_set_proxy(t->gitserver_stream, &opts); break;
git__free(url);
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) static int http_connect(http_subtransport *t)
{ {
gitno_connection_data *connection_data;
int error; int error;
if (t->connected && if (t->connected &&
...@@ -610,25 +638,27 @@ static int http_connect(http_subtransport *t) ...@@ -610,25 +638,27 @@ static int http_connect(http_subtransport *t)
t->connected = 0; t->connected = 0;
} }
if (t->gitserver_data.use_ssl) { connection_data = (t->proxy.type == GIT_PROXY_SPECIFIED) ?
error = git_tls_stream_new(&t->gitserver_stream, &t->proxy_data : &t->gitserver_data;
t->gitserver_data.host, t->gitserver_data.port);
} else {
#ifdef GIT_CURL #ifdef GIT_CURL
error = git_curl_stream_new(&t->gitserver_stream, error = git_curl_stream_new(&t->gitserver_stream,
t->gitserver_data.host, t->gitserver_data.port); t->gitserver_data.host, t->gitserver_data.port);
#else #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, error = git_socket_stream_new(&t->gitserver_stream,
t->gitserver_data.host, t->gitserver_data.port); connection_data->host, connection_data->port);
#endif #endif
}
if (error < 0) if (error < 0)
return error; return error;
GITERR_CHECK_VERSION(t->gitserver_stream, GIT_STREAM_VERSION, "git_stream"); 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; return error;
error = git_stream_connect(t->gitserver_stream); error = git_stream_connect(t->gitserver_stream);
...@@ -1020,13 +1050,24 @@ static int http_action( ...@@ -1020,13 +1050,24 @@ static int http_action(
http_subtransport *t = (http_subtransport *)subtransport; http_subtransport *t = (http_subtransport *)subtransport;
int ret; int ret;
if (!stream) assert(stream);
return -1;
/*
* 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) && 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; 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) if ((ret = http_connect(t)) < 0)
return ret; return ret;
...@@ -1084,6 +1125,12 @@ static int http_close(git_smart_subtransport *subtransport) ...@@ -1084,6 +1125,12 @@ static int http_close(git_smart_subtransport *subtransport)
gitno_connection_data_free_ptrs(&t->gitserver_data); gitno_connection_data_free_ptrs(&t->gitserver_data);
memset(&t->gitserver_data, 0x0, sizeof(gitno_connection_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; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment