Skip to content

Commit 7336e30

Browse files
committed
Added support for the new multiValue headers and query string parameters in both request and response. Issue #198
1 parent c8bebd3 commit 7336e30

File tree

23 files changed

+282
-289
lines changed

23 files changed

+282
-289
lines changed

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
1717
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
1818
import com.amazonaws.serverless.proxy.model.ErrorModel;
19+
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
1920

2021
import com.fasterxml.jackson.core.JsonProcessingException;
2122
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -57,14 +58,14 @@ public class AwsProxyExceptionHandler
5758
// Variables - Private - Static
5859
//-------------------------------------------------------------
5960

60-
private static Map<String, String> headers = new HashMap<>();
61+
private static MultiValuedTreeMap<String, String> headers = new MultiValuedTreeMap<>(String.CASE_INSENSITIVE_ORDER);
6162

6263
//-------------------------------------------------------------
6364
// Constructors
6465
//-------------------------------------------------------------
6566

6667
static {
67-
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
68+
headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
6869
}
6970

7071

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.amazonaws.serverless.proxy.internal.SecurityUtils;
1717
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestContext;
1818
import com.amazonaws.serverless.proxy.model.ContainerConfig;
19+
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
1920
import com.amazonaws.services.lambda.runtime.Context;
2021

2122
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -60,7 +61,6 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
6061
static final String HEADER_VALUE_SEPARATOR = ";";
6162
static final String HEADER_QUALIFIER_SEPARATOR = ",";
6263
static final String FORM_DATA_SEPARATOR = "&";
63-
static final String DEFAULT_CHARACTER_ENCODING = "UTF-8";
6464
static final DateTimeFormatter dateFormatter = DateTimeFormatter.RFC_1123_DATE_TIME;
6565
static final String ENCODING_VALUE_KEY = "charset";
6666

@@ -295,7 +295,7 @@ protected Cookie[] parseCookieHeaderValue(String headerValue) {
295295
* @param encodeCharset Charset to use for encoding the query string
296296
* @return The generated query string for the URI
297297
*/
298-
protected String generateQueryString(Map<String, String> parameters, boolean encode, String encodeCharset)
298+
protected String generateQueryString(MultiValuedTreeMap<String, String> parameters, boolean encode, String encodeCharset)
299299
throws ServletException {
300300
if (parameters == null || parameters.size() == 0) {
301301
return null;
@@ -306,27 +306,22 @@ protected String generateQueryString(Map<String, String> parameters, boolean enc
306306

307307
StringBuilder queryStringBuilder = new StringBuilder();
308308

309-
/*parameters.keySet().stream().forEach(k -> parameters.stream().forEach(v -> {
310-
queryStringBuilder.append("&");
311-
queryStringBuilder.append(k);
312-
queryStringBuilder.append("=");
313-
queryStringBuilder.append(v);
314-
}));*/
315309
try {
316-
for (Map.Entry<String, String> e : parameters.entrySet()) {
317-
queryStringBuilder.append("&");
318-
if (encode) {
319-
queryStringBuilder.append(URLEncoder.encode(e.getKey(), encodeCharset));
320-
} else {
321-
queryStringBuilder.append(e.getKey());
322-
}
323-
queryStringBuilder.append("=");
324-
if (encode) {
325-
queryStringBuilder.append(URLEncoder.encode(e.getValue(), encodeCharset));
326-
} else {
327-
queryStringBuilder.append(e.getValue());
310+
for (String key : parameters.keySet()) {
311+
for (String val : parameters.get(key)) {
312+
queryStringBuilder.append("&");
313+
if (encode) {
314+
queryStringBuilder.append(URLEncoder.encode(key, encodeCharset));
315+
} else {
316+
queryStringBuilder.append(key);
317+
}
318+
queryStringBuilder.append("=");
319+
if (encode) {
320+
queryStringBuilder.append(URLEncoder.encode(val, encodeCharset));
321+
} else {
322+
queryStringBuilder.append(val);
323+
}
328324
}
329-
330325
}
331326
} catch (UnsupportedEncodingException e) {
332327
throw new ServletException("Invalid charset passed for query string encoding", e);

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletResponse.java

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
*/
1313
package com.amazonaws.serverless.proxy.internal.servlet;
1414

15-
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
1615
import com.amazonaws.serverless.proxy.internal.SecurityUtils;
16+
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
1717

1818
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
1919
import org.slf4j.Logger;
@@ -24,7 +24,6 @@
2424
import javax.servlet.http.Cookie;
2525
import javax.servlet.http.HttpServletResponse;
2626
import javax.ws.rs.core.HttpHeaders;
27-
import javax.ws.rs.core.MultivaluedHashMap;
2827
import java.io.ByteArrayOutputStream;
2928
import java.io.IOException;
3029
import java.io.OutputStreamWriter;
@@ -53,7 +52,7 @@ public class AwsHttpServletResponse
5352
// Variables - Private
5453
//-------------------------------------------------------------
5554

56-
private MultivaluedHashMap<String, String> headers = new MultivaluedHashMap<>();
55+
private MultiValuedTreeMap<String, String> headers = new MultiValuedTreeMap<>(String.CASE_INSENSITIVE_ORDER);
5756
private int statusCode;
5857
private String statusMessage;
5958
private String responseBody;
@@ -202,7 +201,12 @@ public void setHeader(String s, String s1) {
202201

203202
@Override
204203
public void addHeader(String s, String s1) {
205-
setHeader(s, s1, false);
204+
// TODO: We should probably have a list of headers that we are not allowed to have multiple values for
205+
if (s.toLowerCase(Locale.getDefault()).equals(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.getDefault()))) {
206+
setHeader(s, s1, true);
207+
} else {
208+
setHeader(s, s1, false);
209+
}
206210
}
207211

208212

@@ -400,7 +404,7 @@ public boolean isCommitted() {
400404

401405
@Override
402406
public void reset() {
403-
headers = new MultivaluedHashMap<>();
407+
headers = new MultiValuedTreeMap<>();
404408
responseBody = null;
405409
writer = null;
406410
bodyOutputStream = new ByteArrayOutputStream();
@@ -435,28 +439,8 @@ byte[] getAwsResponseBodyBytes() {
435439
}
436440

437441

438-
Map<String, String> getAwsResponseHeaders() {
439-
Map<String, String> responseHeaders = new TreeMap<>(String::compareToIgnoreCase);
440-
for (String header : getHeaderNames()) {
441-
// special behavior for set cookie
442-
// RFC 2109 allows for a comma separated list of cookies in one Set-Cookie header: https://tools.ietf.org/html/rfc2109
443-
if (header.equals(HttpHeaders.SET_COOKIE) && LambdaContainerHandler.getContainerConfig().isConsolidateSetCookieHeaders()) {
444-
StringBuilder cookieHeader = new StringBuilder();
445-
for (String cookieValue : headers.get(header)) {
446-
if (cookieHeader.length() > 0) {
447-
cookieHeader.append(",");
448-
}
449-
450-
cookieHeader.append(" ").append(cookieValue);
451-
}
452-
453-
responseHeaders.put(header, cookieHeader.toString());
454-
} else {
455-
responseHeaders.put(header, headers.get(header).get(headers.get(header).size() - 1));
456-
}
457-
}
458-
459-
return responseHeaders;
442+
MultiValuedTreeMap<String, String> getAwsResponseHeaders() {
443+
return headers;
460444
}
461445

462446

0 commit comments

Comments
 (0)