@@ -20,6 +20,7 @@ use serde::Deserialize;
20
20
use serde_json:: error:: Error as JsonError ;
21
21
use std:: future:: Future ;
22
22
use std:: pin:: Pin ;
23
+ use std:: str:: FromStr ;
23
24
use std:: { io:: Read , mem} ;
24
25
use url:: Url ;
25
26
@@ -201,22 +202,25 @@ fn into_alb_request(alb: AlbTargetGroupRequest) -> http::Request<Body> {
201
202
let host = alb. headers . get ( http:: header:: HOST ) . and_then ( |s| s. to_str ( ) . ok ( ) ) ;
202
203
let raw_path = alb. path . unwrap_or_default ( ) ;
203
204
205
+ let query_string_parameters = decode_query_map ( alb. query_string_parameters ) ;
206
+ let multi_value_query_string_parameters = decode_query_map ( alb. multi_value_query_string_parameters ) ;
207
+
204
208
let builder = http:: Request :: builder ( )
205
209
. uri ( build_request_uri (
206
210
& raw_path,
207
211
& alb. headers ,
208
212
host,
209
- Some ( ( & alb . multi_value_query_string_parameters , & alb . query_string_parameters ) ) ,
213
+ Some ( ( & multi_value_query_string_parameters, & query_string_parameters) ) ,
210
214
) )
211
215
. extension ( RawHttpPath ( raw_path) )
212
216
// multi valued query string parameters are always a super
213
217
// set of singly valued query string parameters,
214
218
// when present, multi-valued query string parameters are preferred
215
219
. extension ( QueryStringParameters (
216
- if alb . multi_value_query_string_parameters . is_empty ( ) {
217
- alb . query_string_parameters
220
+ if multi_value_query_string_parameters. is_empty ( ) {
221
+ query_string_parameters
218
222
} else {
219
- alb . multi_value_query_string_parameters
223
+ multi_value_query_string_parameters
220
224
} ,
221
225
) )
222
226
. extension ( RequestContext :: Alb ( alb. request_context ) ) ;
@@ -243,6 +247,12 @@ fn into_alb_request(alb: AlbTargetGroupRequest) -> http::Request<Body> {
243
247
req
244
248
}
245
249
250
+ fn decode_query_map ( query_map : QueryMap ) -> QueryMap {
251
+ let query_string = query_map. to_query_string ( ) ;
252
+ let decoded = percent_encoding:: percent_decode ( query_string. as_bytes ( ) ) . decode_utf8_lossy ( ) ;
253
+ QueryMap :: from_str ( & decoded) . unwrap_or_default ( )
254
+ }
255
+
246
256
#[ cfg( feature = "apigw_websockets" ) ]
247
257
fn into_websocket_request ( ag : ApiGatewayWebsocketProxyRequest ) -> http:: Request < Body > {
248
258
let http_method = ag. http_method ;
@@ -548,6 +558,34 @@ mod tests {
548
558
) ;
549
559
}
550
560
561
+ #[ test]
562
+ fn deserializes_alb_request_encoded_query_parameters_events ( ) {
563
+ // from the docs
564
+ // https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers
565
+ let input = include_str ! ( "../tests/data/alb_request_encoded_query_parameters.json" ) ;
566
+ let result = from_str ( input) ;
567
+ assert ! (
568
+ result. is_ok( ) ,
569
+ "event was not parsed as expected {:?} given {}" ,
570
+ result,
571
+ input
572
+ ) ;
573
+ let req = result. expect ( "failed to parse request" ) ;
574
+ assert_eq ! ( req. method( ) , "GET" ) ;
575
+ assert_eq ! (
576
+ req. uri( ) ,
577
+ "https://lambda-846800462-us-east-2.elb.amazonaws.com/?myKey=%3FshowAll%3Dtrue"
578
+ ) ;
579
+
580
+ // Ensure this is an ALB request
581
+ let req_context = req. request_context ( ) ;
582
+ assert ! (
583
+ matches!( req_context, RequestContext :: Alb ( _) ) ,
584
+ "expected Alb context, got {:?}" ,
585
+ req_context
586
+ ) ;
587
+ }
588
+
551
589
#[ test]
552
590
fn deserializes_apigw_multi_value_request_events ( ) {
553
591
// from docs
@@ -593,6 +631,28 @@ mod tests {
593
631
) ;
594
632
}
595
633
634
+ #[ test]
635
+ fn deserializes_alb_multi_value_request_encoded_query_parameters_events ( ) {
636
+ // from docs
637
+ // https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
638
+ let input = include_str ! ( "../tests/data/alb_multi_value_request_encoded_query_parameters.json" ) ;
639
+ let result = from_str ( input) ;
640
+ assert ! (
641
+ result. is_ok( ) ,
642
+ "event is was not parsed as expected {:?} given {}" ,
643
+ result,
644
+ input
645
+ ) ;
646
+ let request = result. expect ( "failed to parse request" ) ;
647
+ assert ! ( !request. query_string_parameters( ) . is_empty( ) ) ;
648
+
649
+ // test RequestExt#query_string_parameters does the right thing
650
+ assert_eq ! (
651
+ request. query_string_parameters( ) . all( "myKey" ) ,
652
+ Some ( vec![ "?showAll=true" , "?showAll=false" ] )
653
+ ) ;
654
+ }
655
+
596
656
#[ test]
597
657
fn deserialize_apigw_http_sam_local ( ) {
598
658
// manually generated from AWS SAM CLI
0 commit comments