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 <patrick.steinhardt@elego.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jan 31, 2017 at 10:01 UTC
af99049ca92f5a5d16d8cce9727b859ac5c9ee00
3 files changed
+69
-25
t/t1300-repo-config.sh
+33
@@ -1177,6 +1177,39 @@ test_expect_success 'urlmatch' '
1177
test_cmp expect actual
1178
'
1179
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://user@example.com/"]
1187
+ cookieFile = /tmp/user.txt
1188
+ [http "https://averylonguser@example.com/"]
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://user@example.com/ >actual &&
1206
+ test_cmp expect actual &&
1207
+
1208
+ echo http.cookiefile /tmp/subdirectory.txt >expect &&
1209
+ git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual &&
1210
+ test_cmp expect actual
1211
+'
1212
+
1213
# good section hygiene
1214
test_expect_failure 'unsetting the last key in a section removes header' '
1215
cat >.git/config <<-\EOF &&
urlmatch.c
+34
-24
@@ -426,7 +426,7 @@ static size_t url_match_prefix(const char *url,
426
427
static int match_urls(const struct url_info *url,
428
const struct url_info *url_prefix,
429
- int *exactusermatch)
429
+ struct urlmatch_item *match)
430
{
431
/*
432
* 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,
445
* contained a user name or false if url_prefix did not have a
446
* user name. If there is no match *exactusermatch is left untouched.
447
*/
448
- int usermatched = 0;
449
- int pathmatchlen;
448
+ char usermatched = 0;
449
+ size_t pathmatchlen;
450
451
if (!url || !url_prefix || !url->url || !url_prefix->url)
452
return 0;
@@ -483,22 +483,38 @@ static int match_urls(const struct url_info *url,
483
url->url + url->path_off,
484
url_prefix->url + url_prefix->path_off,
485
url_prefix->url_len - url_prefix->path_off);
486
+ if (!pathmatchlen)
487
+ return 0; /* paths do not match */
488
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;
508
}
509
510
int urlmatch_config_entry(const char *var, const char *value, void *cb)
511
{
512
struct string_list_item *item;
513
struct urlmatch_config *collect = cb;
496
- struct urlmatch_item *matched;
514
+ struct urlmatch_item matched = {0};
515
struct url_info *url = &collect->url;
516
const char *key, *dot;
517
struct strbuf synthkey = STRBUF_INIT;
500
- size_t matched_len = 0;
501
- int user_matched = 0;
518
int retval;
519
520
if (!skip_prefix(var, collect->section, &key) || *(key++) != '.') {
@@ -516,9 +532,9 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
532
free(config_url);
533
if (!norm_url)
534
return 0;
519
- matched_len = match_urls(url, &norm_info, &user_matched);
535
+ retval = match_urls(url, &norm_info, &matched);
536
free(norm_url);
521
- if (!matched_len)
537
+ if (!retval)
538
return 0;
539
key = dot + 1;
540
}
@@ -528,24 +544,18 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
544
545
item = string_list_insert(&collect->vars, key);
546
if (!item->util) {
531
- matched = xcalloc(1, sizeof(*matched));
532
- item->util = matched;
547
+ item->util = xcalloc(1, sizeof(matched));
548
} 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
+ */
554
return 0;
555
/* Otherwise, replace it with this one. */
556
}
557
547
- matched->matched_len = matched_len;
548
- matched->user_matched = user_matched;
558
+ memcpy(item->util, &matched, sizeof(matched));
559
strbuf_addstr(&synthkey, collect->section);
560
strbuf_addch(&synthkey, '.');
561
strbuf_addstr(&synthkey, key);
urlmatch.h
+2
-1
@@ -34,7 +34,8 @@ struct url_info {
34
extern char *url_normalize(const char *, struct url_info *);
35
36
struct urlmatch_item {
37
- size_t matched_len;
37
+ size_t hostmatch_len;
38
+ size_t pathmatch_len;
39
char user_matched;
40
};
41