@@ -126,6 +126,7 @@ where
126
126
mut head : MessageHead < Self :: Outgoing > ,
127
127
body : Option < BodyLength > ,
128
128
method : & mut Option < Method > ,
129
+ _title_case_headers : bool ,
129
130
dst : & mut Vec < u8 > ,
130
131
) -> :: Result < Encoder > {
131
132
trace ! ( "Server::encode body={:?}, method={:?}" , body, method) ;
@@ -367,6 +368,7 @@ where
367
368
mut head : MessageHead < Self :: Outgoing > ,
368
369
body : Option < BodyLength > ,
369
370
method : & mut Option < Method > ,
371
+ title_case_headers : bool ,
370
372
dst : & mut Vec < u8 > ,
371
373
) -> :: Result < Encoder > {
372
374
trace ! ( "Client::encode body={:?}, method={:?}" , body, method) ;
@@ -391,7 +393,11 @@ where
391
393
}
392
394
extend ( dst, b"\r \n " ) ;
393
395
394
- write_headers ( & head. headers , dst) ;
396
+ if title_case_headers {
397
+ write_headers_title_case ( & head. headers , dst) ;
398
+ } else {
399
+ write_headers ( & head. headers , dst) ;
400
+ }
395
401
extend ( dst, b"\r \n " ) ;
396
402
397
403
Ok ( body)
@@ -635,6 +641,44 @@ impl<'a> Iterator for HeadersAsBytesIter<'a> {
635
641
}
636
642
}
637
643
644
+ // Write header names as title case. The header name is assumed to be ASCII,
645
+ // therefore it is trivial to convert an ASCII character from lowercase to
646
+ // uppercase. It is as simple as XORing the lowercase character byte with
647
+ // space.
648
+ fn title_case ( dst : & mut Vec < u8 > , name : & [ u8 ] ) {
649
+ dst. reserve ( name. len ( ) ) ;
650
+
651
+ let mut iter = name. iter ( ) ;
652
+
653
+ // Uppercase the first character
654
+ if let Some ( c) = iter. next ( ) {
655
+ if * c >= b'a' && * c <= b'z' {
656
+ dst. push ( * c ^ b' ' ) ;
657
+ }
658
+ }
659
+
660
+ while let Some ( c) = iter. next ( ) {
661
+ dst. push ( * c) ;
662
+
663
+ if * c == b'-' {
664
+ if let Some ( c) = iter. next ( ) {
665
+ if * c >= b'a' && * c <= b'z' {
666
+ dst. push ( * c ^ b' ' ) ;
667
+ }
668
+ }
669
+ }
670
+ }
671
+ }
672
+
673
+ fn write_headers_title_case ( headers : & HeaderMap , dst : & mut Vec < u8 > ) {
674
+ for ( name, value) in headers {
675
+ title_case ( dst, name. as_str ( ) . as_bytes ( ) ) ;
676
+ extend ( dst, b": " ) ;
677
+ extend ( dst, value. as_bytes ( ) ) ;
678
+ extend ( dst, b"\r \n " ) ;
679
+ }
680
+ }
681
+
638
682
fn write_headers ( headers : & HeaderMap , dst : & mut Vec < u8 > ) {
639
683
for ( name, value) in headers {
640
684
extend ( dst, name. as_str ( ) . as_bytes ( ) ) ;
@@ -857,6 +901,21 @@ mod tests {
857
901
Client :: decoder ( & head, method) . unwrap_err ( ) ;
858
902
}
859
903
904
+ #[ test]
905
+ fn test_client_request_encode_title_case ( ) {
906
+ use http:: header:: HeaderValue ;
907
+ use proto:: BodyLength ;
908
+
909
+ let mut head = MessageHead :: default ( ) ;
910
+ head. headers . insert ( "content-length" , HeaderValue :: from_static ( "10" ) ) ;
911
+ head. headers . insert ( "content-type" , HeaderValue :: from_static ( "application/json" ) ) ;
912
+
913
+ let mut vec = Vec :: new ( ) ;
914
+ Client :: encode ( head, Some ( BodyLength :: Known ( 10 ) ) , & mut None , true , & mut vec) . unwrap ( ) ;
915
+
916
+ assert_eq ! ( vec, b"GET / HTTP/1.1\r \n Content-Length: 10\r \n Content-Type: application/json\r \n \r \n " . to_vec( ) ) ;
917
+ }
918
+
860
919
#[ cfg( feature = "nightly" ) ]
861
920
use test:: Bencher ;
862
921
@@ -914,7 +973,7 @@ mod tests {
914
973
915
974
b. iter ( || {
916
975
let mut vec = Vec :: new ( ) ;
917
- Server :: encode ( head. clone ( ) , Some ( BodyLength :: Known ( 10 ) ) , & mut None , & mut vec) . unwrap ( ) ;
976
+ Server :: encode ( head. clone ( ) , Some ( BodyLength :: Known ( 10 ) ) , & mut None , false , & mut vec) . unwrap ( ) ;
918
977
assert_eq ! ( vec. len( ) , len) ;
919
978
:: test:: black_box ( vec) ;
920
979
} )
0 commit comments