115
115
116
116
use http:: { header, Request , Response , StatusCode } ;
117
117
use http_body:: Body ;
118
- use mime:: Mime ;
118
+ use mime:: { Mime , MimeIter } ;
119
119
use pin_project_lite:: pin_project;
120
120
use std:: {
121
121
fmt,
@@ -379,25 +379,24 @@ where
379
379
. headers ( )
380
380
. get_all ( header:: ACCEPT )
381
381
. into_iter ( )
382
- . flat_map ( |header| {
383
- header
384
- . to_str ( )
385
- . ok ( )
386
- . into_iter ( )
387
- . flat_map ( |s| s. split ( "," ) . map ( |typ| typ. trim ( ) ) )
388
- } )
382
+ . filter_map ( |header| header. to_str ( ) . ok ( ) )
389
383
. any ( |h| {
390
- h . parse :: < Mime > ( )
384
+ MimeIter :: new ( & h )
391
385
. map ( |mim| {
392
- let typ = self . header_value . type_ ( ) ;
393
- let subtype = self . header_value . subtype ( ) ;
394
- match ( mim. type_ ( ) , mim. subtype ( ) ) {
395
- ( t, s) if t == typ && s == subtype => true ,
396
- ( t, mime:: STAR ) if t == typ => true ,
397
- ( mime:: STAR , mime:: STAR ) => true ,
398
- _ => false ,
386
+ if let Ok ( mim) = mim {
387
+ let typ = self . header_value . type_ ( ) ;
388
+ let subtype = self . header_value . subtype ( ) ;
389
+ match ( mim. type_ ( ) , mim. subtype ( ) ) {
390
+ ( t, s) if t == typ && s == subtype => true ,
391
+ ( t, mime:: STAR ) if t == typ => true ,
392
+ ( mime:: STAR , mime:: STAR ) => true ,
393
+ _ => false ,
394
+ }
395
+ } else {
396
+ false
399
397
}
400
398
} )
399
+ . reduce ( |acc, mim| acc || mim)
401
400
. unwrap_or ( false )
402
401
} )
403
402
{
@@ -413,7 +412,7 @@ where
413
412
mod tests {
414
413
#[ allow( unused_imports) ]
415
414
use super :: * ;
416
- use http:: header;
415
+ use http:: { header, StatusCode } ;
417
416
use hyper:: Body ;
418
417
use tower:: { BoxError , ServiceBuilder , ServiceExt } ;
419
418
@@ -545,6 +544,40 @@ mod tests {
545
544
assert_eq ! ( res. status( ) , StatusCode :: OK ) ;
546
545
}
547
546
547
+ #[ tokio:: test]
548
+ async fn accepted_header_with_quotes_valid ( ) {
549
+ let value = "foo/bar; parisien=\" baguette, text/html, jambon, fromage\" , application/*" ;
550
+ let mut service = ServiceBuilder :: new ( )
551
+ . layer ( ValidateRequestHeaderLayer :: accept ( "application/xml" ) )
552
+ . service_fn ( echo) ;
553
+
554
+ let request = Request :: get ( "/" )
555
+ . header ( header:: ACCEPT , value)
556
+ . body ( Body :: empty ( ) )
557
+ . unwrap ( ) ;
558
+
559
+ let res = service. ready ( ) . await . unwrap ( ) . call ( request) . await . unwrap ( ) ;
560
+
561
+ assert_eq ! ( res. status( ) , StatusCode :: OK ) ;
562
+ }
563
+
564
+ #[ tokio:: test]
565
+ async fn accepted_header_with_quotes_invalid ( ) {
566
+ let value = "foo/bar; parisien=\" baguette, text/html, jambon, fromage\" " ;
567
+ let mut service = ServiceBuilder :: new ( )
568
+ . layer ( ValidateRequestHeaderLayer :: accept ( "text/html" ) )
569
+ . service_fn ( echo) ;
570
+
571
+ let request = Request :: get ( "/" )
572
+ . header ( header:: ACCEPT , value)
573
+ . body ( Body :: empty ( ) )
574
+ . unwrap ( ) ;
575
+
576
+ let res = service. ready ( ) . await . unwrap ( ) . call ( request) . await . unwrap ( ) ;
577
+
578
+ assert_eq ! ( res. status( ) , StatusCode :: NOT_ACCEPTABLE ) ;
579
+ }
580
+
548
581
async fn echo ( req : Request < Body > ) -> Result < Response < Body > , BoxError > {
549
582
Ok ( Response :: new ( req. into_body ( ) ) )
550
583
}
0 commit comments