Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lambda Proxy Integration produces Execution failed due to configuration error: Malformed Lambda proxy response #534

Closed
gerdzhikov opened this issue Jan 19, 2020 · 15 comments
Labels

Comments

@gerdzhikov
Copy link

It's seems, that the AWS Lambda documentation is not 100% corrrect:

Output Format of a Lambda Function for Proxy Integration
...
The multiValueHeaders key can contain multi-value headers as well as single-value headers. You can use the multiValueHeaders key to specify all of your extra headers, including any single-value ones.
...

but, they must be formated as multi values e.g. x-my-custom-header: ["Singel Value"], if the response contains the multiValueHeaders key, they must be provided as arrays of single values

This seems to be correct

multiValueHeaders: {
            "x-powered-by": ["PHP/7.4.0"],
            "cache-control": ["no-cache, private"],
            "date": ["Fri, 17 Jan 2020 17:18:01 GMT"],
            "content-type": ["application/json"],
            "x-ratelimit-limit": ["60"],
            "x-ratelimit-remaining": ["59"]
        }

but this doesn't work

multiValueHeaders: {
            "x-powered-by": "PHP/7.4.0",
            "cache-control": ["no-cache, private"],
            "date": ["Fri, 17 Jan 2020 17:18:01 GMT"],
            "content-type": ["application/json"],
            "x-ratelimit-limit": ["60"],
            "x-ratelimit-remaining": ["59"]
        }

How can I force bref to use headers and not multiValueHeaders? This could be a dirty hotfix for me?

@mnapoli
Copy link
Member

mnapoli commented Jan 19, 2020

Hi, could you clarify what the problem is? (when do you see a problem? do you have an example?)

Bref is already handling multi-value headers:

bref/src/Runtime/PhpFpm.php

Lines 336 to 348 in ad29b00

private function getResponseHeaders(ProvidesResponseData $response, bool $isMultiHeader): array
{
$responseHeaders = $response->getHeaders();
if (! $isMultiHeader) {
// If we are not in "multi-header" mode, we must keep the last value only
// and cast it to string
foreach ($responseHeaders as $key => $value) {
$responseHeaders[$key] = end($value);
}
}
return array_change_key_case($responseHeaders, CASE_LOWER);
}

@gerdzhikov
Copy link
Author

I'm not using multiValueHeaders, so far I can see in the code, the Lambda should return just headers, but it doesn't. Anyway...this is not the real problem. The real problem is the format of the multiValueHeadersin the response. I'm always getting something like:

{
  "isBase64Encoded": false,
  "statusCode": 200,
  "multiValueHeaders": {
    "x-powered-by": "PHP/7.4.0",
    "cache-control": "no-cache, private",
    "date": "Fri, 17 Jan 2020 17:18:01 GMT",
    "content-type": "application/json",
    "x-ratelimit-limit": "60",
    "x-ratelimit-remaining": "59"
  },
  "body": "{}"
}

which is wrong, because the multi header values are strings and not array of strings.

@mnapoli
Copy link
Member

mnapoli commented Jan 19, 2020

Could you explain a bit more about your project? For example:

  • which Bref runtime you are using
  • an extract of your serverless.yml
  • which framework you are using? or an example of how you return those headers?

Since I have little information one possibility I consider here is that you are not using the PHP-FPM layer and you are creating the response yourself, which is why nothing works the way it should. This is why I want to clear this up.

@gerdzhikov
Copy link
Author

Hi,
thank you for the fast response. Hier my environment:

  1. Laravel 6.11.0
  2. bref 0.5.12
  3. with the php-74-fpm layer
  4. AWS API GW with Use Lambda Proxy integration - configured via the AWS Console

and here is my serverless.yml

service: my-rest-api

provider:
  name: aws
  region: eu-central-1
  runtime: provided
  timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
  stage: dev

package:
  exclude:
    - '.git/**'
    - 'node_modules/**'
    - 'storage/**'

plugins:
  - ./vendor/bref/bref

functions:
  booking:
    handler: public/index.php
    description: 'Laravel implementation of My REST API'
    layers:
      - ${bref:layer.php-74-fpm}

and here is how the response is generated in the Laravel controller:

return response()
            ->json(new \stdClass(), 200, []);

@mnapoli
Copy link
Member

mnapoli commented Jan 19, 2020

Thanks, just before I dig more into this is there any reason you didn't let serverless.yml create and configure API Gateway for you?

@gerdzhikov
Copy link
Author

The only one reason is, that the API Gateway is configured by it's own CloudFormation template and uses different beckends - currently Java and now I'm implementing some services as PHP serverless application with Laravel. I'm new to the serverless framework, and don't realy know how it will co-work with my existing CF templates. It's something I'll investigate later.

@mnapoli
Copy link
Member

mnapoli commented Jan 19, 2020

Just for reference (in case you have something different) here is what serverless configures in API Gateway:

Capture d’écran 2020-01-19 à 21 05 57

@gerdzhikov
Copy link
Author

I'ts exactley the same.

@mnapoli
Copy link
Member

mnapoli commented Jan 19, 2020

What error do you see?

@gerdzhikov
Copy link
Author

Here the log from the API GW

Execution log for request 92b94364-453e-48ac-8995-356d0d1973f3
Sun Jan 19 17:19:42 UTC 2020 : Starting execution for request: 92b94364-453e-48ac-8995-356d0d1973f3
Sun Jan 19 17:19:42 UTC 2020 : HTTP Method: GET, Resource Path: /booking/lorem/lorem
Sun Jan 19 17:19:42 UTC 2020 : Method request path: {affiliateName=lorem, bookingReference=lorem}
Sun Jan 19 17:19:42 UTC 2020 : Method request query string: {}
Sun Jan 19 17:19:42 UTC 2020 : Method request headers: {}
Sun Jan 19 17:19:42 UTC 2020 : Method request body before transformations: 
Sun Jan 19 17:19:42 UTC 2020 : Endpoint request URI: https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:************:function:busexpress-rest-api-dev-booking/invocations
Sun Jan 19 17:19:42 UTC 2020 : Endpoint request headers: {x-amzn-lambda-integration-tag=92b94364-453e-48ac-8995-356d0d1973f3, Authorization=***************************************************************************************************************************************************************************************************************************************************************************************************************************3b2920, X-Amz-Date=20200119T171942Z, x-amzn-apigateway-api-id=**********, X-Amz-Source-Arn=arn:aws:execute-api:eu-central-1:************:**********/test-invoke-stage/GET/booking/{affiliateName}/{bookingReference}, Accept=application/json, User-Agent=AmazonAPIGateway_**********, X-Amz-Security-Token=IQoJb3JpZ2luX2VjEFAaDGV1LWNlbnRyYWwtMSJHMEUCIDBfLDqI5DH7gycnu3ECnXNVzjI3ho1KF+PRqpin0UxyAiEAr2cYqmmw/HG9vKSGAO0ZnR7GaJHIGEnCAPwxw8hX9nkqwwMI2f//////////ARABGgw0NzQyNDAxNDY4MDIiDN0POx7EpOPR0kWHKCqXA1zsI7AC/npO3vlLGs25/o2s05CYXTFMp2OhQENTJB5jrZIfnSsfMOpb8aOhB4K/WHPHYdR+TP4DV4mqGHF+ZeyFZJ49kZYRMEbDewty [TRUNCATED]
Sun Jan 19 17:19:42 UTC 2020 : Endpoint request body after transformations: {"resource":"/booking/{affiliateName}/{bookingReference}","path":"/booking/lorem/lorem","httpMethod":"GET","headers":null,"multiValueHeaders":null,"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":{"affiliateName":"lorem","bookingReference":"lorem"},"stageVariables":{"EnvironmentClass":"dev"},"requestContext":{"resourceId":"88q7db","resourcePath":"/booking/{affiliateName}/{bookingReference}","operationName":"getBookingDetails","httpMethod":"GET","extendedRequestId":"GjtjVH_yliAFtYw=","requestTime":"19/Jan/2020:17:19:42 +0000","path":"/booking/{affiliateName}/{bookingReference}","accountId":"************","protocol":"HTTP/1.1","stage":"test-invoke-stage","domainPrefix":"testPrefix","requestTimeEpoch":1579454382823,"requestId":"92b94364-453e-48ac-8995-356d0d1973f3","identity":{"cognitoIdentityPoolId":null,"cognitoIdentityId":null,"apiKey":"test-invoke-api-key","principalOrgId":null,"cognitoAuthenticationType":null,"userArn":"arn:aws [TRUNCATED]
Sun Jan 19 17:19:42 UTC 2020 : Sending request to https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:************:function:busexpress-rest-api-dev-booking/invocations
Sun Jan 19 17:19:43 UTC 2020 : Received response. Status: 200, Integration latency: 1015 ms
Sun Jan 19 17:19:43 UTC 2020 : Endpoint response headers: {Date=Sun, 19 Jan 2020 17:19:43 GMT, Content-Type=application/json, Content-Length=261, Connection=keep-alive, x-amzn-RequestId=8d513c52-5409-4f14-9f16-2817bdcb93ed, x-amzn-Remapped-Content-Length=0, X-Amz-Executed-Version=$LATEST, X-Amzn-Trace-Id=root=1-5e248fae-ac0e979e7e14d4e6bc76d8aa;sampled=1}
Sun Jan 19 17:19:43 UTC 2020 : Endpoint response body before transformations: {"isBase64Encoded":false,"statusCode":200,"headersKey":{"x-powered-by":"PHP\/7.4.0","cache-control":"no-cache, private","date":"Sun, 19 Jan 2020 17:19:43 GMT","content-type":"application\/json","x-ratelimit-limit":"60","x-ratelimit-remaining":"59"},"body":"{}"}
Sun Jan 19 17:19:43 UTC 2020 : Execution failed due to configuration error: Malformed Lambda proxy response
Sun Jan 19 17:19:43 UTC 2020 : Method completed with status: 502

@gerdzhikov
Copy link
Author

It's looks like, that the problem here happens only when testing the Lamda invocation from the API Gateway Console. When the API Gateway is configured and the call is propagated to the Lamda functioin, everything works like expected. The difference is, that the API Gateway sends to the Lamda Function a multiValueHeaders list, activating the multi-value headers in the Bref layer and it returns a multi-value header list... see the attached log: row Endpoint response body before transformations

timestamp,message
1579627365972,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Extended Request Id: GqT38H-FFiAFhLQ=
1579627365975,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Verifying Usage Plan for request: d0a6c3bf-f5ee-4153-be2d-493031a7c885. API Key: **********************************BeFFOj API Stage: **********/int
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Usage Plan check succeeded for API Key **********************************BeFFOj and API Stage **********/int
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Starting execution for request: d0a6c3bf-f5ee-4153-be2d-493031a7c885
1579627365978,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) HTTP Method: PUT, Resource Path: /int/booking/api-invoker"
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) API Key: **********************************BeFFOj
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) API Key ID: v7y79n2re7
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method request path: {affiliateName=api-invoker}
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method request query string: {}
1579627365978,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method request headers: {X-Amz-Date=20200121T172244Z, Accept=*/*, User-Agent=PostmanRuntime/7.22.0, X-Forwarded-Proto=https, Host=api.int.msbe.lorem-ipsum.bg, Accept-Encoding=gzip, deflate, br, X-Amz-Content-Sha256=3b9a1571523947edfcbebbdda2b54d70a0174f2a69a800251939acfe2f3a7e5b, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-5e273365-fe8addf4f033208cc72525a4, Cache-Control=no-cache, x-api-key=**********************************BeFFOj, X-Forwarded-For=1.1.1.1, Content-Type=application/json}"
1579627365978,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method request body before transformations: {}
1579627365978,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Endpoint request URI: https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:111111111111:function:lorem-ipsum-rest-api-int-booking/invocations
1579627365978,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Endpoint request headers: {x-amzn-lambda-integration-tag=d0a6c3bf-f5ee-4153-be2d-493031a7c885, Authorization=***************************************************************************************************************************************************************************************************************************************************************************************************************************61bde4, X-Amz-Date=20200121T172245Z, x-amzn-apigateway-api-id=**********, X-Amz-Source-Arn=arn:aws:execute-api:eu-central-1:111111111111:**********/int/PUT/booking/{affiliateName}, Accept=application/json, User-Agent=AmazonAPIGateway_**********, X-Amz-Security-Token=IQoJb3JpZ2luX2VjEIH//////////wEaDGV1LWNlbnRyYWwtMSJGMEQCICT6GC+8Yot+pkmvQBvttIcbx3ZQKasvA+l6XOXZqZvlAiBahrQuu2Xy1d6gNHudaz/NhCxTfj0p1Tp7dY7s/D0YOSq6AwgaEAEaDDQ3NDI0MDE0NjgwMiIMPgiW1PhKHjmBG/WnKpcDwGED6kOwARoxk8mB4WVz/bzA+dRCDBaDA1MiTxzRWkzqli6XA+CFWmoMm81yqJL6wBtdDToEHdhVqOr1Ow3G/yiC++k4YkJFaQpSF2T0ER7bepg5kdRDKm5DZqYFgZHtyUXDaclf4 [TRUNCATED]"
1579627365979,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Endpoint request body after transformations: {""resource"":""/booking/{affiliateName}"",""path"":""/int/booking/api-invoker"",""httpMethod"":""PUT"",""headers"":{""Accept"":""*/*"",""Accept-Encoding"":""gzip, deflate, br"",""Cache-Control"":""no-cache"",""Content-Type"":""application/json"",""Host"":""api.int.msbe.lorem-ipsum.bg"",""User-Agent"":""PostmanRuntime/7.22.0"",""X-Amz-Content-Sha256"":""3b9a1571523947edfcbebbdda2b54d70a0174f2a69a800251939acfe2f3a7e5b"",""X-Amz-Date"":""20200121T172244Z"",""X-Amzn-Trace-Id"":""Root=1-5e273365-fe8addf4f033208cc72525a4"",""x-api-key"":""****************************************"",""X-Forwarded-For"":""1.1.1.1"",""X-Forwarded-Port"":""443"",""X-Forwarded-Proto"":""https""},""multiValueHeaders"":{""Accept"":[""*/*""],""Accept-Encoding"":[""gzip, deflate, br""],""Cache-Control"":[""no-cache""],""Content-Type"":[""application/json""],""Host"":[""api.int.msbe.lorem-ipsum.bg""],""User-Agent"":[""PostmanRuntime/7.22.0""],""X-Amz-Content-Sha256"":[""3b9a1571523947edfcbebbdda2b54d70a0174f2a69a800251939acfe2f3a7e5b""],""X-Amz-Date"":[""20200121T172244Z""],""X-Amzn-Tr [TRUNCATED]"
1579627365979,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Sending request to https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:111111111111:function:lorem-ipsum-rest-api-int-booking/invocations
1579627367016,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Received response. Status: 200, Integration latency: 1037 ms"
1579627367016,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Endpoint response headers: {Date=Tue, 21 Jan 2020 17:22:47 GMT, Content-Type=application/json, Content-Length=1255, Connection=keep-alive, x-amzn-RequestId=237191ff-b13d-4e7c-b456-62136dcf966e, x-amzn-Remapped-Content-Length=0, X-Amz-Executed-Version=$LATEST, X-Amzn-Trace-Id=root=1-5e273365-fe8addf4f033208cc72525a4;parent=62fe5846a33c5a7f;sampled=1}"
1579627367016,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Endpoint response body before transformations: {""isBase64Encoded"":false,""statusCode"":200,""multiValueHeaders"":{""x-powered-by"":[""PHP\/7.4.0""],""cache-control"":[""no-cache, private""],""date"":[""Tue, 21 Jan 2020 17:22:47 GMT""],""content-type"":[""application\/json""],""x-ratelimit-limit"":[""60""],""x-ratelimit-remaining"":[""59""]},""body"":""{}""
1579627367016,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method response body after transformations: {}
1579627367016,"(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method response headers: {x-powered-by=PHP/7.4.0, cache-control=no-cache, private, date=Tue, 21 Jan 2020 17:22:47 GMT, content-type=application/json, x-ratelimit-limit=60, x-ratelimit-remaining=59, X-Amzn-Trace-Id=Root=1-5e273365-fe8addf4f033208cc72525a4}"
1579627367016,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Successfully completed execution
1579627367016,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) Method completed with status: 200
1579627367016,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) AWS Integration Endpoint RequestId : 237191ff-b13d-4e7c-b456-62136dcf966e
1579627367016,(d0a6c3bf-f5ee-4153-be2d-493031a7c885) X-ray Tracing ID : Root=1-5e273365-fe8addf4f033208cc72525a4

When calling the Lamda function from the test API Gateway Console, it sends just a single value header list. Why this results in a muty-value header list in the response is not clear for me - here the log from the console:

Tue Jan 21 17:21:21 UTC 2020 : Endpoint request body after transformations: {"resource":"/booking/{affiliateName}","path":"/booking/lorem","httpMethod":"PUT","headers":null,"multiValueHeaders":null,"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":{"affiliateName":"lorem"},"stageVariables":{"EnvironmentClass":"int"},"requestContext":{"resourceId":"qp6ou8","resourcePath":"/booking/{affiliateName}","operationName":"initBooking","httpMethod":"PUT","extendedRequestId":"GqTqwEv0FiAFblQ=","requestTime":"21/Jan/2020:17:21:21 +0000","path":"/booking/{affiliateName}","accountId":"************","protocol":"HTTP/1.1","stage":"test-invoke-stage","domainPrefix":"testPrefix","requestTimeEpoch":1579627281565,"requestId":"1cb03b51-55c0-4443-8cc8-a9b8607fa656","identity":{"cognitoIdentityPoolId":null,"cognitoIdentityId":null,"apiKey":"test-invoke-api-key","principalOrgId":null,"cognitoAuthenticationType":null,"userArn":"arn:aws:iam::************:user/user","apiKeyId":"test-invoke-api-key-id","userAgent":"aws-internal/3 a [TRUNCATED]

@mnapoli
Copy link
Member

mnapoli commented Jan 22, 2020

Oh well spotted!

Just to be sure I understand:

  • things work correctly in most cases
  • except when doing a manual "test" invocation from the API Gateway console

that's correct?

If it is, I'm not really sure I want to spend time working on this to be honest 😅

@mnapoli mnapoli added bug and removed support labels Jan 22, 2020
@gerdzhikov
Copy link
Author

Yes,
to work around this while testing and developing, I've just changed the method toApiGatewayFormat() in /vendor/bref/bref/src/Http/LambdaResponse.php to return always just headers. Other workaround is to send some header from the API Gateway console - this fixes the problem as well.

@mnapoli
Copy link
Member

mnapoli commented Jan 24, 2020

@gerdzhikov OK I've managed to reproduce this in another scenario. I will be pushing a fix at some point.

Thank you for reporting this.

@gerdzhikov
Copy link
Author

Thank you for fixing this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants