@matheusbsbs / matheus-bagliano / commits / b44d0118ac
Fork 0

credential: fix matching URLs with multiple levels in path

46fd7b3900 ("credential: allow wildcard patterns when matching config", 2020-02-20) introduced support for matching credential helpers using urlmatch. In doing so, it introduced code to percent-encode the paths we get from the credential helper so that they could be effectively matched by the urlmatch code. Unfortunately, that code had a bug: it percent-encoded the slashes in the path, resulting in any URL path that contained multiple levels (i.e., a directory component) not matching. We are currently the only caller of the percent-encoding code and could simply change it not to encode slashes. However, we still want to encode slashes in the username component, so we need to have both behaviors available. So instead, let's add a flag to control encoding slashes, which is the behavior we want here, and use it when calling the code in this case. Add a test for credential helper URLs using multiple slashes in the path, which our test suite previously lacked, as well as one ensuring that we handle usernames with slashes gracefully. Since we're testing other percent-encoding handling, let's add one for non-ASCII UTF-8 characters as well. Reported-by: Ilya Tretyakov <it@it3xl.ru> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Apr 27, 2020 at 01:18 UTC b44d0118ac5074215ece7ae2bb86ad0713f70674
4 files changed +58 -6
credential.c
+2 -2
@@ -131,14 +131,14 @@ static void credential_format(struct credential *c, struct strbuf *out)
131 return;
132 strbuf_addf(out, "%s://", c->protocol);
133 if (c->username && *c->username) {
134 - strbuf_add_percentencode(out, c->username);
134 + strbuf_add_percentencode(out, c->username, STRBUF_ENCODE_SLASH);
135 strbuf_addch(out, '@');
136 }
137 if (c->host)
138 strbuf_addstr(out, c->host);
139 if (c->path) {
140 strbuf_addch(out, '/');
141 - strbuf_add_percentencode(out, c->path);
141 + strbuf_add_percentencode(out, c->path, 0);
142 }
143 }
144
strbuf.c
+5 -3
@@ -479,15 +479,17 @@ void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
479 }
480 }
481
482 -#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:/?#[]@!$&'()*+,;="
482 +#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:?#[]@!$&'()*+,;="
483
484 -void strbuf_add_percentencode(struct strbuf *dst, const char *src)
484 +void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
485 {
486 size_t i, len = strlen(src);
487
488 for (i = 0; i < len; i++) {
489 unsigned char ch = src[i];
490 - if (ch <= 0x1F || ch >= 0x7F || strchr(URL_UNSAFE_CHARS, ch))
490 + if (ch <= 0x1F || ch >= 0x7F ||
491 + (ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
492 + strchr(URL_UNSAFE_CHARS, ch))
493 strbuf_addf(dst, "%%%02X", (unsigned char)ch);
494 else
495 strbuf_addch(dst, ch);
strbuf.h
+6 -1
@@ -366,11 +366,16 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb,
366 */
367 void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
368
369 +#define STRBUF_ENCODE_SLASH 1
370 +
371 /**
372 * Append the contents of a string to a strbuf, percent-encoding any characters
373 * that are needed to be encoded for a URL.
374 + *
375 + * If STRBUF_ENCODE_SLASH is set in flags, percent-encode slashes. Otherwise,
376 + * slashes are not percent-encoded.
377 */
373 -void strbuf_add_percentencode(struct strbuf *dst, const char *src);
378 +void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags);
379
380 /**
381 * Append the given byte size as a human-readable string (i.e. 12.23 KiB,
t/t0300-credentials.sh
+45
@@ -291,6 +291,51 @@ test_expect_success 'match percent-encoded values' '
291 EOF
292 '
293
294 +test_expect_success 'match percent-encoded UTF-8 values in path' '
295 + test_config credential.https://example.com.useHttpPath true &&
296 + test_config credential.https://example.com/perú.git.helper "$HELPER" &&
297 + check fill <<-\EOF
298 + url=https://example.com/per%C3%BA.git
299 + --
300 + protocol=https
301 + host=example.com
302 + path=perú.git
303 + username=foo
304 + password=bar
305 + --
306 + EOF
307 +'
308 +
309 +test_expect_success 'match percent-encoded values in username' '
310 + test_config credential.https://user%2fname@example.com/foo/bar.git.helper "$HELPER" &&
311 + check fill <<-\EOF
312 + url=https://user%2fname@example.com/foo/bar.git
313 + --
314 + protocol=https
315 + host=example.com
316 + username=foo
317 + password=bar
318 + --
319 + EOF
320 +'
321 +
322 +test_expect_success 'fetch with multiple path components' '
323 + test_unconfig credential.helper &&
324 + test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
325 + check fill <<-\EOF
326 + url=https://example.com/foo/repo.git
327 + --
328 + protocol=https
329 + host=example.com
330 + username=foo
331 + password=bar
332 + --
333 + verbatim: get
334 + verbatim: protocol=https
335 + verbatim: host=example.com
336 + EOF
337 +'
338 +
339 test_expect_success 'pull username from config' '
340 test_config credential.https://example.com.username foo &&
341 check fill <<-\EOF