Content-Type cannot be set using message headers in GCP adapter
kimberninger opened this issue · 1 comments
Describe the bug
When using spring-cloud-function-adapter-gcp
with a function that responds with a Message
object to an HTTP trigger, the response's Content-Type
header is not set according to the Message
's corresponding header as presumably intended. It is rather overridden by the original request's content type.
It seems like PR #719 was originally meant to fix that the content type was incorrectly referenced by key contentType
rather than the correct Content-Type
, but actually it did not resolve that issue. Instead, it introduced the aforementioned bug. So now, the response contains two headers contentType
and Content-Type
which both do not reflect the value passed as message header.
Versions used:
- Java 21
- Spring Boot 3.3.2
- Spring Cloud 2023.0.3
- Spring Cloud Function & Spring Cloud Function Adapter GCP 4.1.3
- Google Function Maven Plugin 0.11.0
Steps to reproduce
To reproduce the bug in a minimal setting, I used spring initializr with these settings to create a blank Spring Boot Application and replaced the contents of src/main/java/com/example/demo/DemoApplication.java
with the following code:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import java.util.Map;
import java.util.function.Function;
@SpringBootApplication
public class DemoApplication {
@Bean
public Function<String, Message<?>> computation() {
return request -> {
var headers = new MessageHeaders(Map.of("Content-Type", "application/problem+json"));
return MessageBuilder.createMessage(request, headers);
};
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Also, the Maven manifest had to be extended to include the Spring Cloud Function and Spring Cloud Function GCP Adapter, as well as Google's Function Maven plugin to run the function:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>21</java.version>
<spring-cloud.version>2023.0.3</spring-cloud.version>
<spring-cloud-function.version>4.1.3</spring-cloud-function.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-adapter-gcp</artifactId>
<version>${spring-cloud-function.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<outputDirectory>target/deploy</outputDirectory>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-adapter-gcp</artifactId>
<version>${spring-cloud-function.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>com.google.cloud.functions</groupId>
<artifactId>function-maven-plugin</artifactId>
<version>0.11.0</version>
<configuration>
<functionTarget>org.springframework.cloud.function.adapter.gcp.GcfJarLauncher</functionTarget>
<port>8080</port>
</configuration>
</plugin>
</plugins>
</build>
</project>
Finally, the Function Maven Plugin need a pointer to the application's main class in src/main/resources/META-INF/MANIFEST.MF
:
Main-Class: com.example.demo.DemoApplication
After starting the application using ./mvnw function:run
the function is now ready to accept requests:
curl -v localhost:8080 -H "Content-Type: application/json" -d '"Hello World"'
Expected behavior
The Content-Type
header of the resulting response should have the value application/problem+json
and no header named contentType
should exist.
Actual behavior
The request above results in the following response:
HTTP/1.1 200 OK
Date: Thu, 08 Aug 2024 09:16:37 GMT
Content-Type: application/json
id: 6dcf1611-85f9-ae1d-ebd6-9a55539ac228
contentType: application/json
timestamp: 1723108597817
Transfer-Encoding: chunked
Server: Jetty(9.4.51.v20230217)
Both headers Content-Type
and contentType
exist and they both carry the unexpected value application/json
.
If no content type is given with the request (curl -v localhost:8080 -d '"Hello World"'
) then the response looks as follows:
HTTP/1.1 200 OK
Date: Thu, 08 Aug 2024 09:14:18 GMT
Content-Type: application/x-www-form-urlencoded
id: 82984af0-d041-d585-2e08-f4c687009cee
contentType: application/json
timestamp: 1723108458897
Transfer-Encoding: chunked
Server: Jetty(9.4.51.v20230217)
Here the headers Content-Type
and contentType
still exist simultaneously, and they even carry different values.
It is probably also worth mentioning that the current behavior differs from the default behavior when using spring-cloud-starter-function-web
instead of the GCP adapter to run the function. In this case, only Content-Type: application/problem+json
results from the example above.