@@ -5,12 +5,13 @@ use std::io::{self, Read, Write, BufRead};
5
5
6
6
use httparse;
7
7
8
+ use buffer:: BufReader ;
8
9
use header:: Headers ;
9
10
use method:: Method ;
10
11
use uri:: RequestUri ;
11
12
use version:: HttpVersion :: { self , Http10 , Http11 } ;
12
13
use HttpError :: HttpTooLargeError ;
13
- use HttpResult ;
14
+ use { HttpError , HttpResult } ;
14
15
15
16
use self :: HttpReader :: { SizedReader , ChunkedReader , EofReader , EmptyReader } ;
16
17
use self :: HttpWriter :: { ThroughWriter , ChunkedWriter , SizedWriter , EmptyWriter } ;
@@ -307,56 +308,88 @@ impl<W: Write> Write for HttpWriter<W> {
307
308
}
308
309
}
309
310
311
+ const MAX_HEADERS : usize = 100 ;
312
+
310
313
/// Parses a request into an Incoming message head.
311
- pub fn parse_request < T : BufRead > ( buf : & mut T ) -> HttpResult < Incoming < ( Method , RequestUri ) > > {
312
- let ( inc, len) = {
313
- let slice = try!( buf. fill_buf ( ) ) ;
314
- let mut headers = [ httparse:: Header { name : "" , value : b"" } ; 64 ] ;
315
- let mut req = httparse:: Request :: new ( & mut headers) ;
316
- match try!( req. parse ( slice) ) {
314
+ #[ inline]
315
+ pub fn parse_request < R : Read > ( buf : & mut BufReader < R > ) -> HttpResult < Incoming < ( Method , RequestUri ) > > {
316
+ parse :: < R , httparse:: Request , ( Method , RequestUri ) > ( buf)
317
+ }
318
+
319
+ /// Parses a response into an Incoming message head.
320
+ #[ inline]
321
+ pub fn parse_response < R : Read > ( buf : & mut BufReader < R > ) -> HttpResult < Incoming < RawStatus > > {
322
+ parse :: < R , httparse:: Response , RawStatus > ( buf)
323
+ }
324
+
325
+ fn parse < R : Read , T : TryParse < Subject =I > , I > ( rdr : & mut BufReader < R > ) -> HttpResult < Incoming < I > > {
326
+ loop {
327
+ match try!( try_parse :: < R , T , I > ( rdr) ) {
328
+ httparse:: Status :: Complete ( ( inc, len) ) => {
329
+ rdr. consume ( len) ;
330
+ return Ok ( inc) ;
331
+ } ,
332
+ _partial => ( )
333
+ }
334
+ match try!( rdr. read_into_buf ( ) ) {
335
+ 0 => return Err ( HttpTooLargeError ) ,
336
+ _ => ( )
337
+ }
338
+ }
339
+ }
340
+
341
+ fn try_parse < R : Read , T : TryParse < Subject =I > , I > ( rdr : & mut BufReader < R > ) -> TryParseResult < I > {
342
+ let mut headers = [ httparse:: EMPTY_HEADER ; MAX_HEADERS ] ;
343
+ <T as TryParse >:: try_parse ( & mut headers, rdr. get_buf ( ) )
344
+ }
345
+
346
+ #[ doc( hidden) ]
347
+ trait TryParse {
348
+ type Subject ;
349
+ fn try_parse < ' a > ( headers : & ' a mut [ httparse:: Header < ' a > ] , buf : & ' a [ u8 ] ) -> TryParseResult < Self :: Subject > ;
350
+ }
351
+
352
+ type TryParseResult < T > = Result < httparse:: Status < ( Incoming < T > , usize ) > , HttpError > ;
353
+
354
+ impl < ' a > TryParse for httparse:: Request < ' a > {
355
+ type Subject = ( Method , RequestUri ) ;
356
+
357
+ fn try_parse < ' b > ( headers : & ' b mut [ httparse:: Header < ' b > ] , buf : & ' b [ u8 ] ) -> TryParseResult < ( Method , RequestUri ) > {
358
+ let mut req = httparse:: Request :: new ( headers) ;
359
+ Ok ( match try!( req. parse ( buf) ) {
317
360
httparse:: Status :: Complete ( len) => {
318
- ( Incoming {
361
+ httparse :: Status :: Complete ( ( Incoming {
319
362
version : if req. version . unwrap ( ) == 1 { Http11 } else { Http10 } ,
320
363
subject : (
321
364
try!( req. method . unwrap ( ) . parse ( ) ) ,
322
365
try!( req. path . unwrap ( ) . parse ( ) )
323
366
) ,
324
367
headers : try!( Headers :: from_raw ( req. headers ) )
325
- } , len)
368
+ } , len) )
326
369
} ,
327
- _ => {
328
- // request head is bigger than a BufRead's buffer? 400 that!
329
- return Err ( HttpTooLargeError )
330
- }
331
- }
332
- } ;
333
- buf. consume ( len) ;
334
- Ok ( inc)
370
+ httparse:: Status :: Partial => httparse:: Status :: Partial
371
+ } )
372
+ }
335
373
}
336
374
337
- /// Parses a response into an Incoming message head.
338
- pub fn parse_response < T : BufRead > ( buf : & mut T ) -> HttpResult < Incoming < RawStatus > > {
339
- let ( inc , len ) = {
340
- let mut headers = [ httparse:: Header { name : "" , value : b"" } ; 64 ] ;
341
- let mut res = httparse:: Response :: new ( & mut headers) ;
342
- match try!( res. parse ( try! ( buf. fill_buf ( ) ) ) ) {
375
+ impl < ' a > TryParse for httparse :: Response < ' a > {
376
+ type Subject = RawStatus ;
377
+
378
+ fn try_parse < ' b > ( headers : & ' b mut [ httparse:: Header < ' b > ] , buf : & ' b [ u8 ] ) -> TryParseResult < RawStatus > {
379
+ let mut res = httparse:: Response :: new ( headers) ;
380
+ Ok ( match try!( res. parse ( buf) ) {
343
381
httparse:: Status :: Complete ( len) => {
344
- ( Incoming {
382
+ httparse :: Status :: Complete ( ( Incoming {
345
383
version : if res. version . unwrap ( ) == 1 { Http11 } else { Http10 } ,
346
384
subject : RawStatus (
347
385
res. code . unwrap ( ) , res. reason . unwrap ( ) . to_owned ( ) . into_cow ( )
348
386
) ,
349
387
headers : try!( Headers :: from_raw ( res. headers ) )
350
- } , len)
388
+ } , len) )
351
389
} ,
352
- _ => {
353
- // response head is bigger than a BufRead's buffer?
354
- return Err ( HttpTooLargeError )
355
- }
356
- }
357
- } ;
358
- buf. consume ( len) ;
359
- Ok ( inc)
390
+ httparse:: Status :: Partial => httparse:: Status :: Partial
391
+ } )
392
+ }
360
393
}
361
394
362
395
/// An Incoming Message head. Includes request/status line, and headers.
@@ -456,19 +489,30 @@ mod tests {
456
489
read_err ( "1;no CRLF" ) ;
457
490
}
458
491
492
+ #[ test]
493
+ fn test_parse_incoming ( ) {
494
+ use buffer:: BufReader ;
495
+ use mock:: MockStream ;
496
+
497
+ use super :: parse_request;
498
+ let mut raw = MockStream :: with_input ( b"GET /echo HTTP/1.1\r \n Host: hyper.rs\r \n \r \n " ) ;
499
+ let mut buf = BufReader :: new ( & mut raw) ;
500
+ parse_request ( & mut buf) . unwrap ( ) ;
501
+ }
502
+
459
503
use test:: Bencher ;
460
504
461
505
#[ bench]
462
506
fn bench_parse_incoming ( b : & mut Bencher ) {
463
- use std :: io :: BufReader ;
507
+ use buffer :: BufReader ;
464
508
use mock:: MockStream ;
465
509
466
510
use super :: parse_request;
511
+ let mut raw = MockStream :: with_input ( b"GET /echo HTTP/1.1\r \n Host: hyper.rs\r \n \r \n " ) ;
512
+ let mut buf = BufReader :: new ( & mut raw) ;
467
513
b. iter ( || {
468
- let mut raw = MockStream :: with_input ( b"GET /echo HTTP/1.1\r \n Host: hyper.rs\r \n \r \n " ) ;
469
- let mut buf = BufReader :: new ( & mut raw) ;
470
-
471
514
parse_request ( & mut buf) . unwrap ( ) ;
515
+ buf. get_mut ( ) . read . set_position ( 0 ) ;
472
516
} ) ;
473
517
}
474
518
}
0 commit comments