1
1
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
+ use std:: collections:: HashMap ;
4
5
use std:: result:: Result ;
5
6
6
7
use crate :: HttpHeaderError ;
@@ -94,6 +95,8 @@ pub struct Headers {
94
95
/// `Accept` header might be used by HTTP clients to enforce server responses with content
95
96
/// formatted in a specific way.
96
97
accept : MediaType ,
98
+ /// Hashmap reserved for storing custom headers.
99
+ custom_entries : HashMap < String , String > ,
97
100
}
98
101
99
102
impl Default for Headers {
@@ -106,6 +109,7 @@ impl Default for Headers {
106
109
// The default `Accept` media type is plain text. This is inclusive enough
107
110
// for structured and unstructured text.
108
111
accept : MediaType :: PlainText ,
112
+ custom_entries : HashMap :: default ( ) ,
109
113
}
110
114
}
111
115
}
@@ -206,12 +210,11 @@ impl Headers {
206
210
Header :: AcceptEncoding => Encoding :: try_from ( entry[ 1 ] . trim ( ) . as_bytes ( ) ) ,
207
211
}
208
212
} else {
209
- Err ( RequestError :: HeaderError (
210
- HttpHeaderError :: UnsupportedValue (
211
- entry[ 0 ] . to_string ( ) ,
212
- entry[ 1 ] . to_string ( ) ,
213
- ) ,
214
- ) )
213
+ self . insert_custom_header (
214
+ entry[ 0 ] . trim ( ) . to_string ( ) ,
215
+ entry[ 1 ] . trim ( ) . to_string ( ) ,
216
+ ) ?;
217
+ Ok ( ( ) )
215
218
}
216
219
}
217
220
Err ( utf8_err) => Err ( RequestError :: HeaderError (
@@ -289,6 +292,17 @@ impl Headers {
289
292
pub fn set_accept ( & mut self , media_type : MediaType ) {
290
293
self . accept = media_type;
291
294
}
295
+
296
+ /// Insert a new custom header and value pair into the `HashMap`.
297
+ pub fn insert_custom_header ( & mut self , key : String , value : String ) -> Result < ( ) , RequestError > {
298
+ self . custom_entries . insert ( key, value) ;
299
+ Ok ( ( ) )
300
+ }
301
+
302
+ /// Returns the custom header `HashMap`.
303
+ pub fn custom_entries ( & self ) -> & HashMap < String , String > {
304
+ & self . custom_entries
305
+ }
292
306
}
293
307
294
308
/// Wrapper over supported AcceptEncoding.
@@ -414,6 +428,7 @@ impl MediaType {
414
428
#[ cfg( test) ]
415
429
mod tests {
416
430
use super :: * ;
431
+ use std:: collections:: HashMap ;
417
432
418
433
impl Headers {
419
434
pub fn new ( content_length : u32 , expect : bool , chunked : bool ) -> Self {
@@ -422,6 +437,7 @@ mod tests {
422
437
expect,
423
438
chunked,
424
439
accept : MediaType :: PlainText ,
440
+ custom_entries : HashMap :: default ( ) ,
425
441
}
426
442
}
427
443
}
@@ -433,6 +449,7 @@ mod tests {
433
449
assert_eq ! ( headers. chunked( ) , false ) ;
434
450
assert_eq ! ( headers. expect( ) , false ) ;
435
451
assert_eq ! ( headers. accept( ) , MediaType :: PlainText ) ;
452
+ assert_eq ! ( headers. custom_entries( ) , & HashMap :: default ( ) ) ;
436
453
}
437
454
438
455
#[ test]
@@ -512,6 +529,11 @@ mod tests {
512
529
. unwrap ( ) ;
513
530
assert_eq ! ( headers. content_length, 55 ) ;
514
531
assert_eq ! ( headers. accept, MediaType :: ApplicationJson ) ;
532
+ assert_eq ! (
533
+ headers. custom_entries( ) . get( "Last-Modified" ) . unwrap( ) ,
534
+ "Tue, 15 Nov 1994 12:45:26 GMT"
535
+ ) ;
536
+ assert_eq ! ( headers. custom_entries( ) . len( ) , 1 ) ;
515
537
516
538
// Valid headers. (${HEADER_NAME} : WHITESPACE ${HEADER_VALUE})
517
539
// Any number of whitespace characters should be accepted including zero.
@@ -529,7 +551,17 @@ mod tests {
529
551
. unwrap ( ) ;
530
552
assert_eq ! ( headers. content_length, 29 ) ;
531
553
532
- // Valid headers.
554
+ // Custom headers only.
555
+ let headers = Headers :: try_from (
556
+ b"Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r \n foo: bar\r \n bar: 15\r \n \r \n " ,
557
+ )
558
+ . unwrap ( ) ;
559
+ let custom_entries = headers. custom_entries ( ) ;
560
+ assert_eq ! ( custom_entries. get( "foo" ) . unwrap( ) , "bar" ) ;
561
+ assert_eq ! ( custom_entries. get( "bar" ) . unwrap( ) , "15" ) ;
562
+ assert_eq ! ( custom_entries. len( ) , 3 ) ;
563
+
564
+ // Valid headers, invalid value.
533
565
assert_eq ! (
534
566
Headers :: try_from(
535
567
b"Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r \n Content-Length: -55\r \n \r \n "
@@ -656,6 +688,15 @@ mod tests {
656
688
" identity;q=0" . to_string( )
657
689
) ) )
658
690
) ;
691
+
692
+ // Test custom header.
693
+ assert_eq ! ( header. custom_entries( ) . len( ) , 0 ) ;
694
+ assert ! ( header. parse_header_line( b"Custom-Header: foo" ) . is_ok( ) ) ;
695
+ assert_eq ! (
696
+ header. custom_entries( ) . get( "Custom-Header" ) . unwrap( ) ,
697
+ & "foo" . to_string( )
698
+ ) ;
699
+ assert_eq ! ( header. custom_entries( ) . len( ) , 1 ) ;
659
700
}
660
701
661
702
#[ test]
@@ -697,6 +738,13 @@ mod tests {
697
738
// For Expect
698
739
assert ! ( header. parse_header_line( b"Expect:100-continue" ) . is_ok( ) ) ;
699
740
assert ! ( header. parse_header_line( b"Expect: 100-continue" ) . is_ok( ) ) ;
741
+
742
+ // Test that custom headers' names and values are trimmed before being stored
743
+ // inside the HashMap.
744
+ assert ! ( header. parse_header_line( b"Foo:bar" ) . is_ok( ) ) ;
745
+ assert_eq ! ( header. custom_entries( ) . get( "Foo" ) . unwrap( ) , "bar" ) ;
746
+ assert ! ( header. parse_header_line( b" Bar : foo " ) . is_ok( ) ) ;
747
+ assert_eq ! ( header. custom_entries( ) . get( "Bar" ) . unwrap( ) , "foo" ) ;
700
748
}
701
749
702
750
#[ test]
0 commit comments