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