Skip to content

Commit 9181e4b

Browse files
authored
Merge pull request libgit2#5339 from josharian/issue-5321
netops: handle intact query parameters in service_suffix removal
2 parents 258188d + 7142964 commit 9181e4b

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

src/netops.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,25 +171,46 @@ int gitno_connection_data_handle_redirect(
171171

172172
/* Remove the service suffix if it was given to us */
173173
if (service_suffix) {
174+
/*
175+
* Some servers strip the query parameters from the Location header
176+
* when sending a redirect. Others leave it in place.
177+
* Check for both, starting with the stripped case first,
178+
* since it appears to be more common.
179+
*/
174180
const char *service_query = strchr(service_suffix, '?');
181+
size_t full_suffix_len = strlen(service_suffix);
175182
size_t suffix_len = service_query ?
176-
(size_t)(service_query - service_suffix) : strlen(service_suffix);
183+
(size_t)(service_query - service_suffix) : full_suffix_len;
177184
size_t path_len = strlen(url->path);
185+
ssize_t truncate = -1;
178186

187+
/* Check for a redirect without query parameters, like "/newloc/info/refs" */
179188
if (suffix_len && path_len >= suffix_len) {
180189
size_t suffix_offset = path_len - suffix_len;
181190

182191
if (git__strncmp(url->path + suffix_offset, service_suffix, suffix_len) == 0 &&
183192
(!service_query || git__strcmp(url->query, service_query + 1) == 0)) {
184-
/* Ensure we leave a minimum of '/' as the path */
185-
if (suffix_offset == 0)
186-
suffix_offset++;
193+
truncate = suffix_offset;
194+
}
195+
}
187196

188-
url->path[suffix_offset] = '\0';
197+
/*
198+
* If we haven't already found where to truncate to remove the suffix,
199+
* check for a redirect with query parameters,
200+
* like "/newloc/info/refs?service=git-upload-pack"
201+
*/
202+
if (truncate == -1 && git__suffixcmp(url->path, service_suffix) == 0) {
203+
truncate = path_len - full_suffix_len;
204+
}
189205

190-
git__free(url->query);
191-
url->query = NULL;
192-
}
206+
if (truncate >= 0) {
207+
/* Ensure we leave a minimum of '/' as the path */
208+
if (truncate == 0)
209+
truncate++;
210+
url->path[truncate] = '\0';
211+
212+
git__free(url->query);
213+
url->query = NULL;
193214
}
194215
}
195216

tests/network/redirect.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,19 @@ void test_network_redirect__redirect_relative_ssl(void)
111111
cl_assert_equal_p(conndata.username, NULL);
112112
cl_assert_equal_p(conndata.password, NULL);
113113
}
114+
115+
void test_network_redirect__service_query_no_query_params_in_location(void)
116+
{
117+
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
118+
cl_git_pass(gitno_connection_data_handle_redirect(&conndata,
119+
"/baz/info/refs", "/info/refs?service=git-upload-pack"));
120+
cl_assert_equal_s(conndata.path, "/baz");
121+
}
122+
123+
void test_network_redirect__service_query_with_query_params_in_location(void)
124+
{
125+
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
126+
cl_git_pass(gitno_connection_data_handle_redirect(&conndata,
127+
"/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
128+
cl_assert_equal_s(conndata.path, "/baz");
129+
}

0 commit comments

Comments
 (0)