@@ -63,7 +63,50 @@ static int append_normalized_escapes(struct strbuf *buf,
63
63
return 1 ;
64
64
}
65
65
66
- char * url_normalize (const char * url , struct url_info * out_info )
66
+ static const char * end_of_token (const char * s , int c , size_t n )
67
+ {
68
+ const char * next = memchr (s , c , n );
69
+ if (!next )
70
+ next = s + n ;
71
+ return next ;
72
+ }
73
+
74
+ static int match_host (const struct url_info * url_info ,
75
+ const struct url_info * pattern_info )
76
+ {
77
+ const char * url = url_info -> url + url_info -> host_off ;
78
+ const char * pat = pattern_info -> url + pattern_info -> host_off ;
79
+ int url_len = url_info -> host_len ;
80
+ int pat_len = pattern_info -> host_len ;
81
+
82
+ while (url_len && pat_len ) {
83
+ const char * url_next = end_of_token (url , '.' , url_len );
84
+ const char * pat_next = end_of_token (pat , '.' , pat_len );
85
+
86
+ if (pat_next == pat + 1 && pat [0 ] == '*' )
87
+ /* wildcard matches anything */
88
+ ;
89
+ else if ((pat_next - pat ) == (url_next - url ) &&
90
+ !memcmp (url , pat , url_next - url ))
91
+ /* the components are the same */
92
+ ;
93
+ else
94
+ return 0 ; /* found an unmatch */
95
+
96
+ if (url_next < url + url_len )
97
+ url_next ++ ;
98
+ url_len -= url_next - url ;
99
+ url = url_next ;
100
+ if (pat_next < pat + pat_len )
101
+ pat_next ++ ;
102
+ pat_len -= pat_next - pat ;
103
+ pat = pat_next ;
104
+ }
105
+
106
+ return (!url_len && !pat_len );
107
+ }
108
+
109
+ static char * url_normalize_1 (const char * url , struct url_info * out_info , char allow_globs )
67
110
{
68
111
/*
69
112
* Normalize NUL-terminated url using the following rules:
@@ -104,7 +147,7 @@ char *url_normalize(const char *url, struct url_info *out_info)
104
147
struct strbuf norm ;
105
148
size_t spanned ;
106
149
size_t scheme_len , user_off = 0 , user_len = 0 , passwd_off = 0 , passwd_len = 0 ;
107
- size_t host_off = 0 , host_len = 0 , port_len = 0 , path_off , path_len , result_len ;
150
+ size_t host_off = 0 , host_len = 0 , port_off = 0 , port_len = 0 , path_off , path_len , result_len ;
108
151
const char * slash_ptr , * at_ptr , * colon_ptr , * path_start ;
109
152
char * result ;
110
153
@@ -191,7 +234,12 @@ char *url_normalize(const char *url, struct url_info *out_info)
191
234
strbuf_release (& norm );
192
235
return NULL ;
193
236
}
194
- spanned = strspn (url , URL_HOST_CHARS );
237
+
238
+ if (allow_globs )
239
+ spanned = strspn (url , URL_HOST_CHARS "*" );
240
+ else
241
+ spanned = strspn (url , URL_HOST_CHARS );
242
+
195
243
if (spanned < colon_ptr - url ) {
196
244
/* Host name has invalid characters */
197
245
if (out_info ) {
@@ -258,14 +306,15 @@ char *url_normalize(const char *url, struct url_info *out_info)
258
306
return NULL ;
259
307
}
260
308
strbuf_addch (& norm , ':' );
309
+ port_off = norm .len ;
261
310
strbuf_add (& norm , url , slash_ptr - url );
262
311
port_len = slash_ptr - url ;
263
312
}
264
313
url_len -= slash_ptr - colon_ptr ;
265
314
url = slash_ptr ;
266
315
}
267
316
if (host_off )
268
- host_len = norm .len - host_off ;
317
+ host_len = norm .len - host_off - ( port_len ? port_len + 1 : 0 ) ;
269
318
270
319
271
320
/*
@@ -373,13 +422,19 @@ char *url_normalize(const char *url, struct url_info *out_info)
373
422
out_info -> passwd_len = passwd_len ;
374
423
out_info -> host_off = host_off ;
375
424
out_info -> host_len = host_len ;
425
+ out_info -> port_off = port_off ;
376
426
out_info -> port_len = port_len ;
377
427
out_info -> path_off = path_off ;
378
428
out_info -> path_len = path_len ;
379
429
}
380
430
return result ;
381
431
}
382
432
433
+ char * url_normalize (const char * url , struct url_info * out_info )
434
+ {
435
+ return url_normalize_1 (url , out_info , 0 );
436
+ }
437
+
383
438
static size_t url_match_prefix (const char * url ,
384
439
const char * url_prefix ,
385
440
size_t url_prefix_len )
@@ -414,7 +469,7 @@ static size_t url_match_prefix(const char *url,
414
469
415
470
static int match_urls (const struct url_info * url ,
416
471
const struct url_info * url_prefix ,
417
- int * exactusermatch )
472
+ struct urlmatch_item * match )
418
473
{
419
474
/*
420
475
* url_prefix matches url if the scheme, host and port of url_prefix
@@ -433,8 +488,8 @@ static int match_urls(const struct url_info *url,
433
488
* contained a user name or false if url_prefix did not have a
434
489
* user name. If there is no match *exactusermatch is left untouched.
435
490
*/
436
- int usermatched = 0 ;
437
- int pathmatchlen ;
491
+ char usermatched = 0 ;
492
+ size_t pathmatchlen ;
438
493
439
494
if (!url || !url_prefix || !url -> url || !url_prefix -> url )
440
495
return 0 ;
@@ -454,33 +509,53 @@ static int match_urls(const struct url_info *url,
454
509
usermatched = 1 ;
455
510
}
456
511
457
- /* check the host and port */
458
- if (url_prefix -> host_len != url -> host_len ||
459
- strncmp (url -> url + url -> host_off ,
460
- url_prefix -> url + url_prefix -> host_off , url -> host_len ))
461
- return 0 ; /* host names and/or ports do not match */
512
+ /* check the host */
513
+ if (!match_host (url , url_prefix ))
514
+ return 0 ; /* host names do not match */
515
+
516
+ /* check the port */
517
+ if (url_prefix -> port_len != url -> port_len ||
518
+ strncmp (url -> url + url -> port_off ,
519
+ url_prefix -> url + url_prefix -> port_off , url -> port_len ))
520
+ return 0 ; /* ports do not match */
462
521
463
522
/* check the path */
464
523
pathmatchlen = url_match_prefix (
465
524
url -> url + url -> path_off ,
466
525
url_prefix -> url + url_prefix -> path_off ,
467
526
url_prefix -> url_len - url_prefix -> path_off );
527
+ if (!pathmatchlen )
528
+ return 0 ; /* paths do not match */
468
529
469
- if (pathmatchlen && exactusermatch )
470
- * exactusermatch = usermatched ;
471
- return pathmatchlen ;
530
+ if (match ) {
531
+ match -> hostmatch_len = url_prefix -> host_len ;
532
+ match -> pathmatch_len = pathmatchlen ;
533
+ match -> user_matched = usermatched ;
534
+ }
535
+
536
+ return 1 ;
537
+ }
538
+
539
+ static int cmp_matches (const struct urlmatch_item * a ,
540
+ const struct urlmatch_item * b )
541
+ {
542
+ if (a -> hostmatch_len != b -> hostmatch_len )
543
+ return a -> hostmatch_len < b -> hostmatch_len ? -1 : 1 ;
544
+ if (a -> pathmatch_len != b -> pathmatch_len )
545
+ return a -> pathmatch_len < b -> pathmatch_len ? -1 : 1 ;
546
+ if (a -> user_matched != b -> user_matched )
547
+ return b -> user_matched ? -1 : 1 ;
548
+ return 0 ;
472
549
}
473
550
474
551
int urlmatch_config_entry (const char * var , const char * value , void * cb )
475
552
{
476
553
struct string_list_item * item ;
477
554
struct urlmatch_config * collect = cb ;
478
- struct urlmatch_item * matched ;
555
+ struct urlmatch_item matched = { 0 } ;
479
556
struct url_info * url = & collect -> url ;
480
557
const char * key , * dot ;
481
558
struct strbuf synthkey = STRBUF_INIT ;
482
- size_t matched_len = 0 ;
483
- int user_matched = 0 ;
484
559
int retval ;
485
560
486
561
if (!skip_prefix (var , collect -> section , & key ) || * (key ++ ) != '.' ) {
@@ -494,13 +569,13 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
494
569
struct url_info norm_info ;
495
570
496
571
config_url = xmemdupz (key , dot - key );
497
- norm_url = url_normalize (config_url , & norm_info );
572
+ norm_url = url_normalize_1 (config_url , & norm_info , 1 );
498
573
free (config_url );
499
574
if (!norm_url )
500
575
return 0 ;
501
- matched_len = match_urls (url , & norm_info , & user_matched );
576
+ retval = match_urls (url , & norm_info , & matched );
502
577
free (norm_url );
503
- if (!matched_len )
578
+ if (!retval )
504
579
return 0 ;
505
580
key = dot + 1 ;
506
581
}
@@ -510,24 +585,18 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
510
585
511
586
item = string_list_insert (& collect -> vars , key );
512
587
if (!item -> util ) {
513
- matched = xcalloc (1 , sizeof (* matched ));
514
- item -> util = matched ;
588
+ item -> util = xcalloc (1 , sizeof (matched ));
515
589
} else {
516
- matched = item -> util ;
517
- /*
518
- * Is our match shorter? Is our match the same
519
- * length, and without user while the current
520
- * candidate is with user? Then we cannot use it.
521
- */
522
- if (matched_len < matched -> matched_len ||
523
- ((matched_len == matched -> matched_len ) &&
524
- (!user_matched && matched -> user_matched )))
590
+ if (cmp_matches (& matched , item -> util ) < 0 )
591
+ /*
592
+ * Our match is worse than the old one,
593
+ * we cannot use it.
594
+ */
525
595
return 0 ;
526
596
/* Otherwise, replace it with this one. */
527
597
}
528
598
529
- matched -> matched_len = matched_len ;
530
- matched -> user_matched = user_matched ;
599
+ memcpy (item -> util , & matched , sizeof (matched ));
531
600
strbuf_addstr (& synthkey , collect -> section );
532
601
strbuf_addch (& synthkey , '.' );
533
602
strbuf_addstr (& synthkey , key );
0 commit comments