Skip to content

Commit

Permalink
Merge branch 'main' into 976-query-params-not-urldecoded
Browse files Browse the repository at this point in the history
  • Loading branch information
deki committed Nov 27, 2024
2 parents 1785eb5 + 24908a1 commit 269a327
Show file tree
Hide file tree
Showing 62 changed files with 233 additions and 2,670 deletions.
8 changes: 7 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ updates:
slf4j:
patterns:
- "org.slf4j:*"
jackson:
patterns:
- "com.fasterxml.jackson.*:*"
log4j:
patterns:
- "org.apache.logging.log4j:*"
Expand All @@ -36,7 +39,7 @@ updates:
groups:
jersey:
patterns:
- "org.glassfish.jersey:*"
- "org.glassfish.jersey.*:*"
spring:
patterns:
- "org.springframework:*"
Expand All @@ -46,5 +49,8 @@ updates:
log4j:
patterns:
- "org.apache.logging.log4j:*"
jackson:
patterns:
- "com.fasterxml.jackson.*:*"
schedule:
interval: "weekly"
2 changes: 2 additions & 0 deletions .github/workflows/continuous-integration-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ jobs:
run: ./gha_build.sh springboot3 false false -Dspringboot.version=3.1.12 -Dspring.version=6.0.21 -Dspringsecurity.version=6.1.9 -Ddependency-check.skip=true
- name: Build with Spring Boot 3.2.x
run: ./gha_build.sh springboot3 false false -Dspringboot.version=3.2.7 -Dspring.version=6.1.10 -Dspringsecurity.version=6.2.5 -Ddependency-check.skip=true
- name: Build with Spring Boot 3.3.x
run: ./gha_build.sh springboot3 false false -Dspringboot.version=3.3.6 -Dspring.version=6.1.15 -Dspringsecurity.version=6.3.5 -Ddependency-check.skip=true

# temporarily disabled as Struts is not released at the moment
# build_struts2:
Expand Down
2 changes: 1 addition & 1 deletion aws-serverless-java-container-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>6.3.4</version>
<version>6.4.1</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.amazonaws.serverless.proxy.internal;

import org.apache.commons.io.Charsets;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;

public final class HttpUtils {

static final String HEADER_KEY_VALUE_SEPARATOR = "=";
static final String HEADER_VALUE_SEPARATOR = ";";
static final String ENCODING_VALUE_KEY = "charset";


static public Charset parseCharacterEncoding(String contentTypeHeader,Charset defaultCharset) {
// we only look at content-type because content-encoding should only be used for
// "binary" requests such as gzip/deflate.
if (contentTypeHeader == null) {
return defaultCharset;
}

String[] contentTypeValues = contentTypeHeader.split(HEADER_VALUE_SEPARATOR);
if (contentTypeValues.length <= 1) {
return defaultCharset;
}

for (String contentTypeValue : contentTypeValues) {
if (contentTypeValue.trim().startsWith(ENCODING_VALUE_KEY)) {
String[] encodingValues = contentTypeValue.split(HEADER_KEY_VALUE_SEPARATOR);
if (encodingValues.length <= 1) {
return defaultCharset;
}
try {
return Charsets.toCharset(encodingValues[1]);
} catch (UnsupportedCharsetException ex) {
return defaultCharset;
}
}
}
return defaultCharset;
}


static public String appendCharacterEncoding(String currentContentType, String newEncoding) {
if (currentContentType == null || currentContentType.trim().isEmpty()) {
return null;
}

if (currentContentType.contains(HEADER_VALUE_SEPARATOR)) {
String[] contentTypeValues = currentContentType.split(HEADER_VALUE_SEPARATOR);
StringBuilder contentType = new StringBuilder(contentTypeValues[0]);

for (int i = 1; i < contentTypeValues.length; i++) {
String contentTypeValue = contentTypeValues[i];
String contentTypeString = HEADER_VALUE_SEPARATOR + " " + contentTypeValue;
if (contentTypeValue.trim().startsWith(ENCODING_VALUE_KEY)) {
contentTypeString = HEADER_VALUE_SEPARATOR + " " + ENCODING_VALUE_KEY + HEADER_KEY_VALUE_SEPARATOR + newEncoding;
}
contentType.append(contentTypeString);
}

return contentType.toString();
} else {
return currentContentType + HEADER_VALUE_SEPARATOR + " " + ENCODING_VALUE_KEY + HEADER_KEY_VALUE_SEPARATOR + newEncoding;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package com.amazonaws.serverless.proxy.internal.servlet;

import com.amazonaws.serverless.proxy.internal.HttpUtils;
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.internal.SecurityUtils;
import com.amazonaws.serverless.proxy.model.ContainerConfig;
Expand All @@ -32,6 +33,7 @@
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.security.Principal;
import java.time.Instant;
import java.time.ZonedDateTime;
Expand Down Expand Up @@ -232,7 +234,8 @@ public String getCharacterEncoding() {
if (headers == null) {
return config.getDefaultContentCharset();
}
return parseCharacterEncoding(headers.getFirst(HttpHeaders.CONTENT_TYPE));
Charset charset = HttpUtils.parseCharacterEncoding(headers.getFirst(HttpHeaders.CONTENT_TYPE),null);
return charset != null ? charset.name() : null;
}

@Override
Expand All @@ -242,7 +245,7 @@ public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
return;
}
String currentContentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);
headers.putSingle(HttpHeaders.CONTENT_TYPE, appendCharacterEncoding(currentContentType, s));
headers.putSingle(HttpHeaders.CONTENT_TYPE, HttpUtils.appendCharacterEncoding(currentContentType, s));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,53 +369,9 @@ protected StringBuffer generateRequestURL(String requestPath) {
return new StringBuffer(getScheme() + "://" + url);
}

protected String parseCharacterEncoding(String contentTypeHeader) {
// we only look at content-type because content-encoding should only be used for
// "binary" requests such as gzip/deflate.
if (contentTypeHeader == null) {
return null;
}

String[] contentTypeValues = contentTypeHeader.split(HEADER_VALUE_SEPARATOR);
if (contentTypeValues.length <= 1) {
return null;
}

for (String contentTypeValue : contentTypeValues) {
if (contentTypeValue.trim().startsWith(ENCODING_VALUE_KEY)) {
String[] encodingValues = contentTypeValue.split(HEADER_KEY_VALUE_SEPARATOR);
if (encodingValues.length <= 1) {
return null;
}
return encodingValues[1];
}
}
return null;
}

protected String appendCharacterEncoding(String currentContentType, String newEncoding) {
if (currentContentType == null || currentContentType.trim().isEmpty()) {
return null;
}

if (currentContentType.contains(HEADER_VALUE_SEPARATOR)) {
String[] contentTypeValues = currentContentType.split(HEADER_VALUE_SEPARATOR);
StringBuilder contentType = new StringBuilder(contentTypeValues[0]);

for (int i = 1; i < contentTypeValues.length; i++) {
String contentTypeValue = contentTypeValues[i];
String contentTypeString = HEADER_VALUE_SEPARATOR + " " + contentTypeValue;
if (contentTypeValue.trim().startsWith(ENCODING_VALUE_KEY)) {
contentTypeString = HEADER_VALUE_SEPARATOR + " " + ENCODING_VALUE_KEY + HEADER_KEY_VALUE_SEPARATOR + newEncoding;
}
contentType.append(contentTypeString);
}

return contentType.toString();
} else {
return currentContentType + HEADER_VALUE_SEPARATOR + " " + ENCODING_VALUE_KEY + HEADER_KEY_VALUE_SEPARATOR + newEncoding;
}
}

protected ServletInputStream bodyStringToInputStream(String body, boolean isBase64Encoded) throws IOException {
if (body == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package com.amazonaws.serverless.proxy.internal.servlet;


import com.amazonaws.serverless.proxy.internal.HttpUtils;
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.internal.SecurityUtils;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
Expand All @@ -35,6 +36,7 @@
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.Principal;
import java.time.Instant;
import java.time.ZonedDateTime;
Expand Down Expand Up @@ -273,7 +275,8 @@ public String getCharacterEncoding() {
if (request.getMultiValueHeaders() == null) {
return config.getDefaultContentCharset();
}
return parseCharacterEncoding(request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE));
Charset charset = HttpUtils.parseCharacterEncoding(request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE),null);
return charset != null ? charset.name() : null;
}


Expand All @@ -284,12 +287,12 @@ public void setCharacterEncoding(String s)
request.setMultiValueHeaders(new Headers());
}
String currentContentType = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
if (currentContentType == null || "".equals(currentContentType)) {
if (currentContentType == null || currentContentType.isEmpty()) {
log.debug("Called set character encoding to " + SecurityUtils.crlf(s) + " on a request without a content type. Character encoding will not be set");
return;
}

request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_TYPE, appendCharacterEncoding(currentContentType, s));
request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HttpUtils.appendCharacterEncoding(currentContentType, s));
}


Expand Down
2 changes: 1 addition & 1 deletion aws-serverless-java-container-jersey/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</parent>

<properties>
<jersey.version>3.1.8</jersey.version>
<jersey.version>3.1.9</jersey.version>
</properties>

<dependencies>
Expand Down
4 changes: 2 additions & 2 deletions aws-serverless-java-container-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
</parent>

<properties>
<spring.version>6.1.14</spring.version>
<spring-security.version>6.3.4</spring-security.version>
<spring.version>6.2.0</spring.version>
<spring-security.version>6.4.1</spring-security.version>
</properties>

<dependencies>
Expand Down
8 changes: 4 additions & 4 deletions aws-serverless-java-container-springboot3/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
<version>2.1.0-SNAPSHOT</version>

<properties>
<spring.version>6.1.14</spring.version>
<springboot.version>3.3.5</springboot.version>
<springsecurity.version>6.3.4</springsecurity.version>
<spring.version>6.2.0</spring.version>
<springboot.version>3.4.0</springboot.version>
<springsecurity.version>6.4.1</springsecurity.version>
</properties>

<dependencies>
<!-- Core interfaces for the aws-serverless-java-container project -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-serverless-web</artifactId>
<version>4.1.3</version>
<version>4.1.4</version>
</dependency>
<dependency>
<groupId>com.amazonaws.serverless</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
package com.amazonaws.serverless.proxy.spring;

import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Base64;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import com.amazonaws.serverless.proxy.internal.HttpUtils;
import org.apache.commons.io.Charsets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.function.serverless.web.ServerlessHttpServletRequest;
import org.springframework.cloud.function.serverless.web.ServerlessMVC;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.MultiValueMapAdapter;
import org.springframework.util.StringUtils;

import com.amazonaws.serverless.proxy.AsyncInitializationWrapper;
import com.amazonaws.serverless.proxy.AwsHttpApiV2SecurityContextWriter;
import com.amazonaws.serverless.proxy.AwsProxySecurityContextWriter;
import com.amazonaws.serverless.proxy.RequestReader;
Expand Down Expand Up @@ -120,10 +124,12 @@ private static HttpServletRequest generateRequest1(String request, Context lambd
MultiValueMapAdapter headers = new MultiValueMapAdapter(v1Request.getMultiValueHeaders());
httpRequest.setHeaders(headers);
}
if (StringUtils.hasText(v1Request.getBody())) {
httpRequest.setContentType("application/json");
httpRequest.setContent(v1Request.getBody().getBytes(StandardCharsets.UTF_8));
}
populateContentAndContentType(
v1Request.getBody(),
v1Request.getHeaders().get(HttpHeaders.CONTENT_TYPE),
v1Request.isBase64Encoded(),
httpRequest
);
if (v1Request.getRequestContext() != null) {
httpRequest.setAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY, v1Request.getRequestContext());
httpRequest.setAttribute(RequestReader.ALB_CONTEXT_PROPERTY, v1Request.getRequestContext().getElb());
Expand All @@ -149,11 +155,14 @@ private static HttpServletRequest generateRequest2(String request, Context lambd
populateQueryStringparameters(v2Request.getQueryStringParameters(), httpRequest);

v2Request.getHeaders().forEach(httpRequest::setHeader);

if (StringUtils.hasText(v2Request.getBody())) {
httpRequest.setContentType("application/json");
httpRequest.setContent(v2Request.getBody().getBytes(StandardCharsets.UTF_8));
}

populateContentAndContentType(
v2Request.getBody(),
v2Request.getHeaders().get(HttpHeaders.CONTENT_TYPE),
v2Request.isBase64Encoded(),
httpRequest
);

httpRequest.setAttribute(RequestReader.HTTP_API_CONTEXT_PROPERTY, v2Request.getRequestContext());
httpRequest.setAttribute(RequestReader.HTTP_API_STAGE_VARS_PROPERTY, v2Request.getStageVariables());
httpRequest.setAttribute(RequestReader.HTTP_API_EVENT_PROPERTY, v2Request);
Expand All @@ -180,4 +189,22 @@ private static <T> T readValue(String json, Class<T> clazz, ObjectMapper mapper)
}
}

private static void populateContentAndContentType(
String body,
String contentType,
boolean base64Encoded,
ServerlessHttpServletRequest httpRequest) {
if (StringUtils.hasText(body)) {
httpRequest.setContentType(contentType == null ? MediaType.APPLICATION_JSON_VALUE : contentType);
if (base64Encoded) {
httpRequest.setContent(Base64.getMimeDecoder().decode(body));
} else {
Charset charseEncoding = HttpUtils.parseCharacterEncoding(contentType,StandardCharsets.UTF_8);
httpRequest.setContent(body.getBytes(charseEncoding));
}
}
}



}
Loading

0 comments on commit 269a327

Please sign in to comment.