From 46ec9fa2f523426a013ddc49f2a42873dd9a2d03 Mon Sep 17 00:00:00 2001 From: Jerome Van Der Linden Date: Sat, 27 Mar 2021 10:19:49 +0100 Subject: [PATCH 1/6] fix issue #220, using treemap --- .../events/APIGatewayProxyRequestEvent.java | 104 +++++++++++++++--- .../lambda/runtime/tests/EventLoaderTest.java | 3 + .../src/test/resources/apigw_rest_event.json | 5 +- 3 files changed, 93 insertions(+), 19 deletions(-) diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java index f9c118ca..70edb415 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java @@ -1,8 +1,7 @@ package com.amazonaws.services.lambda.runtime.events; import java.io.Serializable; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Class that represents an APIGatewayProxyRequestEvent @@ -17,9 +16,9 @@ public class APIGatewayProxyRequestEvent implements Serializable, Cloneable { private String httpMethod; - private Map headers; + private Headers headers = new Headers<>(); - private Map> multiValueHeaders; + private Headers> multiValueHeaders = new Headers<>(); private Map queryStringParameters; @@ -35,6 +34,77 @@ public class APIGatewayProxyRequestEvent implements Serializable, Cloneable { private Boolean isBase64Encoded; + /** + * Class that represents Http Headers. + * + * Not using a standard map, because we need insensitive case. + */ + public static class Headers implements Map { + + // Headers are case insensitive (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) + private Map map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public T get(Object key) { + return map.get(key); + } + + @Override + public T put(String key, T value) { + return map.put(key, value); + } + + @Override + public T remove(Object key) { + return map.remove(key); + } + + @Override + public void putAll(Map m) { + map.putAll(m); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + } + /** * class that represents proxy request context */ @@ -67,7 +137,8 @@ public static class ProxyRequestContext implements Serializable, Cloneable { /** * default constructor */ - public ProxyRequestContext() {} + public ProxyRequestContext() { + } /** * @return account id that owns Lambda function @@ -101,7 +172,7 @@ public void setAuthorizer(final Map authorizer) { } /** - * @return API Gateway stage name + * @return API Gateway stage name */ public String getStage() { return stage; @@ -286,14 +357,14 @@ public ProxyRequestContext withPath(String path) { /** * @return The name of the operation being performed - * */ + */ public String getOperationName() { return operationName; } /** * @param operationName The name of the operation being performed - * */ + */ public void setOperationName(String operationName) { this.operationName = operationName; } @@ -307,7 +378,6 @@ public ProxyRequestContext withOperationName(String operationName) { * Returns a string representation of this object; useful for testing and debugging. * * @return A string representation of this object. - * * @see Object#toString() */ @Override @@ -412,7 +482,7 @@ public int hashCode() { hashCode = prime * hashCode + ((getApiId() == null) ? 0 : getApiId().hashCode()); hashCode = prime * hashCode + ((getPath() == null) ? 0 : getPath().hashCode()); hashCode = prime * hashCode + ((getAuthorizer() == null) ? 0 : getAuthorizer().hashCode()); - hashCode = prime * hashCode + ((getOperationName() == null) ? 0: getOperationName().hashCode()); + hashCode = prime * hashCode + ((getOperationName() == null) ? 0 : getOperationName().hashCode()); return hashCode; } @@ -457,7 +527,8 @@ public static class RequestIdentity implements Serializable, Cloneable { /** * default constructor */ - public RequestIdentity() {} + public RequestIdentity() { + } /** * @return The Cognito identity pool id. @@ -739,7 +810,6 @@ public RequestIdentity withAccessKey(String accessKey) { * Returns a string representation of this object; useful for testing and debugging. * * @return A string representation of this object. - * * @see Object#toString() */ @Override @@ -869,7 +939,8 @@ public RequestIdentity clone() { /** * default constructor */ - public APIGatewayProxyRequestEvent() {} + public APIGatewayProxyRequestEvent() { + } /** * @return The resource path defined in API Gateway @@ -944,14 +1015,14 @@ public APIGatewayProxyRequestEvent withHttpMethod(String httpMethod) { * @return The headers sent with the request */ public Map getHeaders() { - return headers; + return headers.map; } /** * @param headers The headers sent with the request */ public void setHeaders(Map headers) { - this.headers = headers; + this.headers.putAll(headers); } /** @@ -974,7 +1045,7 @@ public Map> getMultiValueHeaders() { * @param multiValueHeaders The multi value headers sent with the request */ public void setMultiValueHeaders(Map> multiValueHeaders) { - this.multiValueHeaders = multiValueHeaders; + this.multiValueHeaders.putAll(multiValueHeaders); } /** @@ -1167,7 +1238,6 @@ public APIGatewayProxyRequestEvent withIsBase64Encoded(Boolean isBase64Encoded) * Returns a string representation of this object; useful for testing and debugging. * * @return A string representation of this object. - * * @see Object#toString() */ @Override diff --git a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java index aecd0c6a..2f4fdac5 100644 --- a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java +++ b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java @@ -26,6 +26,9 @@ public void testLoadApiGatewayRestEvent() { assertThat(event).isNotNull(); assertThat(event.getBody()).isEqualTo("Hello from Lambda!"); + + assertThat(event.getHeaders().get("Header1")).isEqualTo("value1"); + assertThat(event.getHeaders().get("header1")).isEqualTo("value1"); assertThat(event.getHeaders()).hasSize(2); } diff --git a/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json b/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json index 28f10c22..db7f291c 100644 --- a/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json +++ b/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json @@ -4,8 +4,9 @@ "path": "/my/path", "httpMethod": "GET", "headers": { - "Header1": "value1", - "Header2": "value2" + "Header1": "Value1", + "Header2": "value2", + "header1": "value1" }, "multiValueHeaders": { "Header1": [ From 8e5bbb981b2b97566e75bac4991b9988bbfd3685 Mon Sep 17 00:00:00 2001 From: Jerome Van Der Linden Date: Sat, 27 Mar 2021 19:21:59 +0100 Subject: [PATCH 2/6] use case insensitive headers in all events --- .../APIGatewayCustomAuthorizerEvent.java | 3 +- .../events/APIGatewayProxyRequestEvent.java | 93 ++++--------------- .../events/APIGatewayProxyResponseEvent.java | 20 +++- .../APIGatewayV2CustomAuthorizerEvent.java | 3 +- .../runtime/events/APIGatewayV2HTTPEvent.java | 3 +- .../events/APIGatewayV2HTTPResponse.java | 5 +- .../events/APIGatewayV2WebSocketResponse.java | 20 +++- .../ApplicationLoadBalancerRequestEvent.java | 5 +- .../ApplicationLoadBalancerResponseEvent.java | 5 +- .../runtime/events/models/HttpHeaders.java | 78 ++++++++++++++++ .../lambda/runtime/tests/EventLoaderTest.java | 14 +++ .../src/test/resources/apigw_auth.json | 1 + .../src/test/resources/apigw_auth_v2.json | 5 +- .../src/test/resources/apigw_http_event.json | 5 +- .../src/test/resources/apigw_rest_event.json | 4 + .../src/test/resources/elb_event.json | 1 + 16 files changed, 168 insertions(+), 97 deletions(-) create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayCustomAuthorizerEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayCustomAuthorizerEvent.java index 72883319..e7e448ab 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayCustomAuthorizerEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayCustomAuthorizerEvent.java @@ -1,5 +1,6 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -26,7 +27,7 @@ public class APIGatewayCustomAuthorizerEvent { private String resource; private String path; private String httpMethod; - private Map headers; + private HttpHeaders headers; private Map queryStringParameters; private Map pathParameters; private Map stageVariables; diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java index 70edb415..3df5da97 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java @@ -1,5 +1,7 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; + import java.io.Serializable; import java.util.*; @@ -16,9 +18,9 @@ public class APIGatewayProxyRequestEvent implements Serializable, Cloneable { private String httpMethod; - private Headers headers = new Headers<>(); + private HttpHeaders headers; - private Headers> multiValueHeaders = new Headers<>(); + private HttpHeaders> multiValueHeaders; private Map queryStringParameters; @@ -34,77 +36,6 @@ public class APIGatewayProxyRequestEvent implements Serializable, Cloneable { private Boolean isBase64Encoded; - /** - * Class that represents Http Headers. - * - * Not using a standard map, because we need insensitive case. - */ - public static class Headers implements Map { - - // Headers are case insensitive (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) - private Map map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - - @Override - public int size() { - return map.size(); - } - - @Override - public boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return map.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return map.containsValue(value); - } - - @Override - public T get(Object key) { - return map.get(key); - } - - @Override - public T put(String key, T value) { - return map.put(key, value); - } - - @Override - public T remove(Object key) { - return map.remove(key); - } - - @Override - public void putAll(Map m) { - map.putAll(m); - } - - @Override - public void clear() { - map.clear(); - } - - @Override - public Set keySet() { - return map.keySet(); - } - - @Override - public Collection values() { - return map.values(); - } - - @Override - public Set> entrySet() { - return map.entrySet(); - } - } - /** * class that represents proxy request context */ @@ -1015,14 +946,19 @@ public APIGatewayProxyRequestEvent withHttpMethod(String httpMethod) { * @return The headers sent with the request */ public Map getHeaders() { - return headers.map; + return headers; } /** * @param headers The headers sent with the request */ public void setHeaders(Map headers) { - this.headers.putAll(headers); + if (this.headers == null && headers != null && !headers.isEmpty()) { + this.headers = new HttpHeaders<>(); + } + if (headers != null && !headers.isEmpty()) { + this.headers.putAll(headers); + } } /** @@ -1045,7 +981,12 @@ public Map> getMultiValueHeaders() { * @param multiValueHeaders The multi value headers sent with the request */ public void setMultiValueHeaders(Map> multiValueHeaders) { - this.multiValueHeaders.putAll(multiValueHeaders); + if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders = new HttpHeaders<>(); + } + if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders.putAll(multiValueHeaders); + } } /** diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java index fb1f87c3..22fc1ee1 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java @@ -1,5 +1,7 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; + import java.io.Serializable; import java.util.List; import java.util.Map; @@ -13,9 +15,9 @@ public class APIGatewayProxyResponseEvent implements Serializable, Cloneable { private Integer statusCode; - private Map headers; + private HttpHeaders headers; - private Map> multiValueHeaders; + private HttpHeaders> multiValueHeaders; private String body; @@ -60,7 +62,12 @@ public Map getHeaders() { * @param headers The Http headers return in the response */ public void setHeaders(Map headers) { - this.headers = headers; + if (this.headers == null && headers != null && !headers.isEmpty()) { + this.headers = new HttpHeaders<>(); + } + if (headers != null && !headers.isEmpty()) { + this.headers.putAll(headers); + } } /** @@ -83,7 +90,12 @@ public Map> getMultiValueHeaders() { * @param multiValueHeaders the Http multi value headers to return in the response */ public void setMultiValueHeaders(Map> multiValueHeaders) { - this.multiValueHeaders = multiValueHeaders; + if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders = new HttpHeaders<>(); + } + if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders.putAll(multiValueHeaders); + } } /** diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2CustomAuthorizerEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2CustomAuthorizerEvent.java index 6abfe051..893cce24 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2CustomAuthorizerEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2CustomAuthorizerEvent.java @@ -1,5 +1,6 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -31,7 +32,7 @@ public class APIGatewayV2CustomAuthorizerEvent { private String rawPath; private String rawQueryString; private List cookies; - private Map headers; + private HttpHeaders headers; private Map queryStringParameters; private RequestContext requestContext; private Map pathParameters; diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java index 34894023..9292888e 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java @@ -13,6 +13,7 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -34,7 +35,7 @@ public class APIGatewayV2HTTPEvent { private String rawPath; private String rawQueryString; private List cookies; - private Map headers; + private HttpHeaders headers; private Map queryStringParameters; private Map pathParameters; private Map stageVariables; diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java index 2bd81fad..43fdc8bd 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java @@ -13,6 +13,7 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -27,8 +28,8 @@ @NoArgsConstructor public class APIGatewayV2HTTPResponse { private int statusCode; - private Map headers; - private Map> multiValueHeaders; + private HttpHeaders headers; + private HttpHeaders> multiValueHeaders; private List cookies; private String body; private boolean isBase64Encoded; diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java index 87e4284c..3682db5b 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java @@ -1,5 +1,7 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; + import java.io.Serializable; import java.util.Map; @@ -12,8 +14,8 @@ public class APIGatewayV2WebSocketResponse implements Serializable, Cloneable { private boolean isBase64Encoded = false; private int statusCode; - private Map headers; - private Map multiValueHeaders; + private HttpHeaders headers; + private HttpHeaders multiValueHeaders; private String body; public boolean isIsBase64Encoded() { @@ -37,7 +39,12 @@ public Map getHeaders() { } public void setHeaders(Map headers) { - this.headers = headers; + if (this.headers == null && headers != null && !headers.isEmpty()) { + this.headers = new HttpHeaders<>(); + } + if (headers != null && !headers.isEmpty()) { + this.headers.putAll(headers); + } } public Map getMultiValueHeaders() { @@ -45,7 +52,12 @@ public Map getMultiValueHeaders() { } public void setMultiValueHeaders(Map multiValueHeaders) { - this.multiValueHeaders = multiValueHeaders; + if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders = new HttpHeaders<>(); + } + if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders.putAll(multiValueHeaders); + } } public String getBody() { diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerRequestEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerRequestEvent.java index e7b33117..f42be334 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerRequestEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerRequestEvent.java @@ -1,5 +1,6 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; import lombok.Data; import lombok.NoArgsConstructor; @@ -40,8 +41,8 @@ public static class RequestContext implements Serializable, Cloneable { private String path; private Map queryStringParameters; private Map> multiValueQueryStringParameters; - private Map headers; - private Map> multiValueHeaders; + private HttpHeaders headers; + private HttpHeaders> multiValueHeaders; private String body; private boolean isBase64Encoded; diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerResponseEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerResponseEvent.java index 135de143..3da8951e 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerResponseEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/ApplicationLoadBalancerResponseEvent.java @@ -1,5 +1,6 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; import lombok.Data; import lombok.NoArgsConstructor; @@ -22,8 +23,8 @@ public class ApplicationLoadBalancerResponseEvent implements Serializable, Clone private int statusCode; private String statusDescription; private boolean isBase64Encoded; - private Map headers; - private Map> multiValueHeaders; + private HttpHeaders headers; + private HttpHeaders> multiValueHeaders; private String body; } diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java new file mode 100644 index 00000000..e4cd6a03 --- /dev/null +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java @@ -0,0 +1,78 @@ +package com.amazonaws.services.lambda.runtime.events.models; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Class that represents Http Headers. + *
+ * Not using a standard map, because we need insensitive case. + */ +public class HttpHeaders implements Map { + + // Headers are case insensitive (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) + private Map map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public T get(Object key) { + return map.get(key); + } + + @Override + public T put(String key, T value) { + return map.put(key, value); + } + + @Override + public T remove(Object key) { + return map.remove(key); + } + + @Override + public void putAll(Map m) { + map.putAll(m); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + +} diff --git a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java index 2f4fdac5..de9f8974 100644 --- a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java +++ b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java @@ -29,6 +29,8 @@ public void testLoadApiGatewayRestEvent() { assertThat(event.getHeaders().get("Header1")).isEqualTo("value1"); assertThat(event.getHeaders().get("header1")).isEqualTo("value1"); + assertThat(event.getMultiValueHeaders().get("header1")).contains("value1", "value11"); + assertThat(event.getMultiValueHeaders().get("Header1")).contains("value1", "value11"); assertThat(event.getHeaders()).hasSize(2); } @@ -38,6 +40,9 @@ public void testLoadApiGatewayHttpEvent() { assertThat(event).isNotNull(); assertThat(event.getBody()).isEqualTo("Hello from Lambda!!"); + + assertThat(event.getHeaders().get("Header1")).isEqualTo("value1"); + assertThat(event.getHeaders().get("header1")).isEqualTo("value1"); } @Test @@ -47,6 +52,9 @@ public void testLoadAPIGatewayCustomAuthorizerEvent() { assertThat(event).isNotNull(); assertThat(event.getRequestContext().getHttpMethod()).isEqualTo("GET"); assertThat(event.getHeaders()).hasSize(8); + + assertThat(event.getHeaders().get("Accept")).isEqualTo("application/json"); + assertThat(event.getHeaders().get("accept")).isEqualTo("application/json"); } @Test @@ -56,6 +64,9 @@ public void testLoadAPIGatewayV2CustomAuthorizerEvent() { assertThat(event).isNotNull(); assertThat(event.getRequestContext().getHttp().getMethod()).isEqualTo("POST"); assertThat(event.getRequestContext().getTimeEpoch()).isEqualTo(Instant.ofEpochMilli(1583348638390L)); + + assertThat(event.getHeaders().get("Header1")).isEqualTo("Value1"); + assertThat(event.getHeaders().get("header1")).isEqualTo("Value1"); } @Test @@ -64,6 +75,9 @@ public void testLoadApplicationLoadBalancerRequestEvent() { assertThat(event).isNotNull(); assertThat(event.getBody()).isEqualTo("Hello from ELB"); + + assertThat(event.getHeaders().get("Accept")).isEqualTo("application/json"); + assertThat(event.getHeaders().get("accept")).isEqualTo("application/json"); } @Test diff --git a/aws-lambda-java-tests/src/test/resources/apigw_auth.json b/aws-lambda-java-tests/src/test/resources/apigw_auth.json index eb73956e..bfe2d112 100644 --- a/aws-lambda-java-tests/src/test/resources/apigw_auth.json +++ b/aws-lambda-java-tests/src/test/resources/apigw_auth.json @@ -10,6 +10,7 @@ "headers": { "X-AMZ-Date": "20170718T062915Z", "Accept": "*/*", + "accept": "application/json", "HeaderAuth1": "headerValue1", "CloudFront-Viewer-Country": "US", "CloudFront-Forwarded-Proto": "https", diff --git a/aws-lambda-java-tests/src/test/resources/apigw_auth_v2.json b/aws-lambda-java-tests/src/test/resources/apigw_auth_v2.json index a603763e..70024f22 100644 --- a/aws-lambda-java-tests/src/test/resources/apigw_auth_v2.json +++ b/aws-lambda-java-tests/src/test/resources/apigw_auth_v2.json @@ -8,8 +8,9 @@ "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", "cookies": [ "cookie1", "cookie2" ], "headers": { - "Header1": "value1", - "Header2": "value2" + "header1": "value1", + "Header2": "value2", + "Header1": "Value1" }, "queryStringParameters": { "parameter1": "value1,value2", "parameter2": "value" }, "requestContext": { diff --git a/aws-lambda-java-tests/src/test/resources/apigw_http_event.json b/aws-lambda-java-tests/src/test/resources/apigw_http_event.json index 88f4e5b4..43c7e4b3 100644 --- a/aws-lambda-java-tests/src/test/resources/apigw_http_event.json +++ b/aws-lambda-java-tests/src/test/resources/apigw_http_event.json @@ -8,8 +8,9 @@ "cookie2" ], "headers": { - "Header1": "value1", - "Header2": "value1,value2" + "Header1": "Value1", + "Header2": "value1,value2", + "header1": "value1" }, "queryStringParameters": { "parameter1": "value1,value2", diff --git a/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json b/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json index db7f291c..e7907d58 100644 --- a/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json +++ b/aws-lambda-java-tests/src/test/resources/apigw_rest_event.json @@ -15,6 +15,10 @@ "Header2": [ "value1", "value2" + ], + "header1": [ + "value1", + "value11" ] }, "queryStringParameters": { diff --git a/aws-lambda-java-tests/src/test/resources/elb_event.json b/aws-lambda-java-tests/src/test/resources/elb_event.json index 23f599f4..59e314b7 100644 --- a/aws-lambda-java-tests/src/test/resources/elb_event.json +++ b/aws-lambda-java-tests/src/test/resources/elb_event.json @@ -9,6 +9,7 @@ "queryStringParameters": {}, "headers": { "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept": "application/json", "accept-encoding": "gzip", "accept-language": "en-US,en;q=0.5", "connection": "keep-alive", From 28333c0ae76112b086b65092f74805af9767d949 Mon Sep 17 00:00:00 2001 From: Jerome Van Der Linden Date: Mon, 29 Mar 2021 10:09:06 +0200 Subject: [PATCH 3/6] refactor + headers in websocket event --- .../events/APIGatewayProxyRequestEvent.java | 22 ++++++++++------ .../events/APIGatewayProxyResponseEvent.java | 22 ++++++++++------ .../events/APIGatewayV2WebSocketEvent.java | 26 ++++++++++++++++--- .../events/APIGatewayV2WebSocketResponse.java | 22 ++++++++++------ 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java index 3df5da97..9257de13 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java @@ -953,12 +953,15 @@ public Map getHeaders() { * @param headers The headers sent with the request */ public void setHeaders(Map headers) { - if (this.headers == null && headers != null && !headers.isEmpty()) { - this.headers = new HttpHeaders<>(); + if (headers == null || headers.isEmpty()) { + this.headers = null; + return; } - if (headers != null && !headers.isEmpty()) { - this.headers.putAll(headers); + + if (this.headers == null) { + this.headers = new HttpHeaders<>(); } + this.headers.putAll(headers); } /** @@ -981,12 +984,15 @@ public Map> getMultiValueHeaders() { * @param multiValueHeaders The multi value headers sent with the request */ public void setMultiValueHeaders(Map> multiValueHeaders) { - if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { - this.multiValueHeaders = new HttpHeaders<>(); + if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { + this.multiValueHeaders = null; + return; } - if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { - this.multiValueHeaders.putAll(multiValueHeaders); + + if (this.multiValueHeaders == null) { + this.multiValueHeaders = new HttpHeaders<>(); } + this.multiValueHeaders.putAll(multiValueHeaders); } /** diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java index 22fc1ee1..18c625cd 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java @@ -62,12 +62,15 @@ public Map getHeaders() { * @param headers The Http headers return in the response */ public void setHeaders(Map headers) { - if (this.headers == null && headers != null && !headers.isEmpty()) { - this.headers = new HttpHeaders<>(); + if (headers == null || headers.isEmpty()) { + this.headers = null; + return; } - if (headers != null && !headers.isEmpty()) { - this.headers.putAll(headers); + + if (this.headers == null) { + this.headers = new HttpHeaders<>(); } + this.headers.putAll(headers); } /** @@ -90,12 +93,15 @@ public Map> getMultiValueHeaders() { * @param multiValueHeaders the Http multi value headers to return in the response */ public void setMultiValueHeaders(Map> multiValueHeaders) { - if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { - this.multiValueHeaders = new HttpHeaders<>(); + if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { + this.multiValueHeaders = null; + return; } - if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { - this.multiValueHeaders.putAll(multiValueHeaders); + + if (this.multiValueHeaders == null) { + this.multiValueHeaders = new HttpHeaders<>(); } + this.multiValueHeaders.putAll(multiValueHeaders); } /** diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java index 43a9966b..03a8819b 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java @@ -1,5 +1,7 @@ package com.amazonaws.services.lambda.runtime.events; +import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; + import java.io.Serializable; import java.util.List; import java.util.Map; @@ -556,8 +558,8 @@ public boolean equals(Object obj) { private String resource; private String path; private String httpMethod; - private Map headers; - private Map> multiValueHeaders; + private HttpHeaders headers; + private HttpHeaders> multiValueHeaders; private Map queryStringParameters; private Map> multiValueQueryStringParameters; private Map pathParameters; @@ -595,7 +597,15 @@ public Map getHeaders() { } public void setHeaders(Map headers) { - this.headers = headers; + if (headers == null || headers.isEmpty()) { + this.headers = null; + return; + } + + if (this.headers == null) { + this.headers = new HttpHeaders<>(); + } + this.headers.putAll(headers); } public Map> getMultiValueHeaders() { @@ -603,7 +613,15 @@ public Map> getMultiValueHeaders() { } public void setMultiValueHeaders(Map> multiValueHeaders) { - this.multiValueHeaders = multiValueHeaders; + if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { + this.multiValueHeaders = null; + return; + } + + if (this.multiValueHeaders == null) { + this.multiValueHeaders = new HttpHeaders<>(); + } + this.multiValueHeaders.putAll(multiValueHeaders); } public Map getQueryStringParameters() { diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java index 3682db5b..918d5d92 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java @@ -39,12 +39,15 @@ public Map getHeaders() { } public void setHeaders(Map headers) { - if (this.headers == null && headers != null && !headers.isEmpty()) { - this.headers = new HttpHeaders<>(); + if (headers == null || headers.isEmpty()) { + this.headers = null; + return; } - if (headers != null && !headers.isEmpty()) { - this.headers.putAll(headers); + + if (this.headers == null) { + this.headers = new HttpHeaders<>(); } + this.headers.putAll(headers); } public Map getMultiValueHeaders() { @@ -52,12 +55,15 @@ public Map getMultiValueHeaders() { } public void setMultiValueHeaders(Map multiValueHeaders) { - if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { - this.multiValueHeaders = new HttpHeaders<>(); + if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { + this.multiValueHeaders = null; + return; } - if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { - this.multiValueHeaders.putAll(multiValueHeaders); + + if (this.multiValueHeaders == null) { + this.multiValueHeaders = new HttpHeaders<>(); } + this.multiValueHeaders.putAll(multiValueHeaders); } public String getBody() { From f3e80cca8a3f612b8bc8a2b874f5b61d4ac78748 Mon Sep 17 00:00:00 2001 From: Jerome Van Der Linden Date: Mon, 29 Mar 2021 23:37:04 +0200 Subject: [PATCH 4/6] corrections after real test --- .../runtime/events/APIGatewayV2HTTPEvent.java | 13 +++++++ .../events/APIGatewayV2HTTPResponse.java | 35 +++++++++++++++++++ .../runtime/events/models/HttpHeaders.java | 2 +- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java index 9292888e..cf6f67bb 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java @@ -43,6 +43,19 @@ public class APIGatewayV2HTTPEvent { private boolean isBase64Encoded; private RequestContext requestContext; + public void setHeaders(Map headers) { + System.out.println("setHeaders"); + if (headers == null || headers.isEmpty()) { + this.headers = null; + return; + } + + if (this.headers == null) { + this.headers = new HttpHeaders<>(); + } + this.headers.putAll(headers); + } + @AllArgsConstructor @Builder(setterPrefix = "with") @Data diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java index 43fdc8bd..101dd4ea 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java @@ -33,4 +33,39 @@ public class APIGatewayV2HTTPResponse { private List cookies; private String body; private boolean isBase64Encoded; + + public static APIGatewayV2HTTPResponseBuilder builder() { + return new APIGatewayV2HTTPResponseBuilder(); + } + + public static class APIGatewayV2HTTPResponseBuilder { + private HttpHeaders headers; + private HttpHeaders> multiValueHeaders; + + public APIGatewayV2HTTPResponseBuilder withHeaders(Map headers) { + if (headers == null || headers.isEmpty()) { + this.headers = null; + return this; + } + + if (this.headers == null) { + this.headers = new HttpHeaders<>(); + } + this.headers.putAll(headers); + return this; + } + + public APIGatewayV2HTTPResponseBuilder withMultiValueHeaders(Map> multiValueHeaders) { + if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { + this.multiValueHeaders = null; + return this; + } + + if (this.multiValueHeaders == null) { + this.multiValueHeaders = new HttpHeaders<>(); + } + this.multiValueHeaders.putAll(multiValueHeaders); + return this; + } + } } diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java index e4cd6a03..caa0e7a7 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java @@ -13,7 +13,7 @@ public class HttpHeaders implements Map { // Headers are case insensitive (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) - private Map map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + private final Map map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); @Override public int size() { From d997cfe3f90dae13198b50276d17e251ebb3be09 Mon Sep 17 00:00:00 2001 From: Jerome Van Der Linden Date: Wed, 7 Apr 2021 18:05:50 +0200 Subject: [PATCH 5/6] remove sysout --- .../services/lambda/runtime/events/APIGatewayV2HTTPEvent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java index cf6f67bb..8dda8b54 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java @@ -44,7 +44,6 @@ public class APIGatewayV2HTTPEvent { private RequestContext requestContext; public void setHeaders(Map headers) { - System.out.println("setHeaders"); if (headers == null || headers.isEmpty()) { this.headers = null; return; From 72a0ecf4d0dedc334bcedd7890cb3050e62fd829 Mon Sep 17 00:00:00 2001 From: Jerome Van Der Linden Date: Sat, 29 May 2021 18:57:24 +0200 Subject: [PATCH 6/6] revert http headers --- .../events/APIGatewayV2WebSocketEvent.java | 26 +++---------------- .../events/APIGatewayV2WebSocketResponse.java | 22 ++++++---------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java index 03a8819b..43a9966b 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketEvent.java @@ -1,7 +1,5 @@ package com.amazonaws.services.lambda.runtime.events; -import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders; - import java.io.Serializable; import java.util.List; import java.util.Map; @@ -558,8 +556,8 @@ public boolean equals(Object obj) { private String resource; private String path; private String httpMethod; - private HttpHeaders headers; - private HttpHeaders> multiValueHeaders; + private Map headers; + private Map> multiValueHeaders; private Map queryStringParameters; private Map> multiValueQueryStringParameters; private Map pathParameters; @@ -597,15 +595,7 @@ public Map getHeaders() { } public void setHeaders(Map headers) { - if (headers == null || headers.isEmpty()) { - this.headers = null; - return; - } - - if (this.headers == null) { - this.headers = new HttpHeaders<>(); - } - this.headers.putAll(headers); + this.headers = headers; } public Map> getMultiValueHeaders() { @@ -613,15 +603,7 @@ public Map> getMultiValueHeaders() { } public void setMultiValueHeaders(Map> multiValueHeaders) { - if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { - this.multiValueHeaders = null; - return; - } - - if (this.multiValueHeaders == null) { - this.multiValueHeaders = new HttpHeaders<>(); - } - this.multiValueHeaders.putAll(multiValueHeaders); + this.multiValueHeaders = multiValueHeaders; } public Map getQueryStringParameters() { diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java index 918d5d92..3682db5b 100644 --- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java +++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java @@ -39,15 +39,12 @@ public Map getHeaders() { } public void setHeaders(Map headers) { - if (headers == null || headers.isEmpty()) { - this.headers = null; - return; - } - - if (this.headers == null) { + if (this.headers == null && headers != null && !headers.isEmpty()) { this.headers = new HttpHeaders<>(); } - this.headers.putAll(headers); + if (headers != null && !headers.isEmpty()) { + this.headers.putAll(headers); + } } public Map getMultiValueHeaders() { @@ -55,15 +52,12 @@ public Map getMultiValueHeaders() { } public void setMultiValueHeaders(Map multiValueHeaders) { - if (multiValueHeaders == null || multiValueHeaders.isEmpty()) { - this.multiValueHeaders = null; - return; - } - - if (this.multiValueHeaders == null) { + if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) { this.multiValueHeaders = new HttpHeaders<>(); } - this.multiValueHeaders.putAll(multiValueHeaders); + if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) { + this.multiValueHeaders.putAll(multiValueHeaders); + } } public String getBody() {