Add Content-Type header to AWScJson response and writer for servlet response

This commit is contained in:
Oleg Zhurakousky
2023-05-23 12:01:58 +02:00
parent 571d00c107
commit aa90d256ec
3 changed files with 70 additions and 13 deletions

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.function.adapter.aws.web;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -77,7 +78,8 @@ public class WebProxyInvoker {
logger.debug("httpMethod: " + httpMethod); logger.debug("httpMethod: " + httpMethod);
logger.debug("path: " + path); logger.debug("path: " + path);
} }
ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(null, httpMethod, path);
ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getServletContext(), httpMethod, path);
// CONTENT // CONTENT
if (StringUtils.hasText((String) request.get("body"))) { if (StringUtils.hasText((String) request.get("body"))) {
@@ -126,13 +128,14 @@ public class WebProxyInvoker {
apiGatewayResponseStructure.put("isBase64Encoded", false); apiGatewayResponseStructure.put("isBase64Encoded", false);
apiGatewayResponseStructure.put("statusCode", HttpStatus.OK.value()); apiGatewayResponseStructure.put("statusCode", HttpStatus.OK.value());
apiGatewayResponseStructure.put("body", responseString); apiGatewayResponseStructure.put("body", responseString);
Map<String, List<String>> multiValueHeaders = new HashMap<>(); Map<String, List<String>> multiValueHeaders = new HashMap<>();
Map<String, String> headers = new HashMap<>(); Map<String, String> headers = new HashMap<>();
for (String headerName : httpResponse.getHeaderNames()) { for (String headerName : httpResponse.getHeaderNames()) {
multiValueHeaders.put(headerName, httpResponse.getHeaders(headerName)); multiValueHeaders.put(headerName, httpResponse.getHeaders(headerName));
headers.put(headerName, httpResponse.getHeaders(headerName).toString()); headers.put(headerName, httpResponse.getHeaders(headerName).toString());
} }
headers.put(HttpHeaders.CONTENT_TYPE, httpResponse.getContentType());
multiValueHeaders.put(HttpHeaders.CONTENT_TYPE, Collections.singletonList(httpResponse.getContentType()));
apiGatewayResponseStructure.put("multiValueHeaders", multiValueHeaders); apiGatewayResponseStructure.put("multiValueHeaders", multiValueHeaders);
apiGatewayResponseStructure.put("headers", headers); apiGatewayResponseStructure.put("headers", headers);

View File

@@ -18,8 +18,10 @@ package org.springframework.cloud.function.serverless.web;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -69,6 +71,8 @@ public class ProxyHttpServletResponse implements HttpServletResponse {
private int status = HttpServletResponse.SC_OK; private int status = HttpServletResponse.SC_OK;
private ResponsePrintWriter writer;
@Nullable @Nullable
private String errorMessage; private String errorMessage;
@@ -89,7 +93,11 @@ public class ProxyHttpServletResponse implements HttpServletResponse {
@Override @Override
public PrintWriter getWriter() throws UnsupportedEncodingException { public PrintWriter getWriter() throws UnsupportedEncodingException {
throw new UnsupportedOperationException(); if (this.writer == null) {
Writer targetWriter = new OutputStreamWriter(this.content, getCharacterEncoding());
this.writer = new ResponsePrintWriter(targetWriter);
}
return this.writer;
} }
public byte[] getContentAsByteArray() { public byte[] getContentAsByteArray() {
@@ -163,7 +171,7 @@ public class ProxyHttpServletResponse implements HttpServletResponse {
@Override @Override
public boolean isCommitted() { public boolean isCommitted() {
return false; return this.writer == null ? false : this.writer.commited;
} }
@Override @Override
@@ -425,4 +433,47 @@ public class ProxyHttpServletResponse implements HttpServletResponse {
} }
} }
private class ResponsePrintWriter extends PrintWriter {
private boolean commited;
ResponsePrintWriter(Writer out) {
super(out, true);
}
@Override
public void write(char[] buf, int off, int len) {
super.write(buf, off, len);
super.flush();
this.commited = true;
}
@Override
public void write(String s, int off, int len) {
super.write(s, off, len);
super.flush();
this.commited = true;
}
@Override
public void write(int c) {
super.write(c);
super.flush();
this.commited = true;
}
@Override
public void flush() {
super.flush();
this.commited = true;
}
@Override
public void close() {
super.flush();
super.close();
this.commited = true;
}
}
} }

View File

@@ -41,14 +41,13 @@ import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
/** /**
@@ -85,11 +84,8 @@ public class ProxyMvc {
} }
public static ProxyMvc INSTANCE(Class<?>... componentClasses) { public static ProxyMvc INSTANCE(Class<?>... componentClasses) {
GenericWebApplicationContext applpicationContext = new GenericWebApplicationContext(); AnnotationConfigServletWebApplicationContext applpicationContext = new AnnotationConfigServletWebApplicationContext();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(applpicationContext); applpicationContext.scan(componentClasses[0].getPackageName());
if (!ObjectUtils.isEmpty(componentClasses)) {
reader.register(componentClasses);
}
return INSTANCE(applpicationContext); return INSTANCE(applpicationContext);
} }
@@ -108,10 +104,17 @@ public class ProxyMvc {
reg.setLoadOnStartup(1); reg.setLoadOnStartup(1);
this.servletContext = applicationContext.getServletContext(); this.servletContext = applicationContext.getServletContext();
try { try {
this.dispatcher.init(new ProxyServletConfig(this.servletContext)); this.dispatcher.init(new ProxyServletConfig(this.servletContext));
try {
this.service(new ProxyHttpServletRequest(servletContext, "INFO", "/"), new ProxyHttpServletResponse());
}
catch (Exception e) {
//ignore as this is just a pre-warming attempt
}
} }
catch (Exception e) { catch (Exception e) {
throw new IllegalStateException(e); throw new IllegalStateException("Faild to create Spring MVC DispatcherServlet proxy", e);
} }
} }
@@ -162,7 +165,7 @@ public class ProxyMvc {
* *
* @param servlet the {@link Servlet} to invoke in this {@link FilterChain} * @param servlet the {@link Servlet} to invoke in this {@link FilterChain}
* @param filters the {@link Filter}'s to invoke in this {@link FilterChain} * @param filters the {@link Filter}'s to invoke in this {@link FilterChain}
* @since 3.2 * @since 4.0.x
*/ */
ProxyFilterChain(DispatcherServlet servlet) { ProxyFilterChain(DispatcherServlet servlet) {
List<Filter> filters = new ArrayList<>(); List<Filter> filters = new ArrayList<>();