11/// Traits for converting between the various types
22pub mod conversions;
33
4+ use std:: collections:: HashMap ;
5+
46#[ doc( inline) ]
57pub use conversions:: IntoResponse ;
68
@@ -21,17 +23,32 @@ pub struct Request {
2123 /// The first item is set to `None` if the supplied uri is malformed
2224 uri : ( Option < hyperium:: Uri > , String ) ,
2325 /// The request headers
24- headers : Vec < ( String , String ) > ,
26+ headers : HashMap < String , HeaderValue > ,
2527 /// The request body as bytes
2628 body : Vec < u8 > ,
2729}
2830
31+ enum HeaderValue {
32+ String ( String ) ,
33+ Bytes ( Vec < u8 > ) ,
34+ }
35+
36+ impl HeaderValue {
37+ /// Turn the `HeaderValue` into bytes
38+ fn into_bytes ( self ) -> Vec < u8 > {
39+ match self {
40+ HeaderValue :: String ( s) => s. into_bytes ( ) ,
41+ HeaderValue :: Bytes ( b) => b,
42+ }
43+ }
44+ }
45+
2946impl Request {
3047 fn new ( method : Method , uri : impl Into < String > ) -> Self {
3148 Self {
3249 method,
3350 uri : Self :: parse_uri ( uri. into ( ) ) ,
34- headers : Vec :: new ( ) ,
51+ headers : HashMap :: new ( ) ,
3552 body : Vec :: new ( ) ,
3653 }
3754 }
@@ -61,13 +78,33 @@ impl Request {
6178 }
6279
6380 /// The request headers
64- pub fn headers ( & self ) -> & [ ( String , String ) ] {
65- & self . headers
81+ ///
82+ /// This only returns headers that are utf8 encoded
83+ pub fn headers ( & self ) -> impl Iterator < Item = ( & str , & str ) > {
84+ self . headers . iter ( ) . filter_map ( |( k, v) | match v {
85+ HeaderValue :: String ( v) => Some ( ( k. as_str ( ) , v. as_str ( ) ) ) ,
86+ HeaderValue :: Bytes ( _) => None ,
87+ } )
6688 }
6789
68- /// The request headers
69- pub fn headers_mut ( & mut self ) -> & mut Vec < ( String , String ) > {
70- & mut self . headers
90+ /// Return a header value
91+ ///
92+ /// Will return `None` if the header does not exist or if it is not utf8
93+ pub fn header ( & self , name : & str ) -> Option < & str > {
94+ self . headers
95+ . get ( & name. to_lowercase ( ) )
96+ . and_then ( |v| match v {
97+ HeaderValue :: String ( s) => Some ( s. as_str ( ) ) ,
98+ HeaderValue :: Bytes ( _) => None ,
99+ } )
100+ }
101+
102+ /// The request headers as bytes
103+ pub fn headers_raw ( & self ) -> impl Iterator < Item = ( & str , & [ u8 ] ) > {
104+ self . headers . iter ( ) . map ( |( k, v) | match v {
105+ HeaderValue :: String ( v) => ( k. as_str ( ) , v. as_bytes ( ) ) ,
106+ HeaderValue :: Bytes ( v) => ( k. as_str ( ) , v. as_slice ( ) ) ,
107+ } )
71108 }
72109
73110 /// The request body
@@ -127,7 +164,15 @@ impl RequestBuilder {
127164
128165 /// Set the headers
129166 pub fn headers ( & mut self , headers : impl conversions:: IntoHeaders ) -> & mut Self {
130- self . request . headers = headers. into_headers ( ) ;
167+ self . request . headers = into_header_rep ( headers) ;
168+ self
169+ }
170+
171+ /// Set a header
172+ pub fn header ( & mut self , key : impl Into < String > , value : impl Into < String > ) -> & mut Self {
173+ self . request
174+ . headers
175+ . insert ( key. into ( ) . to_lowercase ( ) , HeaderValue :: String ( value. into ( ) ) ) ;
131176 self
132177 }
133178
@@ -151,7 +196,7 @@ pub struct Response {
151196 /// The status of the response
152197 status : StatusCode ,
153198 /// The response headers
154- headers : Vec < ( String , String ) > ,
199+ headers : HashMap < String , HeaderValue > ,
155200 /// The body of the response as bytes
156201 body : Vec < u8 > ,
157202}
@@ -161,7 +206,7 @@ impl Response {
161206 pub fn new ( status : impl conversions:: IntoStatusCode , body : impl conversions:: IntoBody ) -> Self {
162207 Self {
163208 status : status. into_status_code ( ) ,
164- headers : Vec :: new ( ) ,
209+ headers : HashMap :: new ( ) ,
165210 body : body. into_body ( ) ,
166211 }
167212 }
@@ -173,16 +218,30 @@ impl Response {
173218
174219 /// The response headers
175220 ///
176- /// Technically headers do not have to be utf8 encoded but this type assumes they are.
177- /// If you know you'll be dealing with non-utf8 encoded headers, reach more a more powerful
178- /// response type like that found in the `http` crate.
179- pub fn headers ( & self ) -> & [ ( String , String ) ] {
180- & self . headers
221+ /// This only returns headers that are utf8 encoded
222+ pub fn headers ( & self ) -> impl Iterator < Item = ( & str , & str ) > {
223+ self . headers . iter ( ) . filter_map ( |( k, v) | match v {
224+ HeaderValue :: String ( v) => Some ( ( k. as_str ( ) , v. as_str ( ) ) ) ,
225+ HeaderValue :: Bytes ( _) => None ,
226+ } )
181227 }
182228
183- /// The response headers
184- pub fn headers_mut ( & mut self ) -> & mut Vec < ( String , String ) > {
185- & mut self . headers
229+ /// Return a header value
230+ ///
231+ /// Will return `None` if the header does not exist or if it is not utf8
232+ pub fn header ( & self , name : & str ) -> Option < & str > {
233+ self . headers . get ( name) . and_then ( |v| match v {
234+ HeaderValue :: String ( s) => Some ( s. as_str ( ) ) ,
235+ HeaderValue :: Bytes ( _) => None ,
236+ } )
237+ }
238+
239+ /// The request headers as bytes
240+ pub fn headers_raw ( & self ) -> impl Iterator < Item = ( & str , & [ u8 ] ) > {
241+ self . headers . iter ( ) . map ( |( k, v) | match v {
242+ HeaderValue :: String ( v) => ( k. as_str ( ) , v. as_bytes ( ) ) ,
243+ HeaderValue :: Bytes ( v) => ( k. as_str ( ) , v. as_slice ( ) ) ,
244+ } )
186245 }
187246
188247 /// The response body
@@ -205,11 +264,13 @@ impl Response {
205264 }
206265}
207266
208- struct ResponseBuilder {
267+ /// A builder for `Response``
268+ pub struct ResponseBuilder {
209269 response : Response ,
210270}
211271
212272impl ResponseBuilder {
273+ /// Create a new `ResponseBuilder`
213274 pub fn new ( status : impl conversions:: IntoStatusCode ) -> Self {
214275 ResponseBuilder {
215276 response : Response :: new ( status, Vec :: new ( ) ) ,
@@ -224,7 +285,15 @@ impl ResponseBuilder {
224285
225286 /// Set the headers
226287 pub fn headers ( & mut self , headers : impl conversions:: IntoHeaders ) -> & mut Self {
227- self . response . headers = headers. into_headers ( ) ;
288+ self . response . headers = into_header_rep ( headers. into_headers ( ) ) ;
289+ self
290+ }
291+
292+ /// Set a header
293+ pub fn header ( & mut self , key : impl Into < String > , value : impl Into < String > ) -> & mut Self {
294+ self . response
295+ . headers
296+ . insert ( key. into ( ) . to_lowercase ( ) , HeaderValue :: String ( value. into ( ) ) ) ;
228297 self
229298 }
230299
@@ -234,11 +303,25 @@ impl ResponseBuilder {
234303 self
235304 }
236305
306+ /// Build the `Response`
237307 pub fn build ( & mut self ) -> Response {
238308 std:: mem:: replace ( & mut self . response , Response :: new ( 200 , Vec :: new ( ) ) )
239309 }
240310}
241311
312+ fn into_header_rep ( headers : impl conversions:: IntoHeaders ) -> HashMap < String , HeaderValue > {
313+ headers
314+ . into_headers ( )
315+ . into_iter ( )
316+ . map ( |( k, v) | {
317+ let v = String :: from_utf8 ( v)
318+ . map ( HeaderValue :: String )
319+ . unwrap_or_else ( |e| HeaderValue :: Bytes ( e. into_bytes ( ) ) ) ;
320+ ( k. to_lowercase ( ) , v)
321+ } )
322+ . collect ( )
323+ }
324+
242325impl std:: hash:: Hash for Method {
243326 fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
244327 core:: mem:: discriminant ( self ) . hash ( state) ;
0 commit comments