-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Background and motivation
Uri validates the input and (if needed) converts it into a normalized (canonical) representation.
For example, it will:
- Escape reserved characters (spaces turn into
%20) - Unescape unreserved characters (
%41turns intoA) - Compress dot segments (
/foo/./bar/../turns into/foo/)
It does this based on the recommendations of the Uri RFC.
Some services, however, rely on specific behavior that may be impossible to replicate using .NET's Uri (#52628, #58057).
For example, it is currently not possible to send /foo?A=%42 with HttpClient, as Uri will convert it to /foo?A=B.
I propose adding a UriCreationOptions type and a ctor/TryCreate overload to consume it, serving as the extension point for future Uri customizability.
Uri has support for implicitly converting a file path into a file:// uri.
/foo is a valid Unix absolute file path and support for Unix paths is limited to non-Windows platforms.
This can create confusion in cases like Uri.TryCreate("/foo", UriKind.Absolute) where the behavior depends on the platform.
Given an extension point like UriCreationOptions is available, I propose adding an AllowImplicitFilePaths flag to it.
API Proposal
namespace System
{
// New type
public readonly struct UriCreationOptions
{
public bool AllowImplicitFilePaths { get; init; }
public bool DangerousUseRawPathAndQuery { get; init; }
public UriKind UriKind { get; }
public UriCreationOptions(UriKind uriKind);
}
public partial class Uri
{
// Existing
public Uri(string uriString);
public Uri(string uriString, UriKind uriKind);
// New
public Uri(string uriString, UriCreationOptions creationOptions);
// Existing
public static bool TryCreate(string? uriString, UriKind uriKind, out Uri? result);
// New
public static bool TryCreate(string? uriString, UriCreationOptions creationOptions, out Uri? result);
}
}Alternative names for DangerousUseRawPathAndQuery:
DangerousUseRawTargetDangerousDisableCanonicalization
Behavior of DangerousUseRawPathAndQuery is such that we try not to be opinionated as much as possible:
- Validation of the
Path/Queryis skipped, we assume they already are in the “perfect format” - We will not escape reserved characters (e.g. spaces won't be turned into
%20) - We will not unescape unreserved characters (e.g.
%41won't be turned intoA) - We will not compress dot segments (
/../or/./will be kept) - Fragment is always empty –
#and anything following it is attributed to thePathorQuery- Not doing so would disallow sending the
#literal as part ofPathAndQuery
- Not doing so would disallow sending the
- Properties like
Path,Query,PathAndQuerywill return the value as-is - We will not ensure
Path/PathAndQuerystart with/, that is left up to the user - Uris with
DangerousUseRawPathAndQuerymay only be equal to Uris with the same flag - The
GetComponentsAPI will ignore theUriFormatargument (valuesUriEscaped,Unescaped,SafeUnescaped) forPath&Querycomponents
API Usage
string uriString = "/foo";
Uri.TryCreate(uriString, new UriCreationOptions { AllowImplicitFilePaths = false }, out var uri); // Falsevar options = new UriCreationOptions { DangerousUseRawPathAndQuery = true };
var uri = new Uri("http://foo/%41", options);
// Server receives /%41 instead of /AAlternative API
-
Instead of a
readonly struct, makeUriCreationOptionsan enum- Prevents us from easily exposing more complex options (e.g. ints, callbacks) in the future
- Forces us into inverting names in some cases (e.g.
AllowImplicitFilePathswould have to beDontAllowImplicitFilePaths) to match correctly defaults - Defers validation – with
UriCreationOptionswe can ensure it's always in a valid state (e.g. validUriKind)
-
Instead of a
DangerousUseRawPathAndQueryflag, expose granular options controlling specific transformations- Example:
UnescapeUnreservedCharacters,CompressDotSegments - Any new scenarios that can't be addressed with existing options are blocked on the decision of the networking team, API review, implementation, and release of a major .NET version
- Complicates the code base & testing - some options may conflict
- Example:
Risks
Setting DangerousUseRawPathAndQuery means no validation/transformation of the input will take place past the authority.
If the input is not already in the correct format, HTTP requests using such a Uri may be malformed.
For example:
- Reserved characters will not be escaped - space characters will not be changed to
%20