// Compare with Http2Stream.TryValidatePseudoHeaders private void OnOriginFormTarget(HttpMethod method, HttpVersion version, Span <byte> target, Span <byte> path, Span <byte> query, Span <byte> customMethod, bool pathEncoded) { Debug.Assert(target[0] == ByteForwardSlash, "Should only be called when path starts with /"); _requestTargetForm = HttpRequestTarget.OriginForm; // URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11 // Multibyte Internationalized Resource Identifiers (IRIs) are first converted to utf8; // then encoded/escaped to ASCII https://www.ietf.org/rfc/rfc3987.txt "Mapping of IRIs to URIs" try { // Read raw target before mutating memory. RawTarget = target.GetAsciiStringNonNullCharacters(); QueryString = query.GetAsciiStringNonNullCharacters(); Path = PathNormalizer.DecodePath(path, pathEncoded, RawTarget, query.Length); } catch (InvalidOperationException) { ThrowRequestTargetRejected(target); } }
private void OnOriginFormTarget(HttpMethod method, HttpVersion version, Span <byte> target, Span <byte> path, Span <byte> query, Span <byte> customMethod, bool pathEncoded) { Debug.Assert(target[0] == ByteForwardSlash, "Should only be called when path starts with /"); _requestTargetForm = HttpRequestTarget.OriginForm; // URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11 // Multibyte Internationalized Resource Identifiers (IRIs) are first converted to utf8; // then encoded/escaped to ASCII https://www.ietf.org/rfc/rfc3987.txt "Mapping of IRIs to URIs" string requestUrlPath = null; string rawTarget = null; try { // Read raw target before mutating memory. rawTarget = target.GetAsciiStringNonNullCharacters(); if (pathEncoded) { // URI was encoded, unescape and then parse as UTF-8 // Disabling warning temporary #pragma warning disable 618 var pathLength = UrlEncoder.Decode(path, path); #pragma warning restore 618 // Removing dot segments must be done after unescaping. From RFC 3986: // // URI producing applications should percent-encode data octets that // correspond to characters in the reserved set unless these characters // are specifically allowed by the URI scheme to represent data in that // component. If a reserved character is found in a URI component and // no delimiting role is known for that character, then it must be // interpreted as representing the data octet corresponding to that // character's encoding in US-ASCII. // // https://tools.ietf.org/html/rfc3986#section-2.2 pathLength = PathNormalizer.RemoveDotSegments(path.Slice(0, pathLength)); requestUrlPath = GetUtf8String(path.Slice(0, pathLength)); } else { var pathLength = PathNormalizer.RemoveDotSegments(path); if (path.Length == pathLength && query.Length == 0) { // If no decoding was required, no dot segments were removed and // there is no query, the request path is the same as the raw target requestUrlPath = rawTarget; } else { requestUrlPath = path.Slice(0, pathLength).GetAsciiStringNonNullCharacters(); } } } catch (InvalidOperationException) { ThrowRequestTargetRejected(target); } QueryString = query.GetAsciiStringNonNullCharacters(); RawTarget = rawTarget; Path = requestUrlPath; }
// Compare with Http2Stream.TryValidatePseudoHeaders private void OnOriginFormTarget(HttpMethod method, HttpVersion version, Span <byte> target, Span <byte> path, Span <byte> query, Span <byte> customMethod, bool pathEncoded) { Debug.Assert(target[0] == ByteForwardSlash, "Should only be called when path starts with /"); _requestTargetForm = HttpRequestTarget.OriginForm; if (target.Length == 1) { // If target.Length == 1 it can only be a forward slash (e.g. home page) // and we know RawTarget and Path are the same and QueryString is Empty RawTarget = ForwardSlash; Path = ForwardSlash; QueryString = string.Empty; // Clear parsedData as we won't check it if we come via this path again, // an setting to null is fast as it doesn't need to use a GC write barrier. _parsedRawTarget = _parsedPath = _parsedQueryString = null; return; } // URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11 // Multibyte Internationalized Resource Identifiers (IRIs) are first converted to utf8; // then encoded/escaped to ASCII https://www.ietf.org/rfc/rfc3987.txt "Mapping of IRIs to URIs" try { var disableStringReuse = ServerOptions.DisableStringReuse; // Read raw target before mutating memory. var previousValue = _parsedRawTarget; if (disableStringReuse || previousValue == null || previousValue.Length != target.Length || !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target)) { // The previous string does not match what the bytes would convert to, // so we will need to generate a new string. RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters(); previousValue = _parsedQueryString; if (disableStringReuse || previousValue == null || previousValue.Length != query.Length || !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, query)) { // The previous string does not match what the bytes would convert to, // so we will need to generate a new string. QueryString = _parsedQueryString = query.GetAsciiStringNonNullCharacters(); } else { // Same as previous QueryString = _parsedQueryString; } if (path.Length == 1) { // If path.Length == 1 it can only be a forward slash (e.g. home page) Path = _parsedPath = ForwardSlash; } else { Path = _parsedPath = PathNormalizer.DecodePath(path, pathEncoded, RawTarget, query.Length); } } else { // As RawTarget is the same we can reuse the previous parsed values. RawTarget = _parsedRawTarget; Path = _parsedPath; QueryString = _parsedQueryString; } } catch (InvalidOperationException) { ThrowRequestTargetRejected(target); } }