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

SpringDelegatingLambdaContainerHandler does not handle Headers correctly for FunctionUrls #860

Open
mircohacker opened this issue Apr 26, 2024 · 7 comments
Assignees

Comments

@mircohacker
Copy link

Serverless Java Container version: com.amazonaws.serverless:aws-serverless-java-container-springboot3:2.1.0-SNAPSHOT

Implementations: Spring Boot 3

Framework version: SpringBoot 3.2.5

Frontend service: FunctionUrl

Deployment method: SAM

Scenario

I still try to render freemarker templates via a spring boot lambda. I want to serve those lambdas via a FunctionUrl for simplicity reasons

Expected behavior

When calling the path where the template is rendered, the response should contain the correct template with the correct headers.

Actual behavior

For API GW Requests this works as expected. For FunctionUrl requests it does omit at least the content-type header and always replaces it with application/json

Steps to reproduce

sam build && sam deploy --guided in this modified sample for alt-pet-store

Full log output

FunctionUrl

Cloudwatch:

2024-04-26T17:22:38.784+02:00	INIT_START Runtime Version: java:21.v15 Runtime Version ARN: arn:aws:lambda:eu-central-1::runtime:367cb4c78c9b9b4d4eb04656c9938e85fbed3f853a08f5e0a5f21a46326d3991
	2024-04-26T17:22:39.879+02:00	2024-04-26T15:22:39.868Z INFO --- [ main] o.s.c.f.s.web.FunctionClassUtils : Main class: class com.amazonaws.serverless.sample.springboot3.Application
	2024-04-26T17:22:39.893+02:00	2024-04-26T15:22:39.893Z INFO --- [ Thread-0] o.s.c.f.serverless.web.ServerlessMVC : Starting application with the following configuration classes:
	2024-04-26T17:22:39.894+02:00	2024-04-26T15:22:39.894Z INFO --- [ Thread-0] o.s.c.f.serverless.web.ServerlessMVC : Application
	2024-04-26T17:22:40.237+02:00	START RequestId: 95f605aa-b6f8-422e-ab8f-6db7f9be1269 Version: $LATEST
	2024-04-26T17:22:41.295+02:00	. ____ _ __ _ _
	2024-04-26T17:22:41.295+02:00	/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
	2024-04-26T17:22:41.295+02:00	( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
	2024-04-26T17:22:41.295+02:00	\\/ ___)| |_)| | | | | || (_| | ) ) ) )
	2024-04-26T17:22:41.295+02:00	' |____| .__|_| |_|_| |_\__, | / / / /
	2024-04-26T17:22:41.295+02:00	=========|_|==============|___/=/_/_/_/
	2024-04-26T17:22:41.296+02:00	:: Spring Boot :: (v3.2.5)
	2024-04-26T17:22:41.521+02:00	2024-04-26T15:22:41.520Z INFO 10 --- [ Thread-0] c.a.s.p.s.AwsSpringWebRuntimeInitializer : AWS Environment: ===SNIP===
	2024-04-26T17:22:41.525+02:00	2024-04-26T15:22:41.524Z INFO 10 --- [ Thread-0] c.a.s.p.s.AwsSpringWebRuntimeInitializer : AWS Handler: com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler
	2024-04-26T17:22:41.577+02:00	2024-04-26T15:22:41.577Z INFO 10 --- [ Thread-0] o.s.boot.SpringApplication : Starting application using Java 21.0.2 with PID 10 (started by sbx_user1051 in /var/task)
	2024-04-26T17:22:41.578+02:00	2024-04-26T15:22:41.578Z INFO 10 --- [ Thread-0] o.s.boot.SpringApplication : No active profile set, falling back to 1 default profile: "default"
	2024-04-26T17:22:43.600+02:00	2024-04-26T15:22:43.600Z INFO 10 --- [ Thread-0] o.s.c.f.s.w.ServerlessAutoConfiguration : Configuring Serverless Web Container
	2024-04-26T17:22:43.679+02:00	2024-04-26T15:22:43.679Z INFO 10 --- [ Thread-0] o.s.c.f.s.w.ServerlessAutoConfiguration : Initializing DispatcherServlet
	2024-04-26T17:22:43.695+02:00	2024-04-26T15:22:43.695Z INFO 10 --- [ Thread-0] o.s.c.f.s.web.ServerlessServletContext : Initializing Spring DispatcherServlet 'dispatcherServlet'
	2024-04-26T17:22:43.696+02:00	2024-04-26T15:22:43.696Z INFO 10 --- [ Thread-0] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
	2024-04-26T17:22:43.861+02:00	2024-04-26T15:22:43.861Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings :
	2024-04-26T17:22:43.861+02:00	c.a.s.s.s.c.IndexController:
	2024-04-26T17:22:43.861+02:00	{GET [/index]}: something2()
	2024-04-26T17:22:43.876+02:00	2024-04-26T15:22:43.876Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings :
	2024-04-26T17:22:43.876+02:00	c.a.s.s.s.c.PetsController:
	2024-04-26T17:22:43.876+02:00	{POST [/pets]}: createPet(Pet)
	2024-04-26T17:22:43.876+02:00	{GET [/pets]}: listPets(Optional,Principal)
	2024-04-26T17:22:43.876+02:00	{GET [/pets/{petId}]}: listPets()
	2024-04-26T17:22:43.876+02:00	{POST [/foo/{gender}/bar/{age}], produces [application/json]}: complexRequest(String,String,String,String)
	2024-04-26T17:22:43.898+02:00	2024-04-26T15:22:43.898Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings :
	2024-04-26T17:22:43.898+02:00	o.s.b.a.w.s.e.BasicErrorController:
	2024-04-26T17:22:43.898+02:00	{ [/error], produces [text/html]}: errorHtml(HttpServletRequest,HttpServletResponse)
	2024-04-26T17:22:43.898+02:00	{ [/error]}: error(HttpServletRequest)
	2024-04-26T17:22:43.939+02:00	2024-04-26T15:22:43.939Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings : 'beanNameHandlerMapping' {}
	2024-04-26T17:22:43.995+02:00	2024-04-26T15:22:43.995Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings :
	2024-04-26T17:22:43.995+02:00	c.a.s.s.s.c.IndexController:
	2024-04-26T17:22:43.995+02:00	{GET [/index]}: something2()
	2024-04-26T17:22:43.997+02:00	2024-04-26T15:22:43.997Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings :
	2024-04-26T17:22:43.997+02:00	c.a.s.s.s.c.PetsController:
	2024-04-26T17:22:43.997+02:00	{POST [/pets]}: createPet(Pet)
	2024-04-26T17:22:43.997+02:00	{GET [/pets]}: listPets(Optional,Principal)
	2024-04-26T17:22:43.997+02:00	{GET [/pets/{petId}]}: listPets()
	2024-04-26T17:22:43.997+02:00	{POST [/foo/{gender}/bar/{age}], produces [application/json]}: complexRequest(String,String,String,String)
	2024-04-26T17:22:44.017+02:00	2024-04-26T15:22:44.016Z DEBUG 10 --- [ Thread-0] _.s.web.servlet.HandlerMapping.Mappings :
	2024-04-26T17:22:44.017+02:00	o.s.b.a.w.s.e.BasicErrorController:
	2024-04-26T17:22:44.017+02:00	{ [/error], produces [text/html]}: errorHtml(HttpServletRequest,HttpServletResponse)
	2024-04-26T17:22:44.017+02:00	{ [/error]}: error(HttpServletRequest)
	2024-04-26T17:22:44.178+02:00	2024-04-26T15:22:44.177Z INFO 10 --- [ Thread-0] o.s.web.servlet.DispatcherServlet : Completed initialization in 481 ms
	2024-04-26T17:22:44.178+02:00	2024-04-26T15:22:44.178Z INFO 10 --- [ Thread-0] o.s.c.f.s.w.ServerlessAutoConfiguration : Initalized DispatcherServlet
	2024-04-26T17:22:44.858+02:00	2024-04-26T15:22:44.857Z INFO 10 --- [ Thread-0] o.s.boot.SpringApplication : Started application in 4.694 seconds (process running for 6.032)
	2024-04-26T17:22:44.861+02:00	2024-04-26T15:22:44.861Z INFO 10 --- [ Thread-0] o.s.c.f.serverless.web.ServerlessMVC : Application is started successfully.
	2024-04-26T17:22:44.862+02:00	2024-04-26T15:22:44.862Z DEBUG 10 --- [ main] c.a.s.p.s.AwsSpringHttpProcessingUtils : Creating HttpServletRequest from: {"version":"2.0","routeKey":"$default","rawPath":"/index","rawQueryString":"","headers":{"x-amzn-tls-cipher-suite":"TLS_AES_128_GCM_SHA256","x-amzn-tls-version":"TLSv1.3","x-amzn-trace-id":"Root=1-662bc6be-691dba3b072d08df3ea4a37c","x-forwarded-proto":"https","host":"motbf3yoc5tldyrlv5zuprb4dy0xikik.lambda-url.eu-central-1.on.aws","x-forwarded-port":"443","x-forwarded-for":"SNIP","accept":"*/*","user-agent":"curl/8.6.0"},"requestContext":{"accountId":"anonymous","apiId":"motbf3yoc5tldyrlv5zuprb4dy0xikik","domainName":"motbf3yoc5tldyrlv5zuprb4dy0xikik.lambda-url.eu-central-1.on.aws","domainPrefix":"motbf3yoc5tldyrlv5zuprb4dy0xikik","http":{"method":"GET","path":"/index","protocol":"HTTP/1.1","sourceIp":"82.194.121.90","userAgent":"curl/8.6.0"},"requestId":"95f605aa-b6f8-422e-ab8f-6db7f9be1269","routeKey":"$default","stage":"$default","time":"26/Apr/2024:15:22:38 +0000","timeEpoch":1714144958361},"isBase64Encoded":false}
	2024-04-26T17:22:45.064+02:00	2024-04-26T15:22:45.063Z WARN 10 --- [ main] c.a.s.s.s.filter.CognitoIdentityFilter : API Gateway context is null
	2024-04-26T17:22:45.199+02:00	2024-04-26T15:22:45.198Z DEBUG 10 --- [ main] freemarker.cache : Couldn't find template in cache for "index.ftlh"("en", UTF-8, parsed); will try to load it.
	2024-04-26T17:22:45.200+02:00	2024-04-26T15:22:45.199Z DEBUG 10 --- [ main] freemarker.cache : TemplateLoader.findTemplateSource("index_en.ftlh"): Not found
	2024-04-26T17:22:45.201+02:00	2024-04-26T15:22:45.200Z DEBUG 10 --- [ main] freemarker.cache : TemplateLoader.findTemplateSource("index.ftlh"): Found
	2024-04-26T17:22:45.202+02:00	2024-04-26T15:22:45.202Z DEBUG 10 --- [ main] freemarker.cache : Loading template for "index.ftlh"("en", UTF-8, parsed) from "class path resource [templates/index.ftlh]"
	2024-04-26T17:22:45.276+02:00	2024-04-26T15:22:45.275Z DEBUG 10 --- [ main] freemarker.cache : "index.ftlh"("en", UTF-8, parsed) cached copy not yet stale; using cached.
	2024-04-26T17:22:45.286+02:00	2024-04-26T15:22:45.285Z DEBUG 10 --- [ main] c.a.s.p.i.s.AwsHttpServletResponse : Response buffer flushed with 95 bytes, latch=1
	2024-04-26T17:22:45.360+02:00	END RequestId: 95f605aa-b6f8-422e-ab8f-6db7f9be1269
	2024-04-26T17:22:45.360+02:00
REPORT RequestId: 95f605aa-b6f8-422e-ab8f-6db7f9be1269	Duration: 5122.98 ms	Billed Duration: 5123 ms	Memory Size: 1024 MB	Max Memory Used: 214 MB	Init Duration: 1452.46 ms	
REPORT RequestId: 95f605aa-b6f8-422e-ab8f-6db7f9be1269 Duration: 5122.98 ms Billed Duration: 5123 ms Memory Size: 1024 MB Max Memory Used: 214 MB Init Duration: 1452

curl (note the Content-Type header)

==SNIP==
< HTTP/1.1 200 OK
< Date: Fri, 26 Apr 2024 15:22:45 GMT
< Content-Type: application/json
< Content-Length: 95
< Connection: keep-alive
< x-amzn-RequestId: 95f605aa-b6f8-422e-ab8f-6db7f9be1269
< X-Amzn-Trace-Id: root=1-662bc6be-691dba3b072d08df3ea4a37c;parent=30b0674dce871ba0;sampled=0;lineage=097eefbb:0
< 
<h1> hello from freemarker </h1>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
* C

Api GW

This is working as expected

2024-04-26T17:26:37.833+02:00	START RequestId: 869723e7-8b44-4c7f-961d-f1506030576d Version: $LATEST
	2024-04-26T17:26:37.834+02:00	2024-04-26T15:26:37.834Z DEBUG 10 --- [ main] c.a.s.p.s.AwsSpringHttpProcessingUtils : Creating HttpServletRequest from: {"version":"1.0","resource":"$default","path":"/index","httpMethod":"GET","headers":{"Content-Length":"0","Host":"gimvqfn9q2.execute-api.eu-central-1.amazonaws.com","User-Agent":"curl/8.6.0","X-Amzn-Trace-Id":"Root=1-662bc7ad-0f01a64a540300ba387dae66","X-Forwarded-For":"82.194.121.90","X-Forwarded-Port":"443","X-Forwarded-Proto":"https","accept":"*/*"},"multiValueHeaders":{"Content-Length":["0"],"Host":["gimvqfn9q2.execute-api.eu-central-1.amazonaws.com"],"User-Agent":["curl/8.6.0"],"X-Amzn-Trace-Id":["Root=1-662bc7ad-0f01a64a540300ba387dae66"],"X-Forwarded-For":["82.194.121.90"],"X-Forwarded-Port":["443"],"X-Forwarded-Proto":["https"],"accept":["*/*"]},"queryStringParameters":null,"multiValueQueryStringParameters":null,"requestContext":{"accountId":"156176255525","apiId":"gimvqfn9q2","domainName":"gimvqfn9q2.execute-api.eu-central-1.amazonaws.com","domainPrefix":"gimvqfn9q2","extendedRequestId":"W1wjMhkmFiAEMog=","httpMethod":"GET","identity":{"accessKey":null,"accountId":null,"caller":null,"cognitoAmr":null,"cognitoAuthenticationProvider":null,"cognitoAuthenticationType":null,"cognitoIdentityId":null,"cognitoIdentityPoolId":null,"principalOrgId":null,"sourceIp":"82.194.121.90","user":null,"userAgent":"curl/8.6.0","userArn":null},"path":"/index","protocol":"HTTP/1.1","requestId":"W1wjMhkmFiAEMog=","requestTime":"26/Apr/2024:15:26:37 +0000","requestTimeEpoch":1714145197799,"resourceId":"$default","resourcePath":"$default","stage":"$default"},"pathParameters":null,"stageVariables":null,"body":null,"isBase64Encoded":false}
	2024-04-26T17:26:37.899+02:00	2024-04-26T15:26:37.899Z WARN 10 --- [ main] c.a.s.s.s.filter.CognitoIdentityFilter : Cognito identity id in request is null
	2024-04-26T17:26:37.900+02:00	2024-04-26T15:26:37.900Z DEBUG 10 --- [ main] freemarker.cache : TemplateLoader.findTemplateSource("index_en.ftlh"): Not found
	2024-04-26T17:26:37.900+02:00	2024-04-26T15:26:37.900Z DEBUG 10 --- [ main] freemarker.cache : TemplateLoader.findTemplateSource("index.ftlh"): Found
	2024-04-26T17:26:37.901+02:00	2024-04-26T15:26:37.901Z DEBUG 10 --- [ main] freemarker.cache : "index.ftlh"("en", UTF-8, parsed): using cached since class path resource [templates/index.ftlh] hasn't changed.
	2024-04-26T17:26:37.901+02:00	2024-04-26T15:26:37.901Z DEBUG 10 --- [ main] freemarker.cache : "index.ftlh"("en", UTF-8, parsed) cached copy not yet stale; using cached.
	2024-04-26T17:26:37.902+02:00	2024-04-26T15:26:37.901Z DEBUG 10 --- [ main] c.a.s.p.i.s.AwsHttpServletResponse : Response buffer flushed with 95 bytes, latch=1
	2024-04-26T17:26:37.903+02:00	END RequestId: 869723e7-8b44-4c7f-961d-f1506030576d
	2024-04-26T17:26:37.903+02:00	REPORT RequestId: 869723e7-8b44-4c7f-961d-f1506030576d Duration: 69.94 ms
@mircohacker
Copy link
Author

@olegz I found some more problems 😉

@mircohacker
Copy link
Author

For the record after making the required changes to the StreamLambdaHandler in the pet-store sample in order to work with HttpApiV2ProxyRequest instead, the application works as expected.

@olegz
Copy link
Collaborator

olegz commented May 3, 2024

Why do you use SpringDelegatingLambdaContainerHandler to invoke Lambda? The SpringDelegatingLambdaContainerHandler was specifically designed to proxy HTTP request coming over API Gateway to SpringMVC.
What am I missing?

@mircohacker
Copy link
Author

I use a function URL instead of a full API GW as "frontend" for the lambda. As per the docs they should both use the exact same request and response payload schema. I wonder why the SpringDelegatingLambdaContainerHandler (?) handles them differently?

@olegz
Copy link
Collaborator

olegz commented May 8, 2024

I see "content-type" : "application/json" when invoking via FunctionURL (note lowercase content-type). Via API Gateway it's `"Content-Type" : [ "application/json" ],
So, I am not sure I understand what is the issue?
Also, we are simply copying HTTP headers that come in into Message headers. We don't do anything else with them. So the lower/upper case is how request comes in, so I am a bit at the loss here

@mircohacker
Copy link
Author

Ok this is weird. Maybe it is a bug with AWS function urls. I will try to reproduce it next week.

@HEPBO3AH
Copy link

HEPBO3AH commented Jul 8, 2024

I just ran into the rewriting of the headers to lowercase.
The code for getting the Principal is not working because of its:

// String AUTHORIZATION = "Authorization"
if (getAuthenticationScheme() == null || !event.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
    return null;
}

I'm using Jersey.

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

No branches or pull requests

4 participants