mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-01 15:13:33 +02:00
QueryStringParser
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>1.0.18</VersionPrefix>
|
<VersionPrefix>1.0.19</VersionPrefix>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Choose>
|
<Choose>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
https://github.com/StefH/GitHubReleaseNotes
|
https://github.com/StefH/GitHubReleaseNotes
|
||||||
|
|
||||||
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --version 1.0.18.0
|
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --version 1.0.19.0
|
||||||
@@ -438,6 +438,15 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
.WithBody("<xml>ok</xml>")
|
.WithBody("<xml>ok</xml>")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
server.Given(Request.Create()
|
||||||
|
.WithPath("/services/query/")
|
||||||
|
.WithParam("q", "SELECT Id from User where username='user@gmail.com'")
|
||||||
|
.UsingGet())
|
||||||
|
.RespondWith(Response.Create()
|
||||||
|
.WithStatusCode(200)
|
||||||
|
.WithHeader("Content-Type", "application/json")
|
||||||
|
.WithBodyAsJson(new { Id = "5bdf076c-5654-4b3e-842c-7caf1fabf8c9" }));
|
||||||
|
|
||||||
System.Console.WriteLine("Press any key to stop the server");
|
System.Console.WriteLine("Press any key to stop the server");
|
||||||
System.Console.ReadKey();
|
System.Console.ReadKey();
|
||||||
server.Stop();
|
server.Stop();
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Util;
|
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.RequestBuilders
|
namespace WireMock.RequestBuilders
|
||||||
|
|||||||
@@ -171,40 +171,7 @@ namespace WireMock
|
|||||||
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
||||||
Cookies = cookies;
|
Cookies = cookies;
|
||||||
RawQuery = WebUtility.UrlDecode(urlDetails.Url.Query);
|
RawQuery = WebUtility.UrlDecode(urlDetails.Url.Query);
|
||||||
Query = ParseQuery(RawQuery);
|
Query = QueryStringParser.Parse(RawQuery);
|
||||||
}
|
|
||||||
|
|
||||||
private static IDictionary<string, WireMockList<string>> ParseQuery(string queryString)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(queryString))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryString.StartsWith("?"))
|
|
||||||
{
|
|
||||||
queryString = queryString.Substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryString.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Aggregate(new Dictionary<string, WireMockList<string>>(),
|
|
||||||
(dict, term) =>
|
|
||||||
{
|
|
||||||
string[] parts = term.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
string key = parts[0];
|
|
||||||
if (!dict.ContainsKey(key))
|
|
||||||
{
|
|
||||||
dict.Add(key, new WireMockList<string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parts.Length == 2)
|
|
||||||
{
|
|
||||||
string[] values = parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
dict[key].AddRange(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dict;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
41
src/WireMock.Net/Util/QueryStringParser.cs
Normal file
41
src/WireMock.Net/Util/QueryStringParser.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace WireMock.Util
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Based on https://stackoverflow.com/questions/659887/get-url-parameters-from-a-string-in-net
|
||||||
|
/// </summary>
|
||||||
|
internal static class QueryStringParser
|
||||||
|
{
|
||||||
|
public static IDictionary<string, WireMockList<string>> Parse(string queryString)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(queryString))
|
||||||
|
{
|
||||||
|
return new Dictionary<string, WireMockList<string>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] JoinParts(string[] parts)
|
||||||
|
{
|
||||||
|
if (parts.Length > 2)
|
||||||
|
{
|
||||||
|
return new[] { string.Join("=", parts, 1, parts.Length - 1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.Length > 1)
|
||||||
|
{
|
||||||
|
return parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); // support "?key=1,2"
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryString.TrimStart('?')
|
||||||
|
.Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries) // Support "?key=value;key=anotherValue" and "?key=value&key=anotherValue"
|
||||||
|
.Select(parameter => parameter.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
.GroupBy(parts => parts[0], JoinParts)
|
||||||
|
.ToDictionary(grouping => grouping.Key, grouping => new WireMockList<string>(grouping.SelectMany(x => x)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
210
test/WireMock.Net.Tests/Util/QueryStringParserTests.cs
Normal file
210
test/WireMock.Net.Tests/Util/QueryStringParserTests.cs
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using WireMock.Util;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Util
|
||||||
|
{
|
||||||
|
public class QueryStringParserTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Parse_WithNullString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Equal(new Dictionary<string, WireMockList<string>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_WithEmptyString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Equal(new Dictionary<string, WireMockList<string>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_WithQuestionMark()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Equal(new Dictionary<string, WireMockList<string>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With1Param()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=bla/blub.xml";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>("bla/blub.xml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With2Params()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?x=1&y=2";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(2);
|
||||||
|
result["x"].Should().Equal(new WireMockList<string>("1"));
|
||||||
|
result["y"].Should().Equal(new WireMockList<string>("2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With1ParamNoValue()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?empty";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["empty"].Should().Equal(new WireMockList<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With1ParamNoValueWithEqualSign()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?empty=";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["empty"].Should().Equal(new WireMockList<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With1ParamAndJustAndSign()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=1&";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With2ParamsAndWhereOneHasAQuestion()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=value?&b=c";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(2);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>("value?"));
|
||||||
|
result["b"].Should().Equal(new WireMockList<string>("c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With1ParamWithEqualSign()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=value=what";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>("value=what"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_WithMultipleParamWithSameKeySeparatedBySemiColon()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=value;key=anotherValue";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>(new[] { "value", "anotherValue" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_With1ParamContainingComma()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=1,2&key=3";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>(new[] { "1", "2", "3" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_WithMultipleParamWithSameKey()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?key=value&key=anotherValue";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
result["key"].Should().Equal(new WireMockList<string>(new[] { "value", "anotherValue" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_WithComplex()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string query = "?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.Parse(query);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Count.Should().Be(6);
|
||||||
|
result["q"].Should().Equal(new WireMockList<string>("energy+edge"));
|
||||||
|
result["rls"].Should().Equal(new WireMockList<string>("com.microsoft:en-au"));
|
||||||
|
result["ie"].Should().Equal(new WireMockList<string>("UTF-8"));
|
||||||
|
result["oe"].Should().Equal(new WireMockList<string>("UTF-8"));
|
||||||
|
result["startIndex"].Should().Equal(new WireMockList<string>());
|
||||||
|
result["startPage"].Should().Equal(new WireMockList<string>("1%22"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="5.7.0" />
|
||||||
<PackageReference Include="System.Threading" Version="4.3.0" />
|
<PackageReference Include="System.Threading" Version="4.3.0" />
|
||||||
|
|
||||||
<PackageReference Include="RestEase" Version="1.4.7" />
|
<PackageReference Include="RestEase" Version="1.4.7" />
|
||||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.8" />
|
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.8" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||||
|
|||||||
Reference in New Issue
Block a user