Description
Description
Calling Uri.GetComponents()
with UriFormat.SafeUnescaped
converts %20 characters in query string parameters to regular spaces, which results in a (presumably) invalid URL.
Reproduction Steps
The sample below demonstrates the problem. QueryString.Create()
converts spaces to %20, but then they get converted back to regular spaces by Uri.GetComponents()
.
using Microsoft.AspNetCore.Http;
const string source = "http://localhost/path?filter=some+text";
Console.WriteLine($"source: {source}");
var parameters = new Dictionary<string, string?>
{
["filter"] = "other text"
};
string? queryString = QueryString.Create(parameters).Value;
Console.WriteLine($"queryString: {queryString}");
var builder = new UriBuilder(source)
{
Query = queryString
};
var uri = builder.Uri;
var text = uri.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
Console.WriteLine($"text: {text}");
Prints:
source: http://localhost/path?filter=some+text
queryString: ?filter=other%20text
text: http://localhost/path?filter=other text
Expected behavior
I would have expected text
in the repro steps above to become http://localhost/path?filter=other+text
or http://localhost/path?filter=other%20text
.
Actual behavior
In the repro steps above, text
becomes http://localhost/path?filter=other text
(note the unescaped space in the query string parameter).
Regression?
No response
Known Workarounds
Use UriFormat.UriEscaped
instead of UriFormat.SafeUnescaped
, which always escapes everything. Or run a replace-all on the output text to convert " " back to "+" or "%20".
Configuration
dotnet --info
.NET SDK:
Version: 8.0.202
Commit: 25674bb2f4
Workload version: 8.0.200-manifests.8cf8de6d
Runtime Environment:
OS Name: Windows
OS Version: 10.0.22631
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\8.0.202\
.NET workloads installed:
There are no installed workloads to display.
Host:
Version: 8.0.3
Architecture: x64
Commit: 9f4b1f5d66
.NET SDKs installed:
8.0.202 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Other architectures found:
x86 [C:\Program Files (x86)\dotnet]
registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]
Environment variables:
Not set
global.json file:
Not found
Other information
From https://www.rfc-editor.org/rfc/rfc2396.html#section-3.4, space is not among the set of characters that require escaping:
Within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", and "$" are reserved.
However, the existing implementation already escapes more than the spec requires.
This issue stems from the bug report at json-api-dotnet/JsonApiDotNetCore#1525.