@@ -5,7 +5,7 @@ use std::{borrow::Cow, collections::HashMap, fmt, mem};
55
66use http:: {
77 self ,
8- header:: { HeaderValue , HOST } ,
8+ header:: { HeaderName , HeaderValue , HOST } ,
99 HeaderMap , Method , Request as HttpRequest ,
1010} ;
1111use serde:: {
@@ -31,6 +31,8 @@ pub(crate) struct GatewayRequest<'a> {
3131 pub ( crate ) http_method : Method ,
3232 #[ serde( deserialize_with = "deserialize_headers" ) ]
3333 pub ( crate ) headers : HeaderMap < HeaderValue > ,
34+ #[ serde( default , deserialize_with = "deserialize_multi_value_headers" ) ]
35+ pub ( crate ) multi_value_headers : HeaderMap < HeaderValue > ,
3436 #[ serde( deserialize_with = "nullable_default" ) ]
3537 pub ( crate ) query_string_parameters : StrMap ,
3638 #[ serde( deserialize_with = "nullable_default" ) ]
@@ -78,6 +80,7 @@ pub struct Identity {
7880 pub user_arn : Option < String > ,
7981}
8082
83+ /// Deserialize a str into an http::Method
8184fn deserialize_method < ' de , D > ( deserializer : D ) -> Result < Method , D :: Error >
8285where
8386 D : Deserializer < ' de > ,
@@ -102,6 +105,49 @@ where
102105 deserializer. deserialize_str ( MethodVisitor )
103106}
104107
108+ /// Deserialize a map of Cow<'_, str> => Vec<Cow<'_, str>> into an http::HeaderMap
109+ fn deserialize_multi_value_headers < ' de , D > ( deserializer : D ) -> Result < HeaderMap < HeaderValue > , D :: Error >
110+ where
111+ D : Deserializer < ' de > ,
112+ {
113+ struct HeaderVisitor ;
114+
115+ impl < ' de > Visitor < ' de > for HeaderVisitor {
116+ type Value = HeaderMap < HeaderValue > ;
117+
118+ fn expecting ( & self , formatter : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
119+ write ! ( formatter, "a multi valued HeaderMap<HeaderValue>" )
120+ }
121+
122+ fn visit_map < A > ( self , mut map : A ) -> Result < Self :: Value , A :: Error >
123+ where
124+ A : MapAccess < ' de > ,
125+ {
126+ let mut headers = map
127+ . size_hint ( )
128+ . map ( HeaderMap :: with_capacity)
129+ . unwrap_or_else ( HeaderMap :: new) ;
130+ while let Some ( ( key, values) ) = map. next_entry :: < Cow < ' _ , str > , Vec < Cow < ' _ , str > > > ( ) ? {
131+ // note the aws docs for multi value headers include an empty key. I'm not sure if this is a doc bug
132+ // or not by the http crate doesn't handle it
133+ // https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
134+ if !key. is_empty ( ) {
135+ for value in values {
136+ let header_name = key. parse :: < HeaderName > ( ) . map_err ( A :: Error :: custom) ?;
137+ let header_value =
138+ HeaderValue :: from_shared ( value. into_owned ( ) . into ( ) ) . map_err ( A :: Error :: custom) ?;
139+ headers. append ( header_name, header_value) ;
140+ }
141+ }
142+ }
143+ Ok ( headers)
144+ }
145+ }
146+
147+ deserializer. deserialize_map ( HeaderVisitor )
148+ }
149+
150+ /// Deserialize a map of Cow<'_, str> => Cow<'_, str> into an http::HeaderMap
105151fn deserialize_headers < ' de , D > ( deserializer : D ) -> Result < HeaderMap < HeaderValue > , D :: Error >
106152where
107153 D : Deserializer < ' de > ,
@@ -119,11 +165,13 @@ where
119165 where
120166 A : MapAccess < ' de > ,
121167 {
122- let mut headers = http:: HeaderMap :: new ( ) ;
168+ let mut headers = map
169+ . size_hint ( )
170+ . map ( HeaderMap :: with_capacity)
171+ . unwrap_or_else ( HeaderMap :: new) ;
123172 while let Some ( ( key, value) ) = map. next_entry :: < Cow < ' _ , str > , Cow < ' _ , str > > ( ) ? {
124- let header_name = key. parse :: < http:: header:: HeaderName > ( ) . map_err ( A :: Error :: custom) ?;
125- let header_value =
126- http:: header:: HeaderValue :: from_shared ( value. into_owned ( ) . into ( ) ) . map_err ( A :: Error :: custom) ?;
173+ let header_name = key. parse :: < HeaderName > ( ) . map_err ( A :: Error :: custom) ?;
174+ let header_value = HeaderValue :: from_shared ( value. into_owned ( ) . into ( ) ) . map_err ( A :: Error :: custom) ?;
127175 headers. append ( header_name, header_value) ;
128176 }
129177 Ok ( headers)
@@ -150,6 +198,7 @@ impl<'a> From<GatewayRequest<'a>> for HttpRequest<Body> {
150198 path,
151199 http_method,
152200 headers,
201+ mut multi_value_headers,
153202 query_string_parameters,
154203 path_parameters,
155204 stage_variables,
@@ -191,8 +240,20 @@ impl<'a> From<GatewayRequest<'a>> for HttpRequest<Body> {
191240 } )
192241 . expect ( "failed to build request" ) ;
193242
243+ // merge headers into multi_value_headers and make
244+ // multi_value_headers our cannoncial source of request headers
245+ for ( key, value) in headers {
246+ // see HeaderMap#into_iter() docs for cases when key element may be None
247+ if let Some ( first_key) = key {
248+ // if it contains the key, avoid appending a duplicate value
249+ if !multi_value_headers. contains_key ( & first_key) {
250+ multi_value_headers. append ( first_key, value) ;
251+ }
252+ }
253+ }
254+
194255 // no builder method that sets headers in batch
195- mem:: replace ( req. headers_mut ( ) , headers ) ;
256+ mem:: replace ( req. headers_mut ( ) , multi_value_headers ) ;
196257
197258 req
198259 }
@@ -224,8 +285,18 @@ mod tests {
224285 fn deserializes_request_events ( ) {
225286 // from the docs
226287 // https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-api-gateway-request
227- let input = include_str ! ( "../tests/data/proxy_request.json" ) ;
228- assert ! ( serde_json:: from_str:: <GatewayRequest <' _>>( & input) . is_ok( ) )
288+ let input = include_str ! ( "../tests/data/apigw_proxy_request.json" ) ;
289+ let result = serde_json:: from_str :: < GatewayRequest < ' _ > > ( & input) ;
290+ assert ! ( result. is_ok( ) , format!( "event was not parsed as expected {:?}" , result) ) ;
291+ }
292+
293+ #[ test]
294+ fn deserialize_multi_value_events ( ) {
295+ // from docs
296+ // https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
297+ let input = include_str ! ( "../tests/data/apigw_multi_value_proxy_request.json" ) ;
298+ let result = serde_json:: from_str :: < GatewayRequest < ' _ > > ( & input) ;
299+ assert ! ( result. is_ok( ) , format!( "event was not parsed as expected {:?}" , result) ) ;
229300 }
230301
231302 #[ test]
0 commit comments