Skip to content

Commit ca16213

Browse files
author
ladeak
committed
Merging PathNormalizer Implementations
- Follow up on comment: dotnet#56805 (comment) - Moving PathNormalizer from Shared\HttpSys to Shared\PathNormalizer, changing the namespace to AspNetCore.Internal - Shares the code between HttpSys and Kestrel.Core - Remaining Kestrel specific code renamed to PathDecoder - Keeping the tests and benchmarks in Kestrel
1 parent b5a97c4 commit ca16213

File tree

11 files changed

+56
-170
lines changed

11 files changed

+56
-170
lines changed

src/Servers/IIS/IIS/src/Microsoft.AspNetCore.Server.IIS.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<Compile Include="$(SharedSourceRoot)TypeNameHelper\*.cs" />
2222
<Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\**\*.cs" LinkBase="Shared\" />
2323
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" LinkBase="Shared\" />
24+
<Compile Include="$(SharedSourceRoot)PathNormalizer\**\*.cs" LinkBase="Shared\RequestProcessing\" />
2425
<Compile Include="$(SharedSourceRoot)StackTrace\**\*.cs" LinkBase="Shared\" />
2526
<Compile Include="$(SharedSourceRoot)RazorViews\*.cs" LinkBase="Shared\" />
2627
<Compile Include="$(SharedSourceRoot)ErrorPage\*.cs" LinkBase="Shared\" />

src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ private void ParseTarget(TargetOffsetPathLength targetPath, Span<byte> target)
416416
else
417417
{
418418
var path = target[..pathLength];
419-
Path = _parsedPath = PathNormalizer.DecodePath(path, targetPath.IsEncoded, RawTarget, queryLength);
419+
Path = _parsedPath = PathDecoder.DecodePath(path, targetPath.IsEncoded, RawTarget, queryLength);
420420
}
421421
}
422422
catch (InvalidOperationException)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Text;
5+
using Microsoft.AspNetCore.Internal;
6+
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
7+
8+
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
9+
10+
internal static class PathDecoder
11+
{
12+
public static string DecodePath(Span<byte> path, bool pathEncoded, string rawTarget, int queryLength)
13+
{
14+
int pathLength;
15+
if (pathEncoded)
16+
{
17+
// URI was encoded, unescape and then parse as UTF-8
18+
pathLength = UrlDecoder.DecodeInPlace(path, isFormEncoding: false);
19+
20+
// Removing dot segments must be done after unescaping. From RFC 3986:
21+
//
22+
// URI producing applications should percent-encode data octets that
23+
// correspond to characters in the reserved set unless these characters
24+
// are specifically allowed by the URI scheme to represent data in that
25+
// component. If a reserved character is found in a URI component and
26+
// no delimiting role is known for that character, then it must be
27+
// interpreted as representing the data octet corresponding to that
28+
// character's encoding in US-ASCII.
29+
//
30+
// https://tools.ietf.org/html/rfc3986#section-2.2
31+
pathLength = PathNormalizer.RemoveDotSegments(path.Slice(0, pathLength));
32+
33+
return Encoding.UTF8.GetString(path.Slice(0, pathLength));
34+
}
35+
36+
pathLength = PathNormalizer.RemoveDotSegments(path);
37+
38+
if (path.Length == pathLength && queryLength == 0)
39+
{
40+
// If no decoding was required, no dot segments were removed and
41+
// there is no query, the request path is the same as the raw target
42+
return rawTarget;
43+
}
44+
45+
return path.Slice(0, pathLength).GetAsciiStringNonNullCharacters();
46+
}
47+
}

src/Servers/Kestrel/Core/src/Internal/Http/PathNormalizer.cs

Lines changed: 0 additions & 162 deletions
This file was deleted.

src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ private bool TryValidatePath(ReadOnlySpan<char> pathSegment)
435435
pathBuffer[i] = (byte)ch;
436436
}
437437

438-
Path = PathNormalizer.DecodePath(pathBuffer, pathEncoded, RawTarget!, QueryString!.Length);
438+
Path = PathDecoder.DecodePath(pathBuffer, pathEncoded, RawTarget!, QueryString!.Length);
439439

440440
return true;
441441
}

src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,7 @@ private bool TryValidatePath(ReadOnlySpan<char> pathSegment)
11661166
pathBuffer[i] = (byte)ch;
11671167
}
11681168

1169-
Path = PathNormalizer.DecodePath(pathBuffer, pathEncoded, RawTarget!, QueryString!.Length);
1169+
Path = PathDecoder.DecodePath(pathBuffer, pathEncoded, RawTarget!, QueryString!.Length);
11701170

11711171
return true;
11721172
}

src/Servers/Kestrel/Core/src/Microsoft.AspNetCore.Server.Kestrel.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<Compile Include="$(SharedSourceRoot)CertificateGeneration\**\*.cs" />
2323
<Compile Include="$(SharedSourceRoot)ValueTaskExtensions\**\*.cs" />
2424
<Compile Include="$(SharedSourceRoot)UrlDecoder\**\*.cs" />
25+
<Compile Include="$(SharedSourceRoot)PathNormalizer\**\*.cs" LinkBase="Shared\" />
2526
<Compile Include="$(SharedSourceRoot)InternalHeaderNames.cs" Link="Shared\InternalHeaderNames.cs"/>
2627
<Compile Include="$(SharedSourceRoot)Buffers\**\*.cs" LinkBase="Internal\Infrastructure\PipeWriterHelpers" />
2728
<Compile Include="$(SharedSourceRoot)runtime\*.cs" Link="Shared\runtime\%(Filename)%(Extension)" />

src/Servers/Kestrel/Core/test/PathNormalizerTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
54
using System.Text;
6-
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
7-
using Xunit;
5+
using Microsoft.AspNetCore.Internal;
86

97
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests;
108

src/Servers/Kestrel/perf/Microbenchmarks/DotSegmentRemovalBenchmark.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
using System.Text;
55
using BenchmarkDotNet.Attributes;
6-
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
6+
using Microsoft.AspNetCore.Internal;
77

88
namespace Microsoft.AspNetCore.Server.Kestrel.Microbenchmarks;
99

src/Shared/HttpSys/RequestProcessing/RequestUriBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Diagnostics;
55
using System.Text;
6+
using Microsoft.AspNetCore.Internal;
67

78
namespace Microsoft.AspNetCore.HttpSys.Internal;
89

src/Shared/HttpSys/RequestProcessing/PathNormalizer.cs renamed to src/Shared/PathNormalizer/PathNormalizer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Diagnostics;
55
using System.Runtime.InteropServices;
66

7-
namespace Microsoft.AspNetCore.HttpSys.Internal;
7+
namespace Microsoft.AspNetCore.Internal;
88

99
internal static class PathNormalizer
1010
{

0 commit comments

Comments
 (0)