Skip to content

Commit af99049

Browse files
Patrick Steinhardtgitster
authored andcommitted
urlmatch: include host in urlmatch ranking
In order to be able to rank positive matches by `urlmatch`, we inspect the path length and user part to decide whether a match is better than another match. As all other parts are matched exactly between both URLs, this is the correct thing to do right now. In the future, though, we want to introduce wild cards for the domain part. When doing this, it does not make sense anymore to only compare the path lengths. Instead, we also want to compare the domain lengths to determine which of both URLs matches the host part more closely. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3ec6e6e commit af99049

File tree

3 files changed

+69
-25
lines changed

3 files changed

+69
-25
lines changed

t/t1300-repo-config.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,39 @@ test_expect_success 'urlmatch' '
11771177
test_cmp expect actual
11781178
'
11791179

1180+
test_expect_success 'urlmatch favors more specific URLs' '
1181+
cat >.git/config <<-\EOF &&
1182+
[http "https://example.com/"]
1183+
cookieFile = /tmp/root.txt
1184+
[http "https://example.com/subdirectory"]
1185+
cookieFile = /tmp/subdirectory.txt
1186+
[http "https://[email protected]/"]
1187+
cookieFile = /tmp/user.txt
1188+
[http "https://[email protected]/"]
1189+
cookieFile = /tmp/averylonguser.txt
1190+
EOF
1191+
1192+
echo http.cookiefile /tmp/root.txt >expect &&
1193+
git config --get-urlmatch HTTP https://example.com >actual &&
1194+
test_cmp expect actual &&
1195+
1196+
echo http.cookiefile /tmp/subdirectory.txt >expect &&
1197+
git config --get-urlmatch HTTP https://example.com/subdirectory >actual &&
1198+
test_cmp expect actual &&
1199+
1200+
echo http.cookiefile /tmp/subdirectory.txt >expect &&
1201+
git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual &&
1202+
test_cmp expect actual &&
1203+
1204+
echo http.cookiefile /tmp/user.txt >expect &&
1205+
git config --get-urlmatch HTTP https://[email protected]/ >actual &&
1206+
test_cmp expect actual &&
1207+
1208+
echo http.cookiefile /tmp/subdirectory.txt >expect &&
1209+
git config --get-urlmatch HTTP https://[email protected]/subdirectory >actual &&
1210+
test_cmp expect actual
1211+
'
1212+
11801213
# good section hygiene
11811214
test_expect_failure 'unsetting the last key in a section removes header' '
11821215
cat >.git/config <<-\EOF &&

urlmatch.c

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ static size_t url_match_prefix(const char *url,
426426

427427
static int match_urls(const struct url_info *url,
428428
const struct url_info *url_prefix,
429-
int *exactusermatch)
429+
struct urlmatch_item *match)
430430
{
431431
/*
432432
* url_prefix matches url if the scheme, host and port of url_prefix
@@ -445,8 +445,8 @@ static int match_urls(const struct url_info *url,
445445
* contained a user name or false if url_prefix did not have a
446446
* user name. If there is no match *exactusermatch is left untouched.
447447
*/
448-
int usermatched = 0;
449-
int pathmatchlen;
448+
char usermatched = 0;
449+
size_t pathmatchlen;
450450

451451
if (!url || !url_prefix || !url->url || !url_prefix->url)
452452
return 0;
@@ -483,22 +483,38 @@ static int match_urls(const struct url_info *url,
483483
url->url + url->path_off,
484484
url_prefix->url + url_prefix->path_off,
485485
url_prefix->url_len - url_prefix->path_off);
486+
if (!pathmatchlen)
487+
return 0; /* paths do not match */
486488

487-
if (pathmatchlen && exactusermatch)
488-
*exactusermatch = usermatched;
489-
return pathmatchlen;
489+
if (match) {
490+
match->hostmatch_len = url_prefix->host_len;
491+
match->pathmatch_len = pathmatchlen;
492+
match->user_matched = usermatched;
493+
}
494+
495+
return 1;
496+
}
497+
498+
static int cmp_matches(const struct urlmatch_item *a,
499+
const struct urlmatch_item *b)
500+
{
501+
if (a->hostmatch_len != b->hostmatch_len)
502+
return a->hostmatch_len < b->hostmatch_len ? -1 : 1;
503+
if (a->pathmatch_len != b->pathmatch_len)
504+
return a->pathmatch_len < b->pathmatch_len ? -1 : 1;
505+
if (a->user_matched != b->user_matched)
506+
return b->user_matched ? -1 : 1;
507+
return 0;
490508
}
491509

492510
int urlmatch_config_entry(const char *var, const char *value, void *cb)
493511
{
494512
struct string_list_item *item;
495513
struct urlmatch_config *collect = cb;
496-
struct urlmatch_item *matched;
514+
struct urlmatch_item matched = {0};
497515
struct url_info *url = &collect->url;
498516
const char *key, *dot;
499517
struct strbuf synthkey = STRBUF_INIT;
500-
size_t matched_len = 0;
501-
int user_matched = 0;
502518
int retval;
503519

504520
if (!skip_prefix(var, collect->section, &key) || *(key++) != '.') {
@@ -516,9 +532,9 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
516532
free(config_url);
517533
if (!norm_url)
518534
return 0;
519-
matched_len = match_urls(url, &norm_info, &user_matched);
535+
retval = match_urls(url, &norm_info, &matched);
520536
free(norm_url);
521-
if (!matched_len)
537+
if (!retval)
522538
return 0;
523539
key = dot + 1;
524540
}
@@ -528,24 +544,18 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
528544

529545
item = string_list_insert(&collect->vars, key);
530546
if (!item->util) {
531-
matched = xcalloc(1, sizeof(*matched));
532-
item->util = matched;
547+
item->util = xcalloc(1, sizeof(matched));
533548
} else {
534-
matched = item->util;
535-
/*
536-
* Is our match shorter? Is our match the same
537-
* length, and without user while the current
538-
* candidate is with user? Then we cannot use it.
539-
*/
540-
if (matched_len < matched->matched_len ||
541-
((matched_len == matched->matched_len) &&
542-
(!user_matched && matched->user_matched)))
549+
if (cmp_matches(&matched, item->util) < 0)
550+
/*
551+
* Our match is worse than the old one,
552+
* we cannot use it.
553+
*/
543554
return 0;
544555
/* Otherwise, replace it with this one. */
545556
}
546557

547-
matched->matched_len = matched_len;
548-
matched->user_matched = user_matched;
558+
memcpy(item->util, &matched, sizeof(matched));
549559
strbuf_addstr(&synthkey, collect->section);
550560
strbuf_addch(&synthkey, '.');
551561
strbuf_addstr(&synthkey, key);

urlmatch.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ struct url_info {
3434
extern char *url_normalize(const char *, struct url_info *);
3535

3636
struct urlmatch_item {
37-
size_t matched_len;
37+
size_t hostmatch_len;
38+
size_t pathmatch_len;
3839
char user_matched;
3940
};
4041

0 commit comments

Comments
 (0)