Skip to content

Commit e6e399a

Browse files
committed
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.
1 parent e6f1931 commit e6e399a

File tree

1 file changed

+80
-33
lines changed

1 file changed

+80
-33
lines changed

src/transports/http.c

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ typedef struct {
7373
gitno_connection_data gitserver_data;
7474
bool connected;
7575

76+
/* Proxy */
77+
git_proxy_options proxy;
78+
char *proxy_url;
79+
gitno_connection_data proxy_data;
80+
7681
/* Parser structures */
7782
http_parser parser;
7883
http_parser_settings settings;
@@ -203,7 +208,16 @@ static int gen_request(
203208
const char *path = t->gitserver_data.path ? t->gitserver_data.path : "/";
204209
size_t i;
205210

206-
git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, path, s->service_url);
211+
if (t->proxy.type == GIT_PROXY_SPECIFIED)
212+
git_buf_printf(buf, "%s %s://%s:%s%s%s HTTP/1.1\r\n",
213+
s->verb,
214+
t->gitserver_data.use_ssl ? "https" : "http",
215+
t->gitserver_data.host,
216+
t->gitserver_data.port,
217+
path, s->service_url);
218+
else
219+
git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n",
220+
s->verb, path, s->service_url);
207221

208222
git_buf_puts(buf, "User-Agent: ");
209223
git_http__user_agent(buf);
@@ -560,42 +574,56 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len)
560574
return 0;
561575
}
562576

563-
static int apply_proxy_config(http_subtransport *t)
577+
static int apply_proxy_config_to_stream(http_subtransport *t)
564578
{
565-
int error;
566-
git_proxy_t proxy_type;
567-
568-
if (!git_stream_supports_proxy(t->gitserver_stream))
579+
/* Only set the proxy configuration on the curl stream. */
580+
if (!git_stream_supports_proxy(t->gitserver_stream) ||
581+
t->proxy.type == GIT_PROXY_NONE)
569582
return 0;
570583

571-
proxy_type = t->owner->proxy.type;
584+
return git_stream_set_proxy(t->gitserver_stream, &t->proxy);
585+
}
572586

573-
if (proxy_type == GIT_PROXY_NONE)
587+
static int load_proxy_config(http_subtransport *t)
588+
{
589+
int error;
590+
591+
switch (t->owner->proxy.type) {
592+
case GIT_PROXY_NONE:
574593
return 0;
575594

576-
if (proxy_type == GIT_PROXY_AUTO) {
577-
char *url;
578-
git_proxy_options opts = GIT_PROXY_OPTIONS_INIT;
595+
case GIT_PROXY_AUTO:
596+
git__free(t->proxy_url);
597+
t->proxy_url = NULL;
598+
599+
git_proxy_init_options(&t->proxy, GIT_PROXY_OPTIONS_VERSION);
579600

580-
if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->gitserver_data.use_ssl, &url)) < 0)
601+
if ((error = git_remote__get_http_proxy(t->owner->owner,
602+
!!t->gitserver_data.use_ssl, &t->proxy_url)) < 0)
581603
return error;
582604

583-
opts.credentials = t->owner->proxy.credentials;
584-
opts.certificate_check = t->owner->proxy.certificate_check;
585-
opts.payload = t->owner->proxy.payload;
586-
opts.type = GIT_PROXY_SPECIFIED;
587-
opts.url = url;
588-
error = git_stream_set_proxy(t->gitserver_stream, &opts);
589-
git__free(url);
605+
t->proxy.type = GIT_PROXY_SPECIFIED;
606+
t->proxy.url = t->proxy_url;
607+
t->proxy.credentials = t->owner->proxy.credentials;
608+
t->proxy.certificate_check = t->owner->proxy.certificate_check;
609+
t->proxy.payload = t->owner->proxy.payload;
610+
break;
590611

591-
return error;
612+
case GIT_PROXY_SPECIFIED:
613+
memcpy(&t->proxy, &t->owner->proxy, sizeof(git_proxy_options));
614+
break;
615+
616+
default:
617+
assert(0);
618+
return -1;
592619
}
593620

594-
return git_stream_set_proxy(t->gitserver_stream, &t->owner->proxy);
621+
return gitno_connection_data_from_url(&t->proxy_data, t->proxy.url, NULL);
595622
}
596623

597624
static int http_connect(http_subtransport *t)
598625
{
626+
gitno_connection_data *connection_data;
599627
int error;
600628

601629
if (t->connected &&
@@ -610,25 +638,27 @@ static int http_connect(http_subtransport *t)
610638
t->connected = 0;
611639
}
612640

613-
if (t->gitserver_data.use_ssl) {
614-
error = git_tls_stream_new(&t->gitserver_stream,
615-
t->gitserver_data.host, t->gitserver_data.port);
616-
} else {
641+
connection_data = (t->proxy.type == GIT_PROXY_SPECIFIED) ?
642+
&t->proxy_data : &t->gitserver_data;
643+
617644
#ifdef GIT_CURL
618-
error = git_curl_stream_new(&t->gitserver_stream,
619-
t->gitserver_data.host, t->gitserver_data.port);
645+
error = git_curl_stream_new(&t->gitserver_stream,
646+
t->gitserver_data.host, t->gitserver_data.port);
620647
#else
648+
if (connection_data->use_ssl)
649+
error = git_tls_stream_new(&t->gitserver_stream,
650+
connection_data->host, connection_data->port);
651+
else
621652
error = git_socket_stream_new(&t->gitserver_stream,
622-
t->gitserver_data.host, t->gitserver_data.port);
653+
connection_data->host, connection_data->port);
623654
#endif
624-
}
625655

626656
if (error < 0)
627657
return error;
628658

629659
GITERR_CHECK_VERSION(t->gitserver_stream, GIT_STREAM_VERSION, "git_stream");
630660

631-
if ((error = apply_proxy_config(t)) < 0)
661+
if ((error = apply_proxy_config_to_stream(t)) < 0)
632662
return error;
633663

634664
error = git_stream_connect(t->gitserver_stream);
@@ -1020,11 +1050,22 @@ static int http_action(
10201050
http_subtransport *t = (http_subtransport *)subtransport;
10211051
int ret;
10221052

1023-
if (!stream)
1024-
return -1;
1053+
assert(stream);
10251054

1055+
/*
1056+
* If we've seen a redirect then preserve the location that we've
1057+
* been given. This is important to continue authorization against
1058+
* the redirect target, not the user-given source; the endpoint may
1059+
* have redirected us from HTTP->HTTPS and is using an auth mechanism
1060+
* that would be insecure in plaintext (eg, HTTP Basic).
1061+
*/
10261062
if ((!t->gitserver_data.host || !t->gitserver_data.port || !t->gitserver_data.path) &&
1027-
(ret = gitno_connection_data_from_url(&t->gitserver_data, url, NULL)) < 0)
1063+
(ret = gitno_connection_data_from_url(&t->gitserver_data, url, NULL)) < 0)
1064+
return ret;
1065+
1066+
assert(t->gitserver_data.host && t->gitserver_data.port && t->gitserver_data.path);
1067+
1068+
if ((ret = load_proxy_config(t)) < 0)
10281069
return ret;
10291070

10301071
if ((ret = http_connect(t)) < 0)
@@ -1084,6 +1125,12 @@ static int http_close(git_smart_subtransport *subtransport)
10841125
gitno_connection_data_free_ptrs(&t->gitserver_data);
10851126
memset(&t->gitserver_data, 0x0, sizeof(gitno_connection_data));
10861127

1128+
gitno_connection_data_free_ptrs(&t->proxy_data);
1129+
memset(&t->proxy_data, 0x0, sizeof(gitno_connection_data));
1130+
1131+
git__free(t->proxy_url);
1132+
t->proxy_url = NULL;
1133+
10871134
return 0;
10881135
}
10891136

0 commit comments

Comments
 (0)