diff --git a/aws-serverless-java-container-core/pom.xml b/aws-serverless-java-container-core/pom.xml
index 02a535a35..82d218f9d 100644
--- a/aws-serverless-java-container-core/pom.xml
+++ b/aws-serverless-java-container-core/pom.xml
@@ -16,7 +16,7 @@
- 2.9.8
+ 2.9.9
2.1
3.1.0
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/SecurityUtils.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/SecurityUtils.java
index 03dced873..1d39d849b 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/SecurityUtils.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/SecurityUtils.java
@@ -70,6 +70,9 @@ public static boolean isValidHost(String host, String apiId, String region) {
* @return A copy of the original string without CRLF characters
*/
public static String crlf(String s) {
+ if (s == null) {
+ return null;
+ }
return s.replaceAll("[\r\n]", "");
}
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java
index 86ce62500..8712285ac 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java
@@ -19,6 +19,7 @@
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
import com.amazonaws.services.lambda.runtime.Context;
+import org.apache.http.message.BasicHeaderValueParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -77,6 +78,7 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
private ServletContext servletContext;
private AwsHttpSession session;
private String queryString;
+ private BasicHeaderValueParser headerParser;
protected DispatcherType dispatcherType;
@@ -95,6 +97,7 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
AwsHttpServletRequest(Context lambdaContext) {
this.lambdaContext = lambdaContext;
attributes = new HashMap<>();
+ headerParser = new BasicHeaderValueParser();
}
@@ -312,10 +315,12 @@ protected String generateQueryString(MultiValuedTreeMap paramete
queryStringBuilder.append(key);
}
queryStringBuilder.append("=");
- if (encode) {
- queryStringBuilder.append(URLEncoder.encode(val, encodeCharset));
- } else {
- queryStringBuilder.append(val);
+ if (val != null) {
+ if (encode) {
+ queryStringBuilder.append(URLEncoder.encode(val, encodeCharset));
+ } else {
+ queryStringBuilder.append(val);
+ }
}
}
}
@@ -334,7 +339,7 @@ protected String generateQueryString(MultiValuedTreeMap paramete
* @param headerValue The value to be parsed
* @return A list of SimpleMapEntry objects with all of the possible values for the header.
*/
- protected List parseHeaderValue(String headerValue) {
+ protected List parseHeaderValue(String headerValue) {
return parseHeaderValue(headerValue, HEADER_VALUE_SEPARATOR, HEADER_QUALIFIER_SEPARATOR);
}
@@ -352,6 +357,7 @@ protected List parseHeaderValue(String headerValue, String valueSep
// Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
// Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5
// Cookie: name=value; name2=value2; name3=value3
+ // X-Custom-Header: YQ==
List values = new ArrayList<>();
if (headerValue == null) {
@@ -365,25 +371,44 @@ protected List parseHeaderValue(String headerValue, String valueSep
newValue.setRawValue(v);
for (String q : curValue.split(qualifierSeparator)) {
- if (q.contains(HEADER_KEY_VALUE_SEPARATOR)) {
- String[] kv = q.split(HEADER_KEY_VALUE_SEPARATOR);
- // TODO: Should we concatenate the rest of the values?
- if (newValue.getValue() == null) {
- newValue.setKey(kv[0].trim());
- newValue.setValue(kv[1].trim());
- } else {
- // special case for quality q=
- if ("q".equals(kv[0].trim())) {
- curPreference = Float.parseFloat(kv[1].trim());
- } else {
- newValue.addAttribute(kv[0].trim(), kv[1].trim());
- }
+
+ String[] kv = q.split(HEADER_KEY_VALUE_SEPARATOR, 2);
+ String key = null;
+ String val = null;
+ // no separator, set the value only
+ if (kv.length == 1) {
+ val = q.trim();
+ }
+ // we have a separator
+ if (kv.length == 2) {
+ // if the length of the value is 0 we assume that we are looking at a
+ // base64 encoded value with padding so we just set the value. This is because
+ // we assume that empty values in a key/value pair will contain at least a white space
+ if (kv[1].length() == 0) {
+ val = q.trim();
+ }
+ // this was a base64 string with an additional = for padding, set the value only
+ if ("=".equals(kv[1].trim())) {
+ val = q.trim();
+ } else { // it's a proper key/value set both
+ key = kv[0].trim();
+ val = ("".equals(kv[1].trim()) ? null : kv[1].trim());
}
+ }
+
+ if (newValue.getValue() == null) {
+ newValue.setKey(key);
+ newValue.setValue(val);
} else {
- newValue.setValue(q.trim());
+ // special case for quality q=
+ if ("q".equals(key)) {
+ curPreference = Float.parseFloat(val);
+ } else {
+ newValue.addAttribute(key, val);
+ }
}
- newValue.setPriority(curPreference);
}
+ newValue.setPriority(curPreference);
values.add(newValue);
}
@@ -411,7 +436,6 @@ protected String decodeRequestPath(String requestPath, ContainerConfig config) {
}
-
/**
* Class that represents a header value.
*/
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java
index 7783a95a6..a4d0ab816 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java
@@ -366,7 +366,7 @@ public void setCharacterEncoding(String s)
throws UnsupportedEncodingException {
String currentContentType = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
if (currentContentType == null || "".equals(currentContentType)) {
- log.error("Called set character encoding to " + SecurityUtils.crlf(s) + " on a request without a content type. Character encoding will not be set");
+ log.debug("Called set character encoding to " + SecurityUtils.crlf(s) + " on a request without a content type. Character encoding will not be set");
return;
}
@@ -709,8 +709,8 @@ private Map getMultipartFormParametersMap() {
for (FileItem item : items) {
String fileName = FilenameUtils.getName(item.getName());
AwsProxyRequestPart newPart = new AwsProxyRequestPart(item.get());
- newPart.setName(fileName);
- newPart.setSubmittedFileName(item.getFieldName());
+ newPart.setName(item.getFieldName());
+ newPart.setSubmittedFileName(fileName);
newPart.setContentType(item.getContentType());
newPart.setSize(item.getSize());
item.getHeaders().getHeaderNames().forEachRemaining(h -> {
@@ -892,6 +892,9 @@ public void setReadListener(ReadListener readListener) {
@Override
public int read()
throws IOException {
+ if (bodyStream == null || bodyStream instanceof NullInputStream) {
+ return -1;
+ }
int readByte = bodyStream.read();
if (bodyStream.available() == 0 && listener != null) {
listener.onAllDataRead();
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java
index 5a6dc85d4..cb72e9532 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java
@@ -20,6 +20,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.activation.MimetypesFileTypeMap;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
@@ -72,6 +73,7 @@ public class AwsServletContext
private Map initParameters;
private AwsLambdaServletContainerHandler containerHandler;
private Logger log = LoggerFactory.getLogger(AwsServletContext.class);
+ private MimetypesFileTypeMap mimeTypes; // lazily loaded in the getMimeType method
//-------------------------------------------------------------
@@ -142,13 +144,16 @@ public int getEffectiveMinorVersion() {
@Override
@SuppressFBWarnings("PATH_TRAVERSAL_IN") // suppressing because we are using the getValidFilePath
public String getMimeType(String s) {
- try {
- String validatedPath = SecurityUtils.getValidFilePath(s);
- return Files.probeContentType(Paths.get(validatedPath));
- } catch (IOException e) {
- log.warn("Could not find content type for file: " + SecurityUtils.encode(s), e);
+ if (s == null || !s.contains(".")) {
return null;
}
+ if (mimeTypes == null) {
+ mimeTypes = new MimetypesFileTypeMap();
+ }
+ // TODO: The getContentType method of the MimetypesFileTypeMap returns application/octet-stream
+ // instead of null when the type cannot be found. We should replace with an implementation that
+ // loads the System mime types ($JAVA_HOME/lib/mime.types
+ return mimeTypes.getContentType(s);
}
@@ -232,7 +237,7 @@ public String getRealPath(String s) {
try {
absPath = new File(fileUrl.toURI()).getAbsolutePath();
} catch (URISyntaxException e) {
- log.error("Error while looking for real path: {}", SecurityUtils.encode(s), SecurityUtils.encode(e.getMessage()));
+ log.error("Error while looking for real path {}: {}", SecurityUtils.encode(s), SecurityUtils.encode(e.getMessage()));
}
}
return absPath;
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java
index afea70f98..d361d6741 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java
@@ -14,6 +14,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;
@@ -167,7 +168,7 @@ public void setPath(String path) {
this.path = path;
}
-
+ @JsonProperty("isBase64Encoded")
public boolean isBase64Encoded() {
return isBase64Encoded;
}
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java
index 453a01af6..3cebc02fb 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java
@@ -10,10 +10,12 @@
import org.junit.Test;
import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
import javax.ws.rs.core.HttpHeaders;
import static org.junit.Assert.*;
+import java.util.Base64;
import java.util.List;
@@ -27,6 +29,8 @@ public class AwsHttpServletRequestTest {
.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8").build();
private static final AwsProxyRequest queryString = new AwsProxyRequestBuilder("/test", "GET")
.queryString("one", "two").queryString("three", "four").build();
+ private static final AwsProxyRequest queryStringNullValue = new AwsProxyRequestBuilder("/test", "GET")
+ .queryString("one", "two").queryString("three", null).build();
private static final AwsProxyRequest encodedQueryString = new AwsProxyRequestBuilder("/test", "GET")
.queryString("one", "two").queryString("json", "{\"name\":\"faisal\"}").build();
private static final AwsProxyRequest multipleParams = new AwsProxyRequestBuilder("/test", "GET")
@@ -75,6 +79,55 @@ public void headers_parseHeaderValue_complexAccept() {
assertEquals(4, values.size());
}
+ @Test
+ public void headers_parseHeaderValue_encodedContentWithEquals() {
+ AwsHttpServletRequest context = new AwsProxyHttpServletRequest(null,null,null);
+
+ String value = Base64.getUrlEncoder().encodeToString("a".getBytes());
+
+ List result = context.parseHeaderValue(value);
+ assertTrue(result.size() > 0);
+ assertEquals("YQ==", result.get(0).getValue());
+ }
+
+ @Test
+ public void headers_parseHeaderValue_base64EncodedCookieValue() {
+ String value = Base64.getUrlEncoder().encodeToString("a".getBytes());
+ String cookieValue = "jwt=" + value + "; secondValue=second";
+ AwsProxyRequest req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build();
+ AwsHttpServletRequest context = new AwsProxyHttpServletRequest(req,null,null);
+
+ Cookie[] cookies = context.getCookies();
+
+ assertEquals(2, cookies.length);
+ assertEquals("jwt", cookies[0].getName());
+ assertEquals(value, cookies[0].getValue());
+ }
+
+ @Test
+ public void headers_parseHeaderValue_cookieWithSeparatorInValue() {
+ String cookieValue = "jwt==test; secondValue=second";
+ AwsProxyRequest req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build();
+ AwsHttpServletRequest context = new AwsProxyHttpServletRequest(req,null,null);
+
+ Cookie[] cookies = context.getCookies();
+
+ assertEquals(2, cookies.length);
+ assertEquals("jwt", cookies[0].getName());
+ assertEquals("=test", cookies[0].getValue());
+ }
+
+ @Test
+ public void headers_parseHeaderValue_headerWithPaddingButNotBase64Encoded() {
+ AwsHttpServletRequest context = new AwsProxyHttpServletRequest(null,null,null);
+
+ List result = context.parseHeaderValue("hello=");
+ assertTrue(result.size() > 0);
+ assertEquals("hello", result.get(0).getKey());
+ System.out.println("\"" + result.get(0).getValue() + "\"");
+ assertNull(result.get(0).getValue());
+ }
+
@Test
public void queryString_generateQueryString_validQuery() {
AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(queryString, mockContext, null, config);
@@ -92,6 +145,19 @@ public void queryString_generateQueryString_validQuery() {
assertTrue(parsedString.contains("&") && parsedString.indexOf("&") > 0 && parsedString.indexOf("&") < parsedString.length());
}
+ @Test
+ public void queryString_generateQueryString_nullParameterIsEmpty() {
+ AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(queryStringNullValue, mockContext, null, config);String parsedString = null;
+ try {
+ parsedString = request.generateQueryString(request.getAwsProxyRequest().getMultiValueQueryStringParameters(), true, config.getUriEncoding());
+ } catch (ServletException e) {
+ e.printStackTrace();
+ fail("Could not generate query string");
+ }
+
+ assertTrue(parsedString.endsWith("three="));
+ }
+
@Test
public void queryStringWithEncodedParams_generateQueryString_validQuery() {
AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(encodedQueryString, mockContext, null, config);
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java
index ff09b7dd6..b20982b7c 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java
@@ -6,6 +6,7 @@
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
+import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.junit.Test;
@@ -31,6 +32,7 @@ public class AwsProxyHttpServletRequestFormTest {
private static final String PART_KEY_2 = "test2";
private static final String PART_VALUE_2 = "value2";
private static final String FILE_KEY = "file_upload_1";
+ private static final String FILE_NAME = "testImage.jpg";
private static final String ENCODED_VALUE = "test123a%3D1%262@3";
@@ -46,7 +48,7 @@ public class AwsProxyHttpServletRequestFormTest {
private static final HttpEntity MULTIPART_BINARY_DATA = MultipartEntityBuilder.create()
.addTextBody(PART_KEY_1, PART_VALUE_1)
.addTextBody(PART_KEY_2, PART_VALUE_2)
- .addBinaryBody(FILE_KEY, FILE_BYTES)
+ .addBinaryBody(FILE_KEY, FILE_BYTES, ContentType.IMAGE_JPEG, FILE_NAME)
.build();
private static final String ENCODED_FORM_ENTITY = PART_KEY_1 + "=" + ENCODED_VALUE + "&" + PART_KEY_2 + "=" + PART_VALUE_2;
@@ -99,6 +101,8 @@ public void multipart_getParts_binary() {
assertEquals(3, request.getParts().size());
assertNotNull(request.getPart(FILE_KEY));
assertEquals(FILE_SIZE, request.getPart(FILE_KEY).getSize());
+ assertEquals(FILE_KEY, request.getPart(FILE_KEY).getName());
+ assertEquals(FILE_NAME, request.getPart(FILE_KEY).getSubmittedFileName());
assertEquals(PART_VALUE_1, IOUtils.toString(request.getPart(PART_KEY_1).getInputStream()));
assertEquals(PART_VALUE_2, IOUtils.toString(request.getPart(PART_KEY_2).getInputStream()));
} catch (IOException | ServletException e) {
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContextTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContextTest.java
index faf298558..64c91b8db 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContextTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContextTest.java
@@ -4,6 +4,7 @@
import com.amazonaws.serverless.proxy.internal.servlet.filters.UrlPathValidator;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Test;
import javax.servlet.Filter;
@@ -43,7 +44,7 @@ public static void setUp() {
LambdaContainerHandler.getContainerConfig().addValidFilePath("C:\\MyTestFolder");
}
- @Test
+ @Test @Ignore
public void getMimeType_disabledPath_expectException() {
AwsServletContext ctx = new AwsServletContext(null);
try {
@@ -64,32 +65,23 @@ public void getMimeType_nonExistentFileInTaskPath_expectNull() {
@Test
public void getMimeType_mimeTypeOfCorrectFile_expectMime() {
- String tmpFilePath = TMP_DIR + "/test_text.txt";
- try {
- System.out.println("Writing to tmp file " + tmpFilePath);
- PrintWriter tmpWriter = new PrintWriter(tmpFilePath, "UTF-8");
- tmpWriter.write("Test case for aws-serverless-java-container");
- tmpWriter.close();
-
- AwsServletContext ctx = new AwsServletContext(null);
- String mimeType = ctx.getMimeType(tmpFilePath);
- String deducedMimeType = Files.probeContentType(Paths.get(tmpFilePath));
- assertEquals(deducedMimeType, mimeType);
-
- mimeType = ctx.getMimeType("file://" + tmpFilePath);
- assertEquals(deducedMimeType, mimeType);
- } catch (FileNotFoundException e) {
- fail("tmp file not found");
- e.printStackTrace();
- } catch (UnsupportedEncodingException e) {
- fail("Unsupported encoding");
- e.printStackTrace();
- } catch (IOException e) {
- fail("Failed to prove tmp file content type");
- e.printStackTrace();
- }
+ String tmpFilePath = TMP_DIR + "test_text.txt";
+ AwsServletContext ctx = new AwsServletContext(null);
+ String mimeType = ctx.getMimeType(tmpFilePath);
+ assertEquals("text/plain", mimeType);
+
+ mimeType = ctx.getMimeType("file://" + tmpFilePath);
+ assertEquals("text/plain", mimeType);
}
+ @Test
+ public void getMimeType_unknownExtension_expectAppOctetStream() {
+ AwsServletContext ctx = new AwsServletContext(null);
+ String mimeType = ctx.getMimeType("myfile.unkext");
+ assertEquals("application/octet-stream", mimeType);
+ }
+
+
@Test
public void addFilter_nonExistentFilterClass_expectException() {
AwsServletContext ctx = new AwsServletContext(null);
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java
index 6763bbda5..0b82c4bd3 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java
@@ -1,12 +1,13 @@
package com.amazonaws.serverless.proxy.model;
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.*;
public class AwsProxyRequestTest {
private static final String CUSTOM_HEADER_KEY_LOWER_CASE = "custom-header";
@@ -67,13 +68,96 @@ public class AwsProxyRequestTest {
" \"apiId\": \"apiId\"\n" +
" },\n" +
" \"body\": null,\n" +
- " \"isBase64Encoded\": false\n" +
+ " \"isBase64Encoded\": true\n" +
"}";
@Test
public void deserialize_multiValuedHeaders_caseInsensitive() throws IOException {
- AwsProxyRequest req = new AwsProxyRequestBuilder().fromJsonString(REQUEST_JSON).build();
+ AwsProxyRequest req = new AwsProxyRequestBuilder()
+ .fromJsonString(getRequestJson(true, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build();
assertNotNull(req.getMultiValueHeaders().get(CUSTOM_HEADER_KEY_LOWER_CASE.toUpperCase()));
assertEquals(CUSTOM_HEADER_VALUE, req.getMultiValueHeaders().get(CUSTOM_HEADER_KEY_LOWER_CASE.toUpperCase()).get(0));
+ assertTrue(req.isBase64Encoded());
+ }
+
+ @Test
+ public void deserialize_base64Encoded_readsBoolCorrectly() throws IOException {
+ AwsProxyRequest req = new AwsProxyRequestBuilder()
+ .fromJsonString(getRequestJson(true, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build();
+ assertTrue(req.isBase64Encoded());
+ req = new AwsProxyRequestBuilder()
+ .fromJsonString(getRequestJson(false, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build();
+ assertFalse(req.isBase64Encoded());
+ }
+
+ @Test
+ public void serialize_base64Encoded_fieldContainsIsPrefix() throws IOException {
+ AwsProxyRequest req = new AwsProxyRequestBuilder()
+ .fromJsonString(getRequestJson(true, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build();
+ ObjectMapper mapper = new ObjectMapper();
+ String serializedRequest = mapper.writeValueAsString(req);
+ System.out.println(serializedRequest);
+ assertTrue(serializedRequest.contains("\"isBase64Encoded\":true"));
+ }
+
+ private String getRequestJson(boolean base64Encoded, String headerKey, String headerValue) {
+ return "{\n" +
+ " \"resource\": \"/api/{proxy+}\",\n" +
+ " \"path\": \"/api/endpoint\",\n" +
+ " \"httpMethod\": \"OPTIONS\",\n" +
+ " \"headers\": {\n" +
+ " \"Accept\": \"*/*\",\n" +
+ " \"User-Agent\": \"PostmanRuntime/7.1.1\",\n" +
+ " \"" + headerKey +"\":" + "\"" + headerValue + "\"\n" +
+ " },\n" +
+ " \"multiValueHeaders\": {\n" +
+ " \"Accept\": [\n" +
+ " \"*/*\"\n" +
+ " ],\n" +
+ " \"User-Agent\": [\n" +
+ " \"PostmanRuntime/7.1.1\"\n" +
+ " ],\n" +
+ " \"" + headerKey + "\": [\n" +
+ " \"" + headerValue + "\"\n" +
+ " ]\n" +
+ " },\n" +
+ " \"queryStringParameters\": null,\n" +
+ " \"multiValueQueryStringParameters\": null,\n" +
+ " \"pathParameters\": {\n" +
+ " \"proxy\": \"endpoint\"\n" +
+ " },\n" +
+ " \"stageVariables\": null,\n" +
+ " \"requestContext\": {\n" +
+ " \"resourceId\": null,\n" +
+ " \"resourcePath\": \"/api/{proxy+}\",\n" +
+ " \"httpMethod\": \"OPTIONS\",\n" +
+ " \"extendedRequestId\": null,\n" +
+ " \"requestTime\": \"15/Dec/2018:20:37:47 +0000\",\n" +
+ " \"path\": \"/api/endpoint\",\n" +
+ " \"accountId\": null,\n" +
+ " \"protocol\": \"HTTP/1.1\",\n" +
+ " \"stage\": \"stage_name\",\n" +
+ " \"domainPrefix\": null,\n" +
+ " \"requestTimeEpoch\": 1544906267828,\n" +
+ " \"requestId\": null,\n" +
+ " \"identity\": {\n" +
+ " \"cognitoIdentityPoolId\": null,\n" +
+ " \"accountId\": null,\n" +
+ " \"cognitoIdentityId\": null,\n" +
+ " \"caller\": null,\n" +
+ " \"sourceIp\": \"54.240.196.171\",\n" +
+ " \"accessKey\": null,\n" +
+ " \"cognitoAuthenticationType\": null,\n" +
+ " \"cognitoAuthenticationProvider\": null,\n" +
+ " \"userArn\": null,\n" +
+ " \"userAgent\": \"PostmanRuntime/7.1.1\",\n" +
+ " \"user\": null\n" +
+ " },\n" +
+ " \"domainName\": \"https://apiId.execute-api.eu-central-1.amazonaws.com/\",\n" +
+ " \"apiId\": \"apiId\"\n" +
+ " },\n" +
+ " \"body\": null,\n" +
+ " \"isBase64Encoded\": " + (base64Encoded?"true":"false") + "\n" +
+ "}";
}
}
diff --git a/aws-serverless-java-container-jersey/pom.xml b/aws-serverless-java-container-jersey/pom.xml
index b278936f0..f92c9d702 100644
--- a/aws-serverless-java-container-jersey/pom.xml
+++ b/aws-serverless-java-container-jersey/pom.xml
@@ -60,7 +60,7 @@
com.fasterxml.jackson.core
jackson-databind
- 2.9.8
+ 2.9.9
true
test
diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java
index 576d2b66c..dd9166f7d 100644
--- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java
+++ b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java
@@ -34,6 +34,7 @@
import com.amazonaws.services.lambda.runtime.Context;
import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
@@ -196,4 +197,12 @@ public void initialize() {
Timer.stop("JERSEY_COLD_START_INIT");
initialized = true;
}
+
+
+ public InjectionManager getInjectionManager() {
+ if (!initialized) {
+ initialize();
+ }
+ return jerseyFilter.getApplicationHandler().getInjectionManager();
+ }
}
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java
index 1e62291d8..da67dcf36 100644
--- a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java
@@ -41,6 +41,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
import java.util.Random;
@@ -272,4 +273,11 @@ public Response fileSize(@FormDataParam("file") final File uploadedFile,
return Response.status(500).build();
}
}
+
+ @Path("/plain") @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response plain() {
+ return Response.status(200).entity("Hello!").build();
+ }
}
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java
index 491797957..c54de6c5a 100644
--- a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java
@@ -363,6 +363,20 @@ public void refererHeader_headerParam_expectCorrectInjection() {
validateSingleValueModel(resp, refererValue);
}
+ @Test
+ public void textPlainContent_plain_responseHonorsContentType() {
+ AwsProxyRequest req = getRequestBuilder("/echo/plain", "GET")
+ .nullBody()
+ .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+ .header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN)
+ .build();
+
+ AwsProxyResponse resp = handler.proxy(req, lambdaContext);
+ assertEquals(200, resp.getStatusCode());
+ assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
+ assertEquals(MediaType.TEXT_PLAIN, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0));
+ }
+
private void validateMapResponseModel(AwsProxyResponse output) {
validateMapResponseModel(output, CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
}
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java
new file mode 100644
index 000000000..0af2785ee
--- /dev/null
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+ * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package com.amazonaws.serverless.proxy.jersey;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import javax.inject.Singleton;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.junit.Test;
+
+import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+
+/**
+ * Test that one can access the Jersey injection manager
+ */
+public class JerseyInjectionTest {
+
+ // Test ressource binder
+ private static class ResourceBinder extends AbstractBinder {
+
+ @Override
+ protected void configure() {
+ bind(new JerseyInjectionTest()).to(JerseyInjectionTest.class).in(Singleton.class);
+ }
+
+ }
+
+ private static ResourceConfig app = new ResourceConfig().register(MultiPartFeature.class)
+ .register(new ResourceBinder());
+
+ private static JerseyLambdaContainerHandler handler = JerseyLambdaContainerHandler.getAwsProxyHandler(
+ app);
+
+ @Test
+ public void can_get_injected_resources() throws Exception {
+
+ JerseyInjectionTest instance1 = handler.getInjectionManager().getInstance(JerseyInjectionTest.class);
+ assertNotNull(instance1);
+
+ JerseyInjectionTest instance2 = handler.getInjectionManager().getInstance(JerseyInjectionTest.class);
+ assertEquals(instance1, instance2);
+
+ }
+}
diff --git a/aws-serverless-java-container-spring/pom.xml b/aws-serverless-java-container-spring/pom.xml
index 22ce578bd..bbab50a57 100644
--- a/aws-serverless-java-container-spring/pom.xml
+++ b/aws-serverless-java-container-spring/pom.xml
@@ -19,7 +19,7 @@
5.1.1.RELEASE
1.5.17.RELEASE
5.1.1.RELEASE
- 2.9.8
+ 2.9.9
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java
index e287aa953..3fe730da1 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java
@@ -382,7 +382,7 @@ public void contextPath_generateLink_returnsCorrectPath() {
}
@Test
- public void multipart_getFileName_rerutrnsCorrectFileName()
+ public void multipart_getFileName_returnsCorrectFileName()
throws IOException {
AwsProxyRequest request = new AwsProxyRequestBuilder("/echo/attachment", "POST")
.formFilePart("testFile", "myFile.txt", "hello".getBytes())
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringBootAppTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringBootAppTest.java
index 5e3922f7a..f27d6e57a 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringBootAppTest.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringBootAppTest.java
@@ -1,6 +1,7 @@
package com.amazonaws.serverless.proxy.spring;
+import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
@@ -13,6 +14,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
+import javax.ws.rs.core.HttpHeaders;
import java.io.IOException;
import static org.junit.Assert.*;
@@ -74,6 +76,20 @@ public void queryString_commaSeparatedList_expectUnmarshalAsList() {
validateSingleValueModel(resp, "3");
}
+ @Test
+ public void staticContent_getHtmlFile_returnsHtmlContent() {
+ LambdaContainerHandler.getContainerConfig().addValidFilePath("/Users/bulianis/workspace/aws-serverless-java-container/aws-serverless-java-container-spring");
+ AwsProxyRequest request = new AwsProxyRequestBuilder("/static.html", "GET")
+ .header(HttpHeaders.ACCEPT, "text/html")
+ .header(HttpHeaders.CONTENT_TYPE, "text/plain")
+ .build();
+ AwsProxyResponse output = handler.handleRequest(request, context);
+ System.out.println("Response: " + output.getBody());
+ assertEquals(200, output.getStatusCode());
+ assertTrue(output.getBody().contains("Static
"));
+ }
+
+
private void validateSingleValueModel(AwsProxyResponse output, String value) {
try {
SingleValueModel response = mapper.readValue(output.getBody(), SingleValueModel.class);
diff --git a/aws-serverless-java-container-spring/src/test/resources/static/static.html b/aws-serverless-java-container-spring/src/test/resources/static/static.html
new file mode 100644
index 000000000..5231067b7
--- /dev/null
+++ b/aws-serverless-java-container-spring/src/test/resources/static/static.html
@@ -0,0 +1,5 @@
+
+
+Static
+
+
\ No newline at end of file
diff --git a/aws-serverless-java-container-struts2/pom.xml b/aws-serverless-java-container-struts2/pom.xml
index 49942915c..f981e0876 100644
--- a/aws-serverless-java-container-struts2/pom.xml
+++ b/aws-serverless-java-container-struts2/pom.xml
@@ -16,7 +16,7 @@
2.5.20
- 2.9.8
+ 2.9.9
diff --git a/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/pom.xml b/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/pom.xml
index b94697c7f..549511720 100644
--- a/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/pom.xml
@@ -15,7 +15,7 @@
1.8
1.8
2.27
- 2.9.8
+ 2.9.9
diff --git a/aws-serverless-spark-archetype/src/main/resources/archetype-resources/pom.xml b/aws-serverless-spark-archetype/src/main/resources/archetype-resources/pom.xml
index eec41cd2a..ca9d4dd18 100644
--- a/aws-serverless-spark-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/aws-serverless-spark-archetype/src/main/resources/archetype-resources/pom.xml
@@ -16,7 +16,7 @@
1.8
1.8
- 2.9.8
+ 2.9.9
2.8.0
diff --git a/aws-serverless-struts2-archetype/src/main/resources/archetype-resources/pom.xml b/aws-serverless-struts2-archetype/src/main/resources/archetype-resources/pom.xml
index a1ca2962f..3e224f4a5 100644
--- a/aws-serverless-struts2-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/aws-serverless-struts2-archetype/src/main/resources/archetype-resources/pom.xml
@@ -16,7 +16,7 @@
1.8
1.8
2.5.20
- 2.9.8
+ 2.9.9
4.12
2.11.1
diff --git a/samples/jersey/pet-store/pom.xml b/samples/jersey/pet-store/pom.xml
index daf6b67c0..d85e13b08 100644
--- a/samples/jersey/pet-store/pom.xml
+++ b/samples/jersey/pet-store/pom.xml
@@ -77,7 +77,7 @@
com.fasterxml.jackson.core
jackson-databind
- 2.9.8
+ 2.9.9
diff --git a/samples/spark/pet-store/pom.xml b/samples/spark/pet-store/pom.xml
index 09502efd0..32181f3c9 100644
--- a/samples/spark/pet-store/pom.xml
+++ b/samples/spark/pet-store/pom.xml
@@ -26,7 +26,7 @@
1.8
1.8
- 2.9.8
+ 2.9.9
2.8.0
diff --git a/samples/struts/pet-store/pom.xml b/samples/struts/pet-store/pom.xml
index b104bd716..5763b94a8 100644
--- a/samples/struts/pet-store/pom.xml
+++ b/samples/struts/pet-store/pom.xml
@@ -27,7 +27,7 @@
1.8
1.8
2.5.20
- 2.9.8
+ 2.9.9
4.12
2.11.1