Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions DevProxy.Integration.Tests/BehaviorPluginsIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,42 @@ public async Task GenericRandomError_Rate100_OverridesOriginWithConfiguredError(
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
}

[Theory]
[InlineData("/Get")]
[InlineData("/Ge*")]
public async Task GenericRandomError_MatchesUrlCaseInsensitively(string errorPath)
{
await using var origin = await FakeOrigin.StartAsync();
var urls = KestrelProxyHarness.BuildUrlsToWatch(origin.Host);

var config = PluginConfig.FromJson($$"""
{
"rate": 100,
"errors": [
{
"request": { "url": "http://{{origin.Host}}{{errorPath}}" },
"responses": [ { "statusCode": 503 } ]
}
]
}
""");
var plugin = new GenericRandomErrorPlugin(
SharedHttpClient,
NullLogger<GenericRandomErrorPlugin>.Instance,
urls,
ProxyConfig,
config);

await using var proxy = await KestrelProxyHarness.StartAsync(
origin.Host, [plugin]);
using var client = proxy.CreateHttpClient();

// urlsToWatch matching ignores case, so error URL matching must too.
using var response = await client.GetAsync(new Uri($"http://{origin.Host}/get"));

Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
}

[Fact]
public async Task GenericRandomError_DynamicRetryAfterOnNon429_IsResolved()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,43 @@ public async Task MockResponse_ShortCircuitsWithConfiguredMock()
Assert.Contains("mocked-by-test", body, StringComparison.Ordinal);
}

[Theory]
[InlineData("/Get")]
[InlineData("/Ge*")]
public async Task MockResponse_MatchesUrlCaseInsensitively(string mockPath)
{
await using var origin = await FakeOrigin.StartAsync();
var urls = KestrelProxyHarness.BuildUrlsToWatch(origin.Host);

var config = PluginConfig.FromJson($$"""
{
"mocks": [
{
"request": { "url": "http://{{origin.Host}}{{mockPath}}", "method": "GET" },
"response": { "statusCode": 201, "body": "mocked-by-test" }
}
]
}
""");
var plugin = new MockResponsePlugin(
SharedHttpClient,
NullLogger<MockResponsePlugin>.Instance,
urls,
ProxyConfig,
config);

await using var proxy = await KestrelProxyHarness.StartAsync(
origin.Host, [plugin]);
using var client = proxy.CreateHttpClient();

using var response = await client.GetAsync(new Uri($"http://{origin.Host}/get"));
var body = await response.Content.ReadAsStringAsync();

// urlsToWatch matching ignores case, so mock URL matching must too.
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.Contains("mocked-by-test", body, StringComparison.Ordinal);
}

[Fact]
public async Task Auth_ApiKey_RejectsRequestWithoutKey()
{
Expand Down
4 changes: 2 additions & 2 deletions DevProxy.Plugins/Behavior/GenericRandomErrorPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ private static ThrottlingInfo ShouldThrottle(IHttpRequest request, string thrott
return false;
}

if (errorResponse.Request.Url == request.Url &&
if (string.Equals(errorResponse.Request.Url, request.Url, StringComparison.OrdinalIgnoreCase) &&
HasMatchingBody(errorResponse, request))
{
return true;
Expand All @@ -203,7 +203,7 @@ private static ThrottlingInfo ShouldThrottle(IHttpRequest request, string thrott

// turn mock URL with wildcard into a regex and match against the request URL
var errorResponseUrlRegex = Regex.Escape(errorResponse.Request.Url).Replace("\\*", ".*", StringComparison.OrdinalIgnoreCase);
return Regex.IsMatch(request.Url, $"^{errorResponseUrlRegex}$") &&
return Regex.IsMatch(request.Url, $"^{errorResponseUrlRegex}$", RegexOptions.IgnoreCase) &&
HasMatchingBody(errorResponse, request);
});

Expand Down
4 changes: 2 additions & 2 deletions DevProxy.Plugins/Mocking/GraphMockResponsePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ Configuration.Mocks is null ||
var absoluteRequestFromBatchUrl = ProxyUtils
.GetAbsoluteRequestUrlFromBatch(batchRequestUri, request.Url)
.ToString();
if (mockResponse.Request.Url == absoluteRequestFromBatchUrl)
if (string.Equals(mockResponse.Request.Url, absoluteRequestFromBatchUrl, StringComparison.OrdinalIgnoreCase))
{
return true;
}
Expand All @@ -204,7 +204,7 @@ Configuration.Mocks is null ||

//turn mock URL with wildcard into a regex and match against the request URL
var mockResponseUrlRegex = Regex.Escape(mockResponse.Request.Url).Replace("\\*", ".*", StringComparison.OrdinalIgnoreCase);
return Regex.IsMatch(absoluteRequestFromBatchUrl, $"^{mockResponseUrlRegex}$");
return Regex.IsMatch(absoluteRequestFromBatchUrl, $"^{mockResponseUrlRegex}$", RegexOptions.IgnoreCase);
});
return mockResponse;
}
Expand Down
4 changes: 2 additions & 2 deletions DevProxy.Plugins/Mocking/MockResponsePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ Configuration.Mocks is null ||
return false;
}

if (mockResponse.Request.Url == request.Url &&
if (string.Equals(mockResponse.Request.Url, request.Url, StringComparison.OrdinalIgnoreCase) &&
HasMatchingBody(mockResponse, request) &&
IsNthRequest(mockResponse))
{
Expand All @@ -319,7 +319,7 @@ Configuration.Mocks is null ||
}

// turn mock URL with wildcard into a regex and match against the request URL
return Regex.IsMatch(request.Url, ProxyUtils.PatternToRegex(mockResponse.Request.Url)) &&
return Regex.IsMatch(request.Url, ProxyUtils.PatternToRegex(mockResponse.Request.Url), RegexOptions.IgnoreCase) &&
HasMatchingBody(mockResponse, request) &&
IsNthRequest(mockResponse);
});
Expand Down
2 changes: 1 addition & 1 deletion DevProxy.Plugins/Mocking/WebSocketMockResponsePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ private static Task SendAsync(IWebSocketConnection connection, WebSocketMessageM
return false;
}

return Regex.IsMatch(requestUrl, ProxyUtils.PatternToRegex(mockUrl));
return Regex.IsMatch(requestUrl, ProxyUtils.PatternToRegex(mockUrl), RegexOptions.IgnoreCase);
});
}
}
Loading