Skip to content

Commit 342e55a

Browse files
committed
url: optionally allow off-site redirects
In redirect application logic, (optionally) allow off-site redirects.
1 parent c104a56 commit 342e55a

File tree

5 files changed

+47
-26
lines changed

5 files changed

+47
-26
lines changed

src/net.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ static void remove_service_suffix(
315315
int git_net_url_apply_redirect(
316316
git_net_url *url,
317317
const char *redirect_location,
318+
bool allow_offsite,
318319
const char *service_suffix)
319320
{
320321
git_net_url tmp = GIT_NET_URL_INIT;
@@ -339,8 +340,8 @@ int git_net_url_apply_redirect(
339340
/* Validate that this is a legal redirection */
340341

341342
if (original->scheme &&
342-
strcmp(original->scheme, tmp.scheme) != 0 &&
343-
strcmp(tmp.scheme, "https") != 0) {
343+
strcmp(original->scheme, tmp.scheme) != 0 &&
344+
strcmp(tmp.scheme, "https") != 0) {
344345
git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
345346
original->scheme, tmp.scheme);
346347

@@ -349,6 +350,7 @@ int git_net_url_apply_redirect(
349350
}
350351

351352
if (original->host &&
353+
!allow_offsite &&
352354
git__strcasecmp(original->host, tmp.host) != 0) {
353355
git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
354356
original->host, tmp.host);

src/net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ extern bool git_net_url_is_ipv6(git_net_url *url);
4646
extern int git_net_url_apply_redirect(
4747
git_net_url *url,
4848
const char *redirect_location,
49+
bool allow_offsite,
4950
const char *service_suffix);
5051

5152
/** Swaps the contents of one URL for another. */

src/transports/http.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ static int handle_response(
233233
return -1;
234234
}
235235

236-
if (git_net_url_apply_redirect(&transport->server.url, response->location, stream->service->url) < 0) {
236+
if (git_net_url_apply_redirect(&transport->server.url, response->location, false, stream->service->url) < 0) {
237237
return -1;
238238
}
239239

src/transports/winhttp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1190,7 +1190,7 @@ static int winhttp_stream_read(
11901190

11911191
if (!git__prefixcmp_icase(location8, prefix_https)) {
11921192
/* Upgrade to secure connection; disconnect and start over */
1193-
if (git_net_url_apply_redirect(&t->server.url, location8, s->service_url) < 0) {
1193+
if (git_net_url_apply_redirect(&t->server.url, location8, false, s->service_url) < 0) {
11941194
git__free(location8);
11951195
return -1;
11961196
}

tests/network/url/redirect.c

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ void test_network_url_redirect__cleanup(void)
1717
void test_network_url_redirect__redirect_http(void)
1818
{
1919
cl_git_pass(git_net_url_parse(&conndata,
20-
"http://example.com/foo/bar/baz"));
20+
"http://example.com/foo/bar/baz"));
2121
cl_git_pass(git_net_url_apply_redirect(&conndata,
22-
"http://example.com/foo/bar/baz", "bar/baz"));
22+
"http://example.com/foo/bar/baz", false, "bar/baz"));
2323
cl_assert_equal_s(conndata.scheme, "http");
2424
cl_assert_equal_s(conndata.host, "example.com");
2525
cl_assert_equal_s(conndata.port, "80");
@@ -31,9 +31,9 @@ void test_network_url_redirect__redirect_http(void)
3131
void test_network_url_redirect__redirect_ssl(void)
3232
{
3333
cl_git_pass(git_net_url_parse(&conndata,
34-
"https://example.com/foo/bar/baz"));
34+
"https://example.com/foo/bar/baz"));
3535
cl_git_pass(git_net_url_apply_redirect(&conndata,
36-
"https://example.com/foo/bar/baz", "bar/baz"));
36+
"https://example.com/foo/bar/baz", false, "bar/baz"));
3737
cl_assert_equal_s(conndata.scheme, "https");
3838
cl_assert_equal_s(conndata.host, "example.com");
3939
cl_assert_equal_s(conndata.port, "443");
@@ -45,9 +45,9 @@ void test_network_url_redirect__redirect_ssl(void)
4545
void test_network_url_redirect__redirect_leaves_root_path(void)
4646
{
4747
cl_git_pass(git_net_url_parse(&conndata,
48-
"https://example.com/foo/bar/baz"));
48+
"https://example.com/foo/bar/baz"));
4949
cl_git_pass(git_net_url_apply_redirect(&conndata,
50-
"https://example.com/foo/bar/baz", "/foo/bar/baz"));
50+
"https://example.com/foo/bar/baz", false, "/foo/bar/baz"));
5151
cl_assert_equal_s(conndata.scheme, "https");
5252
cl_assert_equal_s(conndata.host, "example.com");
5353
cl_assert_equal_s(conndata.port, "443");
@@ -59,9 +59,9 @@ void test_network_url_redirect__redirect_leaves_root_path(void)
5959
void test_network_url_redirect__redirect_encoded_username_password(void)
6060
{
6161
cl_git_pass(git_net_url_parse(&conndata,
62-
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
62+
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
6363
cl_git_pass(git_net_url_apply_redirect(&conndata,
64-
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
64+
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", false, "bar/baz"));
6565
cl_assert_equal_s(conndata.scheme, "https");
6666
cl_assert_equal_s(conndata.host, "example.com");
6767
cl_assert_equal_s(conndata.port, "443");
@@ -70,27 +70,42 @@ void test_network_url_redirect__redirect_encoded_username_password(void)
7070
cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
7171
}
7272

73+
void test_network_url_redirect__redirect_cross_host_allowed(void)
74+
{
75+
cl_git_pass(git_net_url_parse(&conndata,
76+
"https://bar.com/bar/baz"));
77+
cl_git_pass(git_net_url_apply_redirect(&conndata,
78+
"https://foo.com/bar/baz", true, NULL));
79+
cl_assert_equal_s(conndata.scheme, "https");
80+
cl_assert_equal_s(conndata.host, "foo.com");
81+
cl_assert_equal_s(conndata.port, "443");
82+
cl_assert_equal_s(conndata.path, "/bar/baz");
83+
cl_assert_equal_p(conndata.username, NULL);
84+
cl_assert_equal_p(conndata.password, NULL);
85+
}
86+
7387
void test_network_url_redirect__redirect_cross_host_denied(void)
7488
{
75-
cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
89+
cl_git_pass(git_net_url_parse(&conndata,
90+
"https://bar.com/bar/baz"));
7691
cl_git_fail_with(git_net_url_apply_redirect(&conndata,
77-
"https://foo.com/bar/baz", NULL),
78-
-1);
92+
"https://foo.com/bar/baz", false, NULL), -1);
7993
}
8094

8195
void test_network_url_redirect__redirect_http_downgrade_denied(void)
8296
{
83-
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
97+
cl_git_pass(git_net_url_parse(&conndata,
98+
"https://foo.com/bar/baz"));
8499
cl_git_fail_with(git_net_url_apply_redirect(&conndata,
85-
"http://foo.com/bar/baz", NULL),
86-
-1);
100+
"http://foo.com/bar/baz", true, NULL), -1);
87101
}
88102

89103
void test_network_url_redirect__redirect_relative(void)
90104
{
91-
cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
105+
cl_git_pass(git_net_url_parse(&conndata,
106+
"http://foo.com/bar/baz/biff"));
92107
cl_git_pass(git_net_url_apply_redirect(&conndata,
93-
"/zap/baz/biff?bam", NULL));
108+
"/zap/baz/biff?bam", true, NULL));
94109
cl_assert_equal_s(conndata.scheme, "http");
95110
cl_assert_equal_s(conndata.host, "foo.com");
96111
cl_assert_equal_s(conndata.port, "80");
@@ -101,9 +116,10 @@ void test_network_url_redirect__redirect_relative(void)
101116

102117
void test_network_url_redirect__redirect_relative_ssl(void)
103118
{
104-
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
119+
cl_git_pass(git_net_url_parse(&conndata,
120+
"https://foo.com/bar/baz/biff"));
105121
cl_git_pass(git_net_url_apply_redirect(&conndata,
106-
"/zap/baz/biff?bam", NULL));
122+
"/zap/baz/biff?bam", true, NULL));
107123
cl_assert_equal_s(conndata.scheme, "https");
108124
cl_assert_equal_s(conndata.host, "foo.com");
109125
cl_assert_equal_s(conndata.port, "443");
@@ -114,16 +130,18 @@ void test_network_url_redirect__redirect_relative_ssl(void)
114130

115131
void test_network_url_redirect__service_query_no_query_params_in_location(void)
116132
{
117-
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
133+
cl_git_pass(git_net_url_parse(&conndata,
134+
"https://foo.com/bar/info/refs?service=git-upload-pack"));
118135
cl_git_pass(git_net_url_apply_redirect(&conndata,
119-
"/baz/info/refs", "/info/refs?service=git-upload-pack"));
136+
"/baz/info/refs", true, "/info/refs?service=git-upload-pack"));
120137
cl_assert_equal_s(conndata.path, "/baz");
121138
}
122139

123140
void test_network_url_redirect__service_query_with_query_params_in_location(void)
124141
{
125-
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
142+
cl_git_pass(git_net_url_parse(&conndata,
143+
"https://foo.com/bar/info/refs?service=git-upload-pack"));
126144
cl_git_pass(git_net_url_apply_redirect(&conndata,
127-
"/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
145+
"/baz/info/refs?service=git-upload-pack", true, "/info/refs?service=git-upload-pack"));
128146
cl_assert_equal_s(conndata.path, "/baz");
129147
}

0 commit comments

Comments
 (0)