-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathUrlRegexComparer.cs
143 lines (118 loc) · 4.52 KB
/
UrlRegexComparer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.RegularExpressions;
namespace DevProxy.Abstractions;
enum UrlRegexComparisonResult
{
/// <summary>
/// The first pattern is broader than the second pattern.
/// </summary>
FirstPatternBroader,
/// <summary>
/// The second pattern is broader than the first pattern.
/// </summary>
SecondPatternBroader,
/// <summary>
/// The patterns are equivalent.
/// </summary>
PatternsEquivalent,
/// <summary>
/// The patterns are mutually exclusive.
/// </summary>
PatternsMutuallyExclusive
}
class UrlRegexComparer
{
/// <summary>
/// Compares two URL patterns and returns a value indicating their
// relationship.
/// </summary>
/// <param name="pattern1">First URL pattern</param>
/// <param name="pattern2">Second URL pattern</param>
/// <returns>1 when the first pattern is broader; -1 when the second pattern
/// is broader or patterns are mutually exclusive; 0 when the patterns are
/// equal</returns>
public static UrlRegexComparisonResult CompareRegexPatterns(string pattern1, string pattern2)
{
var regex1 = new Regex(ProxyUtils.PatternToRegex(pattern1));
var regex2 = new Regex(ProxyUtils.PatternToRegex(pattern2));
// Generate test URLs based on patterns
var testUrls = GenerateTestUrls(pattern1, pattern2);
var matches1 = testUrls.Where(url => regex1.IsMatch(url)).ToList();
var matches2 = testUrls.Where(url => regex2.IsMatch(url)).ToList();
bool pattern1MatchesAll = matches2.All(regex1.IsMatch);
bool pattern2MatchesAll = matches1.All(regex2.IsMatch);
if (pattern1MatchesAll && !pattern2MatchesAll)
// Pattern 1 is broader
return UrlRegexComparisonResult.FirstPatternBroader;
else if (pattern2MatchesAll && !pattern1MatchesAll)
// Pattern 2 is broader
return UrlRegexComparisonResult.SecondPatternBroader;
else if (pattern1MatchesAll && pattern2MatchesAll)
// Patterns are equivalent
return UrlRegexComparisonResult.PatternsEquivalent;
else
// Patterns have different matching sets
return UrlRegexComparisonResult.PatternsMutuallyExclusive;
}
private static List<string> GenerateTestUrls(string pattern1, string pattern2)
{
var urls = new HashSet<string>();
// Extract domains and paths from patterns
var domains = ExtractDomains(pattern1)
.Concat(ExtractDomains(pattern2))
.Distinct()
.ToList();
var paths = ExtractPaths(pattern1)
.Concat(ExtractPaths(pattern2))
.Distinct()
.ToList();
// Generate combinations
foreach (var domain in domains)
{
foreach (var path in paths)
{
urls.Add($"https://{domain}/{path}");
}
// Add variants
urls.Add($"https://{domain}/");
urls.Add($"https://sub.{domain}/path");
urls.Add($"https://other-{domain}/different");
}
return urls.ToList();
}
private static HashSet<string> ExtractDomains(string pattern)
{
var domains = new HashSet<string>();
// Extract literal domains
var domainMatch = Regex.Match(Regex.Unescape(pattern), @"https://([^/\s]+)");
if (domainMatch.Success)
{
var domain = domainMatch.Groups[1].Value;
if (!domain.Contains(".*"))
domains.Add(domain);
}
// Add test domains
domains.Add("example.com");
domains.Add("test.com");
return domains;
}
private static HashSet<string> ExtractPaths(string pattern)
{
var paths = new HashSet<string>();
// Extract literal paths
var pathMatch = Regex.Match(pattern, @"https://[^/]+(/[^/\s]+)");
if (pathMatch.Success)
{
var path = pathMatch.Groups[1].Value;
if (!path.Contains(".*"))
paths.Add(path.TrimStart('/'));
}
// Add test paths
paths.Add("api");
paths.Add("users");
paths.Add("path1/path2");
return paths;
}
}