@@ -5,26 +5,29 @@ use std::str::FromStr;
5
5
use async_dup:: { Arc , Mutex } ;
6
6
use async_std:: io:: { BufReader , Read , Write } ;
7
7
use async_std:: { prelude:: * , task} ;
8
- use http_types:: content:: ContentLength ;
9
- use http_types:: headers:: { EXPECT , TRANSFER_ENCODING } ;
10
- use http_types:: { ensure, ensure_eq, format_err} ;
8
+ use http_types:: { content:: ContentLength , Version } ;
9
+ use http_types:: { ensure, format_err} ;
10
+ use http_types:: {
11
+ headers:: { EXPECT , TRANSFER_ENCODING } ,
12
+ StatusCode ,
13
+ } ;
11
14
use http_types:: { Body , Method , Request , Url } ;
12
15
13
16
use super :: body_reader:: BodyReader ;
14
- use crate :: chunked:: ChunkedDecoder ;
15
17
use crate :: read_notifier:: ReadNotifier ;
18
+ use crate :: { chunked:: ChunkedDecoder , ServerOptions } ;
16
19
use crate :: { MAX_HEADERS , MAX_HEAD_LENGTH } ;
17
20
18
21
const LF : u8 = b'\n' ;
19
22
20
- /// The number returned from httparse when the request is HTTP 1.1
21
- const HTTP_1_1_VERSION : u8 = 1 ;
22
-
23
23
const CONTINUE_HEADER_VALUE : & str = "100-continue" ;
24
24
const CONTINUE_RESPONSE : & [ u8 ] = b"HTTP/1.1 100 Continue\r \n \r \n " ;
25
25
26
26
/// Decode an HTTP request on the server.
27
- pub async fn decode < IO > ( mut io : IO ) -> http_types:: Result < Option < ( Request , BodyReader < IO > ) > >
27
+ pub async fn decode < IO > (
28
+ mut io : IO ,
29
+ opts : & ServerOptions ,
30
+ ) -> http_types:: Result < Option < ( Request , BodyReader < IO > ) > >
28
31
where
29
32
IO : Read + Write + Clone + Send + Sync + Unpin + ' static ,
30
33
{
@@ -63,21 +66,22 @@ where
63
66
let method = httparse_req. method ;
64
67
let method = method. ok_or_else ( || format_err ! ( "No method found" ) ) ?;
65
68
66
- let version = httparse_req. version ;
67
- let version = version . ok_or_else ( || format_err ! ( "No version found" ) ) ? ;
68
-
69
- ensure_eq ! (
70
- version,
71
- HTTP_1_1_VERSION ,
72
- "Unsupported HTTP version 1.{}" ,
73
- version
74
- ) ;
69
+ let version = match ( & opts . default_host , httparse_req. version ) {
70
+ ( Some ( _ ) , None ) | ( Some ( _ ) , Some ( 0 ) ) => Version :: Http1_0 ,
71
+ ( _ , Some ( 1 ) ) => Version :: Http1_1 ,
72
+ _ => {
73
+ let mut err = format_err ! ( "http version not supported" ) ;
74
+ err . set_status ( StatusCode :: HttpVersionNotSupported ) ;
75
+ return Err ( err ) ;
76
+ }
77
+ } ;
75
78
76
- let url = url_from_httparse_req ( & httparse_req) ?;
79
+ let url = url_from_httparse_req ( & httparse_req, opts. default_host . as_deref ( ) )
80
+ . ok_or_else ( || format_err ! ( "unable to construct url from request" ) ) ?;
77
81
78
82
let mut req = Request :: new ( Method :: from_str ( method) ?, url) ;
79
83
80
- req. set_version ( Some ( http_types :: Version :: Http1_1 ) ) ;
84
+ req. set_version ( Some ( version ) ) ;
81
85
82
86
for header in httparse_req. headers . iter ( ) {
83
87
req. append_header ( header. name , std:: str:: from_utf8 ( header. value ) ?) ;
@@ -141,26 +145,27 @@ where
141
145
}
142
146
}
143
147
144
- fn url_from_httparse_req ( req : & httparse:: Request < ' _ , ' _ > ) -> http_types:: Result < Url > {
145
- let path = req. path . ok_or_else ( || format_err ! ( "No uri found" ) ) ?;
148
+ fn url_from_httparse_req (
149
+ req : & httparse:: Request < ' _ , ' _ > ,
150
+ default_host : Option < & str > ,
151
+ ) -> Option < Url > {
152
+ let path = req. path ?;
146
153
147
154
let host = req
148
155
. headers
149
156
. iter ( )
150
157
. find ( |x| x. name . eq_ignore_ascii_case ( "host" ) )
151
- . ok_or_else ( || format_err ! ( "Mandatory Host header missing" ) ) ?
152
- . value ;
153
-
154
- let host = std:: str:: from_utf8 ( host) ?;
158
+ . and_then ( |x| std:: str:: from_utf8 ( x. value ) . ok ( ) )
159
+ . or ( default_host) ?;
155
160
156
161
if path. starts_with ( "http://" ) || path. starts_with ( "https://" ) {
157
- Ok ( Url :: parse ( path) ? )
162
+ Url :: parse ( path) . ok ( )
158
163
} else if path. starts_with ( '/' ) {
159
- Ok ( Url :: parse ( & format ! ( "http://{}{}" , host, path) ) ? )
164
+ Url :: parse ( & format ! ( "http://{}{}" , host, path) ) . ok ( )
160
165
} else if req. method . unwrap ( ) . eq_ignore_ascii_case ( "connect" ) {
161
- Ok ( Url :: parse ( & format ! ( "http://{}/" , path) ) ? )
166
+ Url :: parse ( & format ! ( "http://{}/" , path) ) . ok ( )
162
167
} else {
163
- Err ( format_err ! ( "unexpected uri format" ) )
168
+ None
164
169
}
165
170
}
166
171
@@ -180,7 +185,7 @@ mod tests {
180
185
httparse_req (
181
186
"CONNECT server.example.com:443 HTTP/1.1\r \n Host: server.example.com:443\r \n " ,
182
187
|req| {
183
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
188
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
184
189
assert_eq ! ( url. as_str( ) , "http://server.example.com:443/" ) ;
185
190
} ,
186
191
) ;
@@ -191,7 +196,7 @@ mod tests {
191
196
httparse_req (
192
197
"GET /some/resource HTTP/1.1\r \n Host: server.example.com:443\r \n " ,
193
198
|req| {
194
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
199
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
195
200
assert_eq ! ( url. as_str( ) , "http://server.example.com:443/some/resource" ) ;
196
201
} ,
197
202
)
@@ -202,7 +207,7 @@ mod tests {
202
207
httparse_req (
203
208
"GET http://domain.com/some/resource HTTP/1.1\r \n Host: server.example.com\r \n " ,
204
209
|req| {
205
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
210
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
206
211
assert_eq ! ( url. as_str( ) , "http://domain.com/some/resource" ) ; // host header MUST be ignored according to spec
207
212
} ,
208
213
)
@@ -213,7 +218,7 @@ mod tests {
213
218
httparse_req (
214
219
"CONNECT server.example.com:443 HTTP/1.1\r \n Host: conflicting.host\r \n " ,
215
220
|req| {
216
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
221
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
217
222
assert_eq ! ( url. as_str( ) , "http://server.example.com:443/" ) ;
218
223
} ,
219
224
)
@@ -224,7 +229,7 @@ mod tests {
224
229
httparse_req (
225
230
"GET not-a-url HTTP/1.1\r \n Host: server.example.com\r \n " ,
226
231
|req| {
227
- assert ! ( url_from_httparse_req( & req) . is_err ( ) ) ;
232
+ assert ! ( url_from_httparse_req( & req, None ) . is_none ( ) ) ;
228
233
} ,
229
234
)
230
235
}
@@ -234,7 +239,7 @@ mod tests {
234
239
httparse_req (
235
240
"GET //double/slashes HTTP/1.1\r \n Host: server.example.com:443\r \n " ,
236
241
|req| {
237
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
242
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
238
243
assert_eq ! (
239
244
url. as_str( ) ,
240
245
"http://server.example.com:443//double/slashes"
@@ -247,7 +252,7 @@ mod tests {
247
252
httparse_req (
248
253
"GET ///triple/slashes HTTP/1.1\r \n Host: server.example.com:443\r \n " ,
249
254
|req| {
250
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
255
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
251
256
assert_eq ! (
252
257
url. as_str( ) ,
253
258
"http://server.example.com:443///triple/slashes"
@@ -261,7 +266,7 @@ mod tests {
261
266
httparse_req (
262
267
"GET /foo?bar=1 HTTP/1.1\r \n Host: server.example.com:443\r \n " ,
263
268
|req| {
264
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
269
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
265
270
assert_eq ! ( url. as_str( ) , "http://server.example.com:443/foo?bar=1" ) ;
266
271
} ,
267
272
)
@@ -272,7 +277,7 @@ mod tests {
272
277
httparse_req (
273
278
"GET /foo?bar=1#anchor HTTP/1.1\r \n Host: server.example.com:443\r \n " ,
274
279
|req| {
275
- let url = url_from_httparse_req ( & req) . unwrap ( ) ;
280
+ let url = url_from_httparse_req ( & req, None ) . unwrap ( ) ;
276
281
assert_eq ! (
277
282
url. as_str( ) ,
278
283
"http://server.example.com:443/foo?bar=1#anchor"
0 commit comments