Commit 342e55ac by Edward Thomson

url: optionally allow off-site redirects

In redirect application logic, (optionally) allow off-site redirects.
parent c104a565
......@@ -315,6 +315,7 @@ static void remove_service_suffix(
int git_net_url_apply_redirect(
git_net_url *url,
const char *redirect_location,
bool allow_offsite,
const char *service_suffix)
{
git_net_url tmp = GIT_NET_URL_INIT;
......@@ -339,8 +340,8 @@ int git_net_url_apply_redirect(
/* Validate that this is a legal redirection */
if (original->scheme &&
strcmp(original->scheme, tmp.scheme) != 0 &&
strcmp(tmp.scheme, "https") != 0) {
strcmp(original->scheme, tmp.scheme) != 0 &&
strcmp(tmp.scheme, "https") != 0) {
git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
original->scheme, tmp.scheme);
......@@ -349,6 +350,7 @@ int git_net_url_apply_redirect(
}
if (original->host &&
!allow_offsite &&
git__strcasecmp(original->host, tmp.host) != 0) {
git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
original->host, tmp.host);
......
......@@ -46,6 +46,7 @@ extern bool git_net_url_is_ipv6(git_net_url *url);
extern int git_net_url_apply_redirect(
git_net_url *url,
const char *redirect_location,
bool allow_offsite,
const char *service_suffix);
/** Swaps the contents of one URL for another. */
......
......@@ -233,7 +233,7 @@ static int handle_response(
return -1;
}
if (git_net_url_apply_redirect(&transport->server.url, response->location, stream->service->url) < 0) {
if (git_net_url_apply_redirect(&transport->server.url, response->location, false, stream->service->url) < 0) {
return -1;
}
......
......@@ -1190,7 +1190,7 @@ replay:
if (!git__prefixcmp_icase(location8, prefix_https)) {
/* Upgrade to secure connection; disconnect and start over */
if (git_net_url_apply_redirect(&t->server.url, location8, s->service_url) < 0) {
if (git_net_url_apply_redirect(&t->server.url, location8, false, s->service_url) < 0) {
git__free(location8);
return -1;
}
......
......@@ -17,9 +17,9 @@ void test_network_url_redirect__cleanup(void)
void test_network_url_redirect__redirect_http(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"http://example.com/foo/bar/baz"));
"http://example.com/foo/bar/baz"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"http://example.com/foo/bar/baz", "bar/baz"));
"http://example.com/foo/bar/baz", false, "bar/baz"));
cl_assert_equal_s(conndata.scheme, "http");
cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "80");
......@@ -31,9 +31,9 @@ void test_network_url_redirect__redirect_http(void)
void test_network_url_redirect__redirect_ssl(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://example.com/foo/bar/baz"));
"https://example.com/foo/bar/baz"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"https://example.com/foo/bar/baz", "bar/baz"));
"https://example.com/foo/bar/baz", false, "bar/baz"));
cl_assert_equal_s(conndata.scheme, "https");
cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "443");
......@@ -45,9 +45,9 @@ void test_network_url_redirect__redirect_ssl(void)
void test_network_url_redirect__redirect_leaves_root_path(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://example.com/foo/bar/baz"));
"https://example.com/foo/bar/baz"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"https://example.com/foo/bar/baz", "/foo/bar/baz"));
"https://example.com/foo/bar/baz", false, "/foo/bar/baz"));
cl_assert_equal_s(conndata.scheme, "https");
cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "443");
......@@ -59,9 +59,9 @@ void test_network_url_redirect__redirect_leaves_root_path(void)
void test_network_url_redirect__redirect_encoded_username_password(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", false, "bar/baz"));
cl_assert_equal_s(conndata.scheme, "https");
cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "443");
......@@ -70,27 +70,42 @@ void test_network_url_redirect__redirect_encoded_username_password(void)
cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
}
void test_network_url_redirect__redirect_cross_host_allowed(void)
{
cl_git_pass(git_net_url_parse(&conndata,
"https://bar.com/bar/baz"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"https://foo.com/bar/baz", true, NULL));
cl_assert_equal_s(conndata.scheme, "https");
cl_assert_equal_s(conndata.host, "foo.com");
cl_assert_equal_s(conndata.port, "443");
cl_assert_equal_s(conndata.path, "/bar/baz");
cl_assert_equal_p(conndata.username, NULL);
cl_assert_equal_p(conndata.password, NULL);
}
void test_network_url_redirect__redirect_cross_host_denied(void)
{
cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
cl_git_pass(git_net_url_parse(&conndata,
"https://bar.com/bar/baz"));
cl_git_fail_with(git_net_url_apply_redirect(&conndata,
"https://foo.com/bar/baz", NULL),
-1);
"https://foo.com/bar/baz", false, NULL), -1);
}
void test_network_url_redirect__redirect_http_downgrade_denied(void)
{
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
cl_git_pass(git_net_url_parse(&conndata,
"https://foo.com/bar/baz"));
cl_git_fail_with(git_net_url_apply_redirect(&conndata,
"http://foo.com/bar/baz", NULL),
-1);
"http://foo.com/bar/baz", true, NULL), -1);
}
void test_network_url_redirect__redirect_relative(void)
{
cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
cl_git_pass(git_net_url_parse(&conndata,
"http://foo.com/bar/baz/biff"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"/zap/baz/biff?bam", NULL));
"/zap/baz/biff?bam", true, NULL));
cl_assert_equal_s(conndata.scheme, "http");
cl_assert_equal_s(conndata.host, "foo.com");
cl_assert_equal_s(conndata.port, "80");
......@@ -101,9 +116,10 @@ void test_network_url_redirect__redirect_relative(void)
void test_network_url_redirect__redirect_relative_ssl(void)
{
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
cl_git_pass(git_net_url_parse(&conndata,
"https://foo.com/bar/baz/biff"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"/zap/baz/biff?bam", NULL));
"/zap/baz/biff?bam", true, NULL));
cl_assert_equal_s(conndata.scheme, "https");
cl_assert_equal_s(conndata.host, "foo.com");
cl_assert_equal_s(conndata.port, "443");
......@@ -114,16 +130,18 @@ void test_network_url_redirect__redirect_relative_ssl(void)
void test_network_url_redirect__service_query_no_query_params_in_location(void)
{
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
cl_git_pass(git_net_url_parse(&conndata,
"https://foo.com/bar/info/refs?service=git-upload-pack"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"/baz/info/refs", "/info/refs?service=git-upload-pack"));
"/baz/info/refs", true, "/info/refs?service=git-upload-pack"));
cl_assert_equal_s(conndata.path, "/baz");
}
void test_network_url_redirect__service_query_with_query_params_in_location(void)
{
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
cl_git_pass(git_net_url_parse(&conndata,
"https://foo.com/bar/info/refs?service=git-upload-pack"));
cl_git_pass(git_net_url_apply_redirect(&conndata,
"/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
"/baz/info/refs?service=git-upload-pack", true, "/info/refs?service=git-upload-pack"));
cl_assert_equal_s(conndata.path, "/baz");
}
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