@@ -136,14 +136,14 @@ static void credential_format(struct credential *c, struct strbuf *out)
return;
strbuf_addf(out, "%s://", c->protocol);
if (c->username && *c->username) {
- strbuf_add_percentencode(out, c->username);
+ strbuf_add_percentencode(out, c->username, STRBUF_ENCODE_SLASH);
strbuf_addch(out, '@');
}
if (c->host)
strbuf_addstr(out, c->host);
if (c->path) {
strbuf_addch(out, '/');
- strbuf_add_percentencode(out, c->path);
+ strbuf_add_percentencode(out, c->path, 0);
}
}
@@ -479,15 +479,17 @@ void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
}
}
-#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:/?#[]@!$&'()*+,;="
+#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:?#[]@!$&'()*+,;="
-void strbuf_add_percentencode(struct strbuf *dst, const char *src)
+void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
{
size_t i, len = strlen(src);
for (i = 0; i < len; i++) {
unsigned char ch = src[i];
- if (ch <= 0x1F || ch >= 0x7F || strchr(URL_UNSAFE_CHARS, ch))
+ if (ch <= 0x1F || ch >= 0x7F ||
+ (ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
+ strchr(URL_UNSAFE_CHARS, ch))
strbuf_addf(dst, "%%%02X", (unsigned char)ch);
else
strbuf_addch(dst, ch);
@@ -378,11 +378,16 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb,
*/
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
+#define STRBUF_ENCODE_SLASH 1
+
/**
* Append the contents of a string to a strbuf, percent-encoding any characters
* that are needed to be encoded for a URL.
+ *
+ * If STRBUF_ENCODE_SLASH is set in flags, percent-encode slashes. Otherwise,
+ * slashes are not percent-encoded.
*/
-void strbuf_add_percentencode(struct strbuf *dst, const char *src);
+void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags);
/**
* Append the given byte size as a human-readable string (i.e. 12.23 KiB,
@@ -366,6 +366,51 @@ test_expect_success 'match percent-encoded values' '
EOF
'
+test_expect_success 'match percent-encoded UTF-8 values in path' '
+ test_config credential.https://example.com.useHttpPath true &&
+ test_config credential.https://example.com/perú.git.helper "$HELPER" &&
+ check fill <<-\EOF
+ url=https://example.com/per%C3%BA.git
+ --
+ protocol=https
+ host=example.com
+ path=perú.git
+ username=foo
+ password=bar
+ --
+ EOF
+'
+
+test_expect_success 'match percent-encoded values in username' '
+ test_config credential.https://user%2fname@example.com/foo/bar.git.helper "$HELPER" &&
+ check fill <<-\EOF
+ url=https://user%2fname@example.com/foo/bar.git
+ --
+ protocol=https
+ host=example.com
+ username=foo
+ password=bar
+ --
+ EOF
+'
+
+test_expect_success 'fetch with multiple path components' '
+ test_unconfig credential.helper &&
+ test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
+ check fill <<-\EOF
+ url=https://example.com/foo/repo.git
+ --
+ protocol=https
+ host=example.com
+ username=foo
+ password=bar
+ --
+ verbatim: get
+ verbatim: protocol=https
+ verbatim: host=example.com
+ EOF
+'
+
test_expect_success 'pull username from config' '
test_config credential.https://example.com.username foo &&
check fill <<-\EOF