@@ -38,145 +38,152 @@ internal Request(RequestContext requestContext)
38
38
{
39
39
// TODO: Verbose log
40
40
RequestContext = requestContext ;
41
- _contentBoundaryType = BoundaryType . None ;
42
41
43
- RequestId = requestContext . RequestId ;
44
- // For HTTP/2 Http.Sys assigns each request a unique connection id for use with API calls, but the RawConnectionId represents the real connection.
45
- UConnectionId = requestContext . ConnectionId ;
46
- RawConnectionId = requestContext . RawConnectionId ;
47
- SslStatus = requestContext . SslStatus ;
42
+ try
43
+ {
44
+ _contentBoundaryType = BoundaryType . None ;
48
45
49
- KnownMethod = requestContext . VerbId ;
50
- Method = requestContext . GetVerb ( ) ! ;
46
+ RequestId = requestContext . RequestId ;
47
+ // For HTTP/2 Http.Sys assigns each request a unique connection id for use with API calls, but the RawConnectionId represents the real connection.
48
+ UConnectionId = requestContext . ConnectionId ;
49
+ RawConnectionId = requestContext . RawConnectionId ;
50
+ SslStatus = requestContext . SslStatus ;
51
51
52
- RawUrl = requestContext . GetRawUrl ( ) ! ;
52
+ KnownMethod = requestContext . VerbId ;
53
+ Method = requestContext . GetVerb ( ) ! ;
53
54
54
- var cookedUrl = requestContext . GetCookedUrl ( ) ;
55
- QueryString = cookedUrl . GetQueryString ( ) ?? string . Empty ;
55
+ RawUrl = requestContext . GetRawUrl ( ) ! ;
56
56
57
- var rawUrlInBytes = requestContext . GetRawUrlInBytes ( ) ;
58
- var originalPath = RequestUriBuilder . DecodeAndUnescapePath ( rawUrlInBytes ) ;
57
+ var cookedUrl = requestContext . GetCookedUrl ( ) ;
58
+ QueryString = cookedUrl . GetQueryString ( ) ?? string . Empty ;
59
59
60
- PathBase = string . Empty ;
61
- Path = originalPath ;
62
- var prefix = requestContext . Server . Options . UrlPrefixes . GetPrefix ( ( int ) requestContext . UrlContext ) ;
60
+ var rawUrlInBytes = requestContext . GetRawUrlInBytes ( ) ;
61
+ var originalPath = RequestUriBuilder . DecodeAndUnescapePath ( rawUrlInBytes ) ;
63
62
64
- // 'OPTIONS * HTTP/1.1'
65
- if ( KnownMethod == HTTP_VERB . HttpVerbOPTIONS && string . Equals ( RawUrl , "*" , StringComparison . Ordinal ) )
66
- {
67
63
PathBase = string . Empty ;
68
- Path = string . Empty ;
69
- }
70
- // Prefix may be null if the requested has been transferred to our queue
71
- else if ( prefix is not null )
72
- {
73
- var pathBase = prefix . PathWithoutTrailingSlash ;
64
+ Path = originalPath ;
65
+ var prefix = requestContext . Server . Options . UrlPrefixes . GetPrefix ( ( int ) requestContext . UrlContext ) ;
74
66
75
- // url: /base/path, prefix: /base/, base: /base, path: /path
76
- // url: /, prefix: /, base: , path: /
77
- if ( originalPath . Equals ( pathBase , StringComparison . Ordinal ) )
78
- {
79
- // Exact match, no need to preserve the casing
80
- PathBase = pathBase ;
81
- Path = string . Empty ;
82
- }
83
- else if ( originalPath . Equals ( pathBase , StringComparison . OrdinalIgnoreCase ) )
67
+ // 'OPTIONS * HTTP/1.1'
68
+ if ( KnownMethod == HTTP_VERB . HttpVerbOPTIONS && string . Equals ( RawUrl , "*" , StringComparison . Ordinal ) )
84
69
{
85
- // Preserve the user input casing
86
- PathBase = originalPath ;
70
+ PathBase = string . Empty ;
87
71
Path = string . Empty ;
88
72
}
89
- else if ( originalPath . StartsWith ( prefix . Path , StringComparison . Ordinal ) )
90
- {
91
- // Exact match, no need to preserve the casing
92
- PathBase = pathBase ;
93
- Path = originalPath [ pathBase . Length ..] ;
94
- }
95
- else if ( originalPath . StartsWith ( prefix . Path , StringComparison . OrdinalIgnoreCase ) )
73
+ // Prefix may be null if the requested has been transferred to our queue
74
+ else if ( prefix is not null )
96
75
{
97
- // Preserve the user input casing
98
- PathBase = originalPath [ ..pathBase . Length ] ;
99
- Path = originalPath [ pathBase . Length ..] ;
100
- }
101
- else
102
- {
103
- // Http.Sys path base matching is based on the cooked url which applies some non-standard normalizations that we don't use
104
- // like collapsing duplicate slashes "//", converting '\' to '/', and un-escaping "%2F" to '/'. Find the right split and
105
- // ignore the normalizations.
106
- var originalOffset = 0 ;
107
- var baseOffset = 0 ;
108
- while ( originalOffset < originalPath . Length && baseOffset < pathBase . Length )
76
+ var pathBase = prefix . PathWithoutTrailingSlash ;
77
+
78
+ // url: /base/path, prefix: /base/, base: /base, path: /path
79
+ // url: /, prefix: /, base: , path: /
80
+ if ( originalPath . Equals ( pathBase , StringComparison . Ordinal ) )
109
81
{
110
- var baseValue = pathBase [ baseOffset ] ;
111
- var offsetValue = originalPath [ originalOffset ] ;
112
- if ( baseValue == offsetValue
113
- || char . ToUpperInvariant ( baseValue ) == char . ToUpperInvariant ( offsetValue ) )
114
- {
115
- // case-insensitive match, continue
116
- originalOffset ++ ;
117
- baseOffset ++ ;
118
- }
119
- else if ( baseValue == '/' && offsetValue == '\\ ' )
120
- {
121
- // Http.Sys considers these equivalent
122
- originalOffset ++ ;
123
- baseOffset ++ ;
124
- }
125
- else if ( baseValue == '/' && originalPath . AsSpan ( originalOffset ) . StartsWith ( "%2F" , StringComparison . OrdinalIgnoreCase ) )
126
- {
127
- // Http.Sys un-escapes this
128
- originalOffset += 3 ;
129
- baseOffset ++ ;
130
- }
131
- else if ( baseOffset > 0 && pathBase [ baseOffset - 1 ] == '/'
132
- && ( offsetValue == '/' || offsetValue == '\\ ' ) )
133
- {
134
- // Duplicate slash, skip
135
- originalOffset ++ ;
136
- }
137
- else if ( baseOffset > 0 && pathBase [ baseOffset - 1 ] == '/'
138
- && originalPath . AsSpan ( originalOffset ) . StartsWith ( "%2F" , StringComparison . OrdinalIgnoreCase ) )
139
- {
140
- // Duplicate slash equivalent, skip
141
- originalOffset += 3 ;
142
- }
143
- else
82
+ // Exact match, no need to preserve the casing
83
+ PathBase = pathBase ;
84
+ Path = string . Empty ;
85
+ }
86
+ else if ( originalPath . Equals ( pathBase , StringComparison . OrdinalIgnoreCase ) )
87
+ {
88
+ // Preserve the user input casing
89
+ PathBase = originalPath ;
90
+ Path = string . Empty ;
91
+ }
92
+ else if ( originalPath . StartsWith ( prefix . Path , StringComparison . Ordinal ) )
93
+ {
94
+ // Exact match, no need to preserve the casing
95
+ PathBase = pathBase ;
96
+ Path = originalPath [ pathBase . Length ..] ;
97
+ }
98
+ else if ( originalPath . StartsWith ( prefix . Path , StringComparison . OrdinalIgnoreCase ) )
99
+ {
100
+ // Preserve the user input casing
101
+ PathBase = originalPath [ ..pathBase . Length ] ;
102
+ Path = originalPath [ pathBase . Length ..] ;
103
+ }
104
+ else
105
+ {
106
+ // Http.Sys path base matching is based on the cooked url which applies some non-standard normalizations that we don't use
107
+ // like collapsing duplicate slashes "//", converting '\' to '/', and un-escaping "%2F" to '/'. Find the right split and
108
+ // ignore the normalizations.
109
+ var originalOffset = 0 ;
110
+ var baseOffset = 0 ;
111
+ while ( originalOffset < originalPath . Length && baseOffset < pathBase . Length )
144
112
{
145
- // Mismatch, fall back
146
- // The failing test case here is "/base/call//../bat//path1//path2", reduced to "/base/call/bat//path1//path2",
147
- // where http.sys collapses "//" before "../", but we do "../" first. We've lost the context that there were dot segments,
148
- // or duplicate slashes, how do we figure out that "call/" can be eliminated?
149
- originalOffset = 0 ;
150
- break ;
113
+ var baseValue = pathBase [ baseOffset ] ;
114
+ var offsetValue = originalPath [ originalOffset ] ;
115
+ if ( baseValue == offsetValue
116
+ || char . ToUpperInvariant ( baseValue ) == char . ToUpperInvariant ( offsetValue ) )
117
+ {
118
+ // case-insensitive match, continue
119
+ originalOffset ++ ;
120
+ baseOffset ++ ;
121
+ }
122
+ else if ( baseValue == '/' && offsetValue == '\\ ' )
123
+ {
124
+ // Http.Sys considers these equivalent
125
+ originalOffset ++ ;
126
+ baseOffset ++ ;
127
+ }
128
+ else if ( baseValue == '/' && originalPath . AsSpan ( originalOffset ) . StartsWith ( "%2F" , StringComparison . OrdinalIgnoreCase ) )
129
+ {
130
+ // Http.Sys un-escapes this
131
+ originalOffset += 3 ;
132
+ baseOffset ++ ;
133
+ }
134
+ else if ( baseOffset > 0 && pathBase [ baseOffset - 1 ] == '/'
135
+ && ( offsetValue == '/' || offsetValue == '\\ ' ) )
136
+ {
137
+ // Duplicate slash, skip
138
+ originalOffset ++ ;
139
+ }
140
+ else if ( baseOffset > 0 && pathBase [ baseOffset - 1 ] == '/'
141
+ && originalPath . AsSpan ( originalOffset ) . StartsWith ( "%2F" , StringComparison . OrdinalIgnoreCase ) )
142
+ {
143
+ // Duplicate slash equivalent, skip
144
+ originalOffset += 3 ;
145
+ }
146
+ else
147
+ {
148
+ // Mismatch, fall back
149
+ // The failing test case here is "/base/call//../bat//path1//path2", reduced to "/base/call/bat//path1//path2",
150
+ // where http.sys collapses "//" before "../", but we do "../" first. We've lost the context that there were dot segments,
151
+ // or duplicate slashes, how do we figure out that "call/" can be eliminated?
152
+ originalOffset = 0 ;
153
+ break ;
154
+ }
151
155
}
156
+ PathBase = originalPath [ ..originalOffset ] ;
157
+ Path = originalPath [ originalOffset ..] ;
152
158
}
153
- PathBase = originalPath [ ..originalOffset ] ;
154
- Path = originalPath [ originalOffset ..] ;
155
159
}
156
- }
157
- else if ( requestContext . Server . Options . UrlPrefixes . TryMatchLongestPrefix ( IsHttps , cookedUrl . GetHost ( ) ! , originalPath , out var pathBase , out var path ) )
158
- {
159
- PathBase = pathBase ;
160
- Path = path ;
161
- }
160
+ else if ( requestContext . Server . Options . UrlPrefixes . TryMatchLongestPrefix ( IsHttps , cookedUrl . GetHost ( ) ! , originalPath , out var pathBase , out var path ) )
161
+ {
162
+ PathBase = pathBase ;
163
+ Path = path ;
164
+ }
162
165
163
- ProtocolVersion = RequestContext . GetVersion ( ) ;
166
+ ProtocolVersion = RequestContext . GetVersion ( ) ;
164
167
165
- Headers = new RequestHeaders ( RequestContext ) ;
168
+ Headers = new RequestHeaders ( RequestContext ) ;
166
169
167
- User = RequestContext . GetUser ( ) ;
170
+ User = RequestContext . GetUser ( ) ;
168
171
169
- SniHostName = string . Empty ;
170
- if ( IsHttps )
171
- {
172
- GetTlsHandshakeResults ( ) ;
173
- }
172
+ SniHostName = string . Empty ;
173
+ if ( IsHttps )
174
+ {
175
+ GetTlsHandshakeResults ( ) ;
176
+ }
174
177
175
- // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231
178
+ // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231
176
179
177
- // Finished directly accessing the HTTP_REQUEST structure.
178
- RequestContext . ReleasePins ( ) ;
179
- // TODO: Verbose log parameters
180
+ }
181
+ finally
182
+ {
183
+ // Finished directly accessing the HTTP_REQUEST structure.
184
+ RequestContext . ReleasePins ( ) ;
185
+ // TODO: Verbose log parameters
186
+ }
180
187
181
188
RemoveContentLengthIfTransferEncodingContainsChunked ( ) ;
182
189
}
0 commit comments