@@ -5,7 +5,7 @@ use std::{borrow::Cow, collections::HashMap, fmt, mem};
5
5
6
6
use http:: {
7
7
self ,
8
- header:: { HeaderValue , HOST } ,
8
+ header:: { HeaderName , HeaderValue , HOST } ,
9
9
HeaderMap , Method , Request as HttpRequest ,
10
10
} ;
11
11
use serde:: {
@@ -31,6 +31,8 @@ pub(crate) struct GatewayRequest<'a> {
31
31
pub ( crate ) http_method : Method ,
32
32
#[ serde( deserialize_with = "deserialize_headers" ) ]
33
33
pub ( crate ) headers : HeaderMap < HeaderValue > ,
34
+ #[ serde( default , deserialize_with = "deserialize_multi_value_headers" ) ]
35
+ pub ( crate ) multi_value_headers : HeaderMap < HeaderValue > ,
34
36
#[ serde( deserialize_with = "nullable_default" ) ]
35
37
pub ( crate ) query_string_parameters : StrMap ,
36
38
#[ serde( deserialize_with = "nullable_default" ) ]
@@ -78,6 +80,7 @@ pub struct Identity {
78
80
pub user_arn : Option < String > ,
79
81
}
80
82
83
+ /// Deserialize a str into an http::Method
81
84
fn deserialize_method < ' de , D > ( deserializer : D ) -> Result < Method , D :: Error >
82
85
where
83
86
D : Deserializer < ' de > ,
@@ -102,6 +105,49 @@ where
102
105
deserializer. deserialize_str ( MethodVisitor )
103
106
}
104
107
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
105
151
fn deserialize_headers < ' de , D > ( deserializer : D ) -> Result < HeaderMap < HeaderValue > , D :: Error >
106
152
where
107
153
D : Deserializer < ' de > ,
@@ -119,11 +165,13 @@ where
119
165
where
120
166
A : MapAccess < ' de > ,
121
167
{
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) ;
123
172
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) ?;
127
175
headers. append ( header_name, header_value) ;
128
176
}
129
177
Ok ( headers)
@@ -150,6 +198,7 @@ impl<'a> From<GatewayRequest<'a>> for HttpRequest<Body> {
150
198
path,
151
199
http_method,
152
200
headers,
201
+ mut multi_value_headers,
153
202
query_string_parameters,
154
203
path_parameters,
155
204
stage_variables,
@@ -191,8 +240,20 @@ impl<'a> From<GatewayRequest<'a>> for HttpRequest<Body> {
191
240
} )
192
241
. expect ( "failed to build request" ) ;
193
242
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
+
194
255
// no builder method that sets headers in batch
195
- mem:: replace ( req. headers_mut ( ) , headers ) ;
256
+ mem:: replace ( req. headers_mut ( ) , multi_value_headers ) ;
196
257
197
258
req
198
259
}
@@ -224,8 +285,18 @@ mod tests {
224
285
fn deserializes_request_events ( ) {
225
286
// from the docs
226
287
// 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) ) ;
229
300
}
230
301
231
302
#[ test]
0 commit comments