@@ -21,6 +21,8 @@ pub enum Header {
21
21
Server ,
22
22
/// Header `Accept`
23
23
Accept ,
24
+ /// Header `Accept-Encoding`
25
+ AcceptEncoding ,
24
26
}
25
27
26
28
impl Header {
@@ -33,6 +35,7 @@ impl Header {
33
35
Self :: TransferEncoding => b"Transfer-Encoding" ,
34
36
Self :: Server => b"Server" ,
35
37
Self :: Accept => b"Accept" ,
38
+ Self :: AcceptEncoding => b"Accept-Encoding" ,
36
39
}
37
40
}
38
41
@@ -52,6 +55,7 @@ impl Header {
52
55
"transfer-encoding" => Ok ( Self :: TransferEncoding ) ,
53
56
"server" => Ok ( Self :: Server ) ,
54
57
"accept" => Ok ( Self :: Accept ) ,
58
+ "accept-encoding" => Ok ( Self :: AcceptEncoding ) ,
55
59
invalid_key => Err ( RequestError :: HeaderError ( HttpHeaderError :: UnsupportedName (
56
60
invalid_key. to_string ( ) ,
57
61
) ) ) ,
@@ -199,6 +203,7 @@ impl Headers {
199
203
) ) ,
200
204
} ,
201
205
Header :: Server => Ok ( ( ) ) ,
206
+ Header :: AcceptEncoding => Encoding :: try_from ( entry[ 1 ] . trim ( ) . as_bytes ( ) ) ,
202
207
}
203
208
} else {
204
209
Err ( RequestError :: HeaderError (
@@ -286,6 +291,63 @@ impl Headers {
286
291
}
287
292
}
288
293
294
+ /// Wrapper over supported AcceptEncoding.
295
+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
296
+ pub struct Encoding { }
297
+
298
+ impl Encoding {
299
+ /// Parses a byte slice and checks if identity encoding is invalidated. Encoding
300
+ /// must be ASCII, so also UTF-8 valid.
301
+ ///
302
+ /// # Errors
303
+ /// `InvalidRequest` is returned when the byte stream is empty.
304
+ ///
305
+ /// `InvalidValue` is returned when the identity encoding is invalidated.
306
+ ///
307
+ /// `InvalidUtf8String` is returned when the byte stream contains invalid characters.
308
+ ///
309
+ /// # Examples
310
+ ///
311
+ /// ```
312
+ /// use micro_http::Encoding;
313
+ ///
314
+ /// assert!(Encoding::try_from(b"deflate").is_ok());
315
+ /// assert!(Encoding::try_from(b"identity;q=0").is_err());
316
+ /// ```
317
+ pub fn try_from ( bytes : & [ u8 ] ) -> Result < ( ) , RequestError > {
318
+ if bytes. is_empty ( ) {
319
+ return Err ( RequestError :: InvalidRequest ) ;
320
+ }
321
+ match std:: str:: from_utf8 ( bytes) {
322
+ Ok ( headers_str) => {
323
+ let entry = headers_str. split ( ',' ) . collect :: < Vec < & str > > ( ) ;
324
+
325
+ for encoding in entry {
326
+ match encoding. trim ( ) {
327
+ "identity;q=0" => {
328
+ Err ( RequestError :: HeaderError ( HttpHeaderError :: InvalidValue (
329
+ "Accept-Encoding" . to_string ( ) ,
330
+ encoding. to_string ( ) ,
331
+ ) ) )
332
+ }
333
+ "*;q=0" if !headers_str. contains ( "identity" ) => {
334
+ Err ( RequestError :: HeaderError ( HttpHeaderError :: InvalidValue (
335
+ "Accept-Encoding" . to_string ( ) ,
336
+ encoding. to_string ( ) ,
337
+ ) ) )
338
+ }
339
+ _ => Ok ( ( ) ) ,
340
+ } ?;
341
+ }
342
+ Ok ( ( ) )
343
+ }
344
+ Err ( utf8_err) => Err ( RequestError :: HeaderError (
345
+ HttpHeaderError :: InvalidUtf8String ( utf8_err) ,
346
+ ) ) ,
347
+ }
348
+ }
349
+ }
350
+
289
351
/// Wrapper over supported Media Types.
290
352
#[ derive( Clone , Copy , Debug , PartialEq ) ]
291
353
pub enum MediaType {
@@ -404,6 +466,42 @@ mod tests {
404
466
assert_eq ! ( media_type. as_str( ) , "text/plain" ) ;
405
467
}
406
468
469
+ #[ test]
470
+ fn test_try_from_encoding ( ) {
471
+ assert_eq ! (
472
+ Encoding :: try_from( b"" ) . unwrap_err( ) ,
473
+ RequestError :: InvalidRequest
474
+ ) ;
475
+
476
+ assert_eq ! (
477
+ Encoding :: try_from( b"identity;q=0" ) . unwrap_err( ) ,
478
+ RequestError :: HeaderError ( HttpHeaderError :: InvalidValue (
479
+ "Accept-Encoding" . to_string( ) ,
480
+ "identity;q=0" . to_string( )
481
+ ) )
482
+ ) ;
483
+
484
+ assert ! ( Encoding :: try_from( b"identity;q" ) . is_ok( ) ) ;
485
+
486
+ assert_eq ! (
487
+ Encoding :: try_from( b"*;q=0" ) . unwrap_err( ) ,
488
+ RequestError :: HeaderError ( HttpHeaderError :: InvalidValue (
489
+ "Accept-Encoding" . to_string( ) ,
490
+ "*;q=0" . to_string( )
491
+ ) )
492
+ ) ;
493
+
494
+ let bytes: [ u8 ; 10 ] = [ 130 , 140 , 150 , 130 , 140 , 150 , 130 , 140 , 150 , 160 ] ;
495
+ assert ! ( Encoding :: try_from( & bytes[ ..] ) . is_err( ) ) ;
496
+
497
+ assert ! ( Encoding :: try_from( b"identity;q=1" ) . is_ok( ) ) ;
498
+ assert ! ( Encoding :: try_from( b"identity;q=0.1" ) . is_ok( ) ) ;
499
+ assert ! ( Encoding :: try_from( b"deflate, identity, *;q=0" ) . is_ok( ) ) ;
500
+ assert ! ( Encoding :: try_from( b"br" ) . is_ok( ) ) ;
501
+ assert ! ( Encoding :: try_from( b"compress" ) . is_ok( ) ) ;
502
+ assert ! ( Encoding :: try_from( b"gzip" ) . is_ok( ) ) ;
503
+ }
504
+
407
505
#[ test]
408
506
fn test_try_from_headers ( ) {
409
507
// Valid headers.
@@ -526,9 +624,9 @@ mod tests {
526
624
assert ! ( header
527
625
. parse_header_line( b"Accept: application/json" )
528
626
. is_ok( ) ) ;
529
- assert ! ( header. accept == MediaType :: ApplicationJson ) ;
627
+ assert_eq ! ( header. accept, MediaType :: ApplicationJson ) ;
530
628
assert ! ( header. parse_header_line( b"Accept: text/plain" ) . is_ok( ) ) ;
531
- assert ! ( header. accept == MediaType :: PlainText ) ;
629
+ assert_eq ! ( header. accept, MediaType :: PlainText ) ;
532
630
533
631
// Test invalid accept media type.
534
632
assert ! ( header
@@ -543,6 +641,17 @@ mod tests {
543
641
" -1" . to_string( )
544
642
) ) )
545
643
) ;
644
+
645
+ assert ! ( header
646
+ . parse_header_line( b"Accept-Encoding: deflate" )
647
+ . is_ok( ) ) ;
648
+ assert_eq ! (
649
+ header. parse_header_line( b"Accept-Encoding: compress, identity;q=0" ) ,
650
+ Err ( RequestError :: HeaderError ( HttpHeaderError :: InvalidValue (
651
+ "Accept-Encoding" . to_string( ) ,
652
+ " identity;q=0" . to_string( )
653
+ ) ) )
654
+ ) ;
546
655
}
547
656
548
657
#[ test]
0 commit comments