Skip to content

Using UriFormat.SafeUnescaped replaces %20 with space in query string #100792

Closed
@bkoelman

Description

@bkoelman

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions