@@ -20,6 +20,7 @@ use serde::Deserialize;
2020use serde_json:: error:: Error as JsonError ;
2121use std:: future:: Future ;
2222use std:: pin:: Pin ;
23+ use std:: str:: FromStr ;
2324use std:: { io:: Read , mem} ;
2425use url:: Url ;
2526
@@ -201,22 +202,25 @@ fn into_alb_request(alb: AlbTargetGroupRequest) -> http::Request<Body> {
201202 let host = alb. headers . get ( http:: header:: HOST ) . and_then ( |s| s. to_str ( ) . ok ( ) ) ;
202203 let raw_path = alb. path . unwrap_or_default ( ) ;
203204
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+
204208 let builder = http:: Request :: builder ( )
205209 . uri ( build_request_uri (
206210 & raw_path,
207211 & alb. headers ,
208212 host,
209- Some ( ( & alb . multi_value_query_string_parameters , & alb . query_string_parameters ) ) ,
213+ Some ( ( & multi_value_query_string_parameters, & query_string_parameters) ) ,
210214 ) )
211215 . extension ( RawHttpPath ( raw_path) )
212216 // multi valued query string parameters are always a super
213217 // set of singly valued query string parameters,
214218 // when present, multi-valued query string parameters are preferred
215219 . 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
218222 } else {
219- alb . multi_value_query_string_parameters
223+ multi_value_query_string_parameters
220224 } ,
221225 ) )
222226 . extension ( RequestContext :: Alb ( alb. request_context ) ) ;
@@ -243,6 +247,12 @@ fn into_alb_request(alb: AlbTargetGroupRequest) -> http::Request<Body> {
243247 req
244248}
245249
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+
246256#[ cfg( feature = "apigw_websockets" ) ]
247257fn into_websocket_request ( ag : ApiGatewayWebsocketProxyRequest ) -> http:: Request < Body > {
248258 let http_method = ag. http_method ;
@@ -548,6 +558,34 @@ mod tests {
548558 ) ;
549559 }
550560
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+
551589 #[ test]
552590 fn deserializes_apigw_multi_value_request_events ( ) {
553591 // from docs
@@ -593,6 +631,28 @@ mod tests {
593631 ) ;
594632 }
595633
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+
596656 #[ test]
597657 fn deserialize_apigw_http_sam_local ( ) {
598658 // manually generated from AWS SAM CLI
0 commit comments