Skip to content

Commit fdfaf16

Browse files
committed
aws#220 Fix header case sensitivity (updated aws#234)
This solution builds upon @jeromevdl 's solution of PR aws#234 to fix the issue of headers being case sensitive. Fixes @carlzogh 's comment regarding breaking changes in setHeaders.
1 parent 4569e72 commit fdfaf16

File tree

11 files changed

+379
-94
lines changed

11 files changed

+379
-94
lines changed

aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyRequestEvent.java

+2-18
Original file line numberDiff line numberDiff line change
@@ -1010,15 +1010,7 @@ public Map<String, String> getHeaders() {
10101010
* @param headers The headers sent with the request
10111011
*/
10121012
public void setHeaders(Map<String, String> headers) {
1013-
if (headers == null || headers.isEmpty()) {
1014-
this.headers = null;
1015-
return;
1016-
}
1017-
1018-
if (this.headers == null) {
1019-
this.headers = new HttpHeaders<>();
1020-
}
1021-
this.headers.putAll(headers);
1013+
this.headers = HttpHeadersUtil.mergeOrReplace(headers);
10221014
}
10231015

10241016
/**
@@ -1041,15 +1033,7 @@ public Map<String, List<String>> getMultiValueHeaders() {
10411033
* @param multiValueHeaders The multi value headers sent with the request
10421034
*/
10431035
public void setMultiValueHeaders(Map<String, List<String>> multiValueHeaders) {
1044-
if (multiValueHeaders == null || multiValueHeaders.isEmpty()) {
1045-
this.multiValueHeaders = null;
1046-
return;
1047-
}
1048-
1049-
if (this.multiValueHeaders == null) {
1050-
this.multiValueHeaders = new HttpHeaders<>();
1051-
}
1052-
this.multiValueHeaders.putAll(multiValueHeaders);
1036+
this.multiValueHeaders = HttpHeadersUtil.mergeOrReplace(multiValueHeaders);
10531037
}
10541038

10551039
/**

aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayProxyResponseEvent.java

+2-18
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,7 @@ public Map<String, String> getHeaders() {
6262
* @param headers The Http headers return in the response
6363
*/
6464
public void setHeaders(Map<String, String> headers) {
65-
if (headers == null || headers.isEmpty()) {
66-
this.headers = null;
67-
return;
68-
}
69-
70-
if (this.headers == null) {
71-
this.headers = new HttpHeaders<>();
72-
}
73-
this.headers.putAll(headers);
65+
this.headers = HttpHeadersUtil.mergeOrReplace(headers);
7466
}
7567

7668
/**
@@ -93,15 +85,7 @@ public Map<String, List<String>> getMultiValueHeaders() {
9385
* @param multiValueHeaders the Http multi value headers to return in the response
9486
*/
9587
public void setMultiValueHeaders(Map<String, List<String>> multiValueHeaders) {
96-
if (multiValueHeaders == null || multiValueHeaders.isEmpty()) {
97-
this.multiValueHeaders = null;
98-
return;
99-
}
100-
101-
if (this.multiValueHeaders == null) {
102-
this.multiValueHeaders = new HttpHeaders<>();
103-
}
104-
this.multiValueHeaders.putAll(multiValueHeaders);
88+
this.multiValueHeaders = HttpHeadersUtil.mergeOrReplace(multiValueHeaders);
10589
}
10690

10791
/**

aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPEvent.java

+1-9
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,7 @@ public class APIGatewayV2HTTPEvent {
4444
private RequestContext requestContext;
4545

4646
public void setHeaders(Map<String, String> headers) {
47-
if (headers == null || headers.isEmpty()) {
48-
this.headers = null;
49-
return;
50-
}
51-
52-
if (this.headers == null) {
53-
this.headers = new HttpHeaders<>();
54-
}
55-
this.headers.putAll(headers);
47+
this.headers = HttpHeadersUtil.mergeOrReplace(headers);
5648
}
5749

5850
@AllArgsConstructor

aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2HTTPResponse.java

+2-18
Original file line numberDiff line numberDiff line change
@@ -43,28 +43,12 @@ public static class APIGatewayV2HTTPResponseBuilder {
4343
private HttpHeaders<List<String>> multiValueHeaders;
4444

4545
public APIGatewayV2HTTPResponseBuilder withHeaders(Map<String, String> headers) {
46-
if (headers == null || headers.isEmpty()) {
47-
this.headers = null;
48-
return this;
49-
}
50-
51-
if (this.headers == null) {
52-
this.headers = new HttpHeaders<>();
53-
}
54-
this.headers.putAll(headers);
46+
this.headers = HttpHeadersUtil.mergeOrReplace(headers);
5547
return this;
5648
}
5749

5850
public APIGatewayV2HTTPResponseBuilder withMultiValueHeaders(Map<String, List<String>> multiValueHeaders) {
59-
if (multiValueHeaders == null || multiValueHeaders.isEmpty()) {
60-
this.multiValueHeaders = null;
61-
return this;
62-
}
63-
64-
if (this.multiValueHeaders == null) {
65-
this.multiValueHeaders = new HttpHeaders<>();
66-
}
67-
this.multiValueHeaders.putAll(multiValueHeaders);
51+
this.multiValueHeaders = HttpHeadersUtil.mergeOrReplace(multiValueHeaders);
6852
return this;
6953
}
7054
}

aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/APIGatewayV2WebSocketResponse.java

+2-12
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,15 @@ public Map<String, String> getHeaders() {
3939
}
4040

4141
public void setHeaders(Map<String, String> headers) {
42-
if (this.headers == null && headers != null && !headers.isEmpty()) {
43-
this.headers = new HttpHeaders<>();
44-
}
45-
if (headers != null && !headers.isEmpty()) {
46-
this.headers.putAll(headers);
47-
}
42+
this.headers = HttpHeadersUtil.mergeOrReplace(headers);
4843
}
4944

5045
public Map<String, String[]> getMultiValueHeaders() {
5146
return multiValueHeaders;
5247
}
5348

5449
public void setMultiValueHeaders(Map<String, String[]> multiValueHeaders) {
55-
if (this.multiValueHeaders == null && multiValueHeaders != null && !multiValueHeaders.isEmpty()) {
56-
this.multiValueHeaders = new HttpHeaders<>();
57-
}
58-
if (multiValueHeaders != null && !multiValueHeaders.isEmpty()) {
59-
this.multiValueHeaders.putAll(multiValueHeaders);
60-
}
50+
this.multiValueHeaders = HttpHeadersUtil.mergeOrReplace(multiValueHeaders);
6151
}
6252

6353
public String getBody() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.amazonaws.services.lambda.runtime.events;
2+
3+
import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders;
4+
5+
import java.util.Map;
6+
7+
final class HttpHeadersUtil {
8+
private HttpHeadersUtil() {}
9+
10+
public static <T> HttpHeaders<T> mergeOrReplace(Map<String, T> from) {
11+
if (from == null) return null;
12+
if (from instanceof HttpHeaders) return (HttpHeaders<T>) from;
13+
14+
HttpHeaders<T> out = new HttpHeaders<>();
15+
if (from.isEmpty()) return out;
16+
17+
out.putAll(from);
18+
return out;
19+
}
20+
}

aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/models/HttpHeaders.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
/**
99
* Class that represents Http Headers.
1010
* <br>
11-
* Not using a standard map, because we need insensitive case.
11+
* Http Headers are case-insensitive.
12+
* Thus, requesting a header "host" will yield the same result as "Host" or "HOST"
1213
*/
1314
public class HttpHeaders<T> implements Map<String, T> {
1415

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package com.amazonaws.services.lambda.runtime.events;
2+
3+
import com.amazonaws.services.lambda.runtime.events.models.HttpHeaders;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.util.*;
7+
8+
import static org.junit.jupiter.api.Assertions.*;
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
11+
public class HttpHeadersTest {
12+
13+
@Test
14+
public void testHttpHeadersCanBeInit() {
15+
HttpHeaders<String> obj = new HttpHeaders<>();
16+
}
17+
18+
@Test
19+
public void testValueCanBeAddedToHttpHeaders() {
20+
HttpHeaders<String> obj = new HttpHeaders<>();
21+
obj.put("key", "value");
22+
assertThat(obj).hasSize(1);
23+
assertThat(obj).containsEntry("key", "value");
24+
}
25+
26+
@Test
27+
public void testValuesCanBeAddedToHttpHeaders() {
28+
HttpHeaders<String> obj = new HttpHeaders<>();
29+
obj.put("key", "value");
30+
obj.put("key2", "value2");
31+
obj.put("key3", "value3");
32+
33+
assertThat(obj).hasSize(3);
34+
assertThat(obj).containsEntry("key", "value");
35+
assertThat(obj).containsEntry("key2", "value2");
36+
assertThat(obj).containsEntry("key3", "value3");
37+
}
38+
39+
@Test
40+
public void testOverridingHttpHeadersKeysIsCaseInsensitive() {
41+
HttpHeaders<String> obj = new HttpHeaders<>();
42+
obj.put("key", "value");
43+
obj.put("KEY", "value2");
44+
obj.put("kEy", "value3");
45+
46+
assertThat(obj).hasSize(1);
47+
assertThat(obj).containsEntry("key", "value3");
48+
}
49+
50+
@Test
51+
public void testValuesCanBeRemovedFromHttpHeaders() {
52+
HttpHeaders<String> obj = new HttpHeaders<>();
53+
obj.put("key", "value");
54+
55+
assertThat(obj).hasSize(1);
56+
obj.remove("key");
57+
assertThat(obj).isEmpty();
58+
}
59+
60+
@Test
61+
public void testContainedKeysAreContainedInHttpHeaders() {
62+
HttpHeaders<String> obj = new HttpHeaders<>();
63+
obj.put("key", "value");
64+
65+
assertTrue(obj.containsKey("key"));
66+
}
67+
68+
@Test
69+
public void testContainedValuesAreContainedInHttpHeaders() {
70+
HttpHeaders<String> obj = new HttpHeaders<>();
71+
obj.put("key", "value");
72+
73+
assertTrue(obj.containsValue("value"));
74+
}
75+
76+
@Test
77+
public void testPutAllWorksInHttpHeaders() {
78+
HttpHeaders<String> obj = new HttpHeaders<>();
79+
obj.put("key", "value");
80+
obj.put("key2", "value2");
81+
82+
Map<String, String> otherMap = new HashMap<>();
83+
otherMap.put("otherKey1", "otherVal1");
84+
otherMap.put("otherKey2", "otherVal2");
85+
otherMap.put("otherKey3", "otherVal3");
86+
87+
obj.putAll(otherMap);
88+
89+
assertThat(obj).hasSize(5);
90+
assertThat(obj).containsEntry("key", "value");
91+
assertThat(obj).containsEntry("key2", "value2");
92+
assertThat(obj).containsEntry("otherKey1", "otherVal1");
93+
assertThat(obj).containsEntry("otherKey2", "otherVal2");
94+
assertThat(obj).containsEntry("otherKey3", "otherVal3");
95+
}
96+
97+
@Test
98+
public void testClearWorksInHttpHeaders() {
99+
HttpHeaders<String> obj = new HttpHeaders<>();
100+
obj.put("key", "value");
101+
obj.put("key2", "value2");
102+
103+
assertThat(obj).hasSize(2);
104+
105+
obj.clear();
106+
107+
assertThat(obj).hasSize(0);
108+
}
109+
110+
@Test
111+
public void testKeySetWorksInHttpHeaders() {
112+
HttpHeaders<String> obj = new HttpHeaders<>();
113+
obj.put("key", "value");
114+
obj.put("key2", "value2");
115+
116+
Set<String> keySet = obj.keySet();
117+
118+
assertNotNull(keySet);
119+
assertThat(keySet).hasSize(2);
120+
assertThat(keySet).contains("key", "key2");
121+
}
122+
123+
@Test
124+
public void testValuesWorksInHttpHeaders() {
125+
HttpHeaders<String> obj = new HttpHeaders<>();
126+
obj.put("key", "value");
127+
obj.put("key2", "value2");
128+
129+
Collection<String> values = obj.values();
130+
131+
assertNotNull(values);
132+
assertThat(values).hasSize(2);
133+
assertThat(values).contains("value", "value2");
134+
}
135+
136+
@Test
137+
public void testEntrySetWorksInHttpHeaders() {
138+
HttpHeaders<String> obj = new HttpHeaders<>();
139+
obj.put("key", "value");
140+
obj.put("key2", "value2");
141+
142+
Set<Map.Entry<String, String>> entrySet = obj.entrySet();
143+
144+
assertNotNull(entrySet);
145+
assertThat(entrySet).hasSize(2);
146+
assertThat(entrySet).contains(new AbstractMap.SimpleEntry<>("key", "value"));
147+
assertThat(entrySet).contains(new AbstractMap.SimpleEntry<>("key2", "value2"));
148+
}
149+
}

0 commit comments

Comments
 (0)