Skip to content

Commit a07615a

Browse files
rhernandez35adwsingh
authored andcommitted
Add ModifiableHttpHeaders method to overwrite HTTP header values
The documentation for `putHeader` was previously incorrect: the methods retained old values instead of overwriting them. I renamed them to `addHeader` to be more clear and added a `setHeader` method that behaves the way `putHeader` was originally documented.
1 parent b641b9f commit a07615a

File tree

9 files changed

+109
-21
lines changed

9 files changed

+109
-21
lines changed

aws/integrations/aws-lambda-endpoint/src/main/java/software/amazon/smithy/java/aws/integrations/lambda/LambdaEndpoint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private static HttpRequest getRequest(ProxyRequest proxyRequest) {
9898
if (proxyRequest.getMultiValueHeaders() != null && !proxyRequest.getMultiValueHeaders().isEmpty()) {
9999
// TODO: handle single-value headers?
100100
// -- APIGW puts the actual headers in both, but only the latest header per key
101-
headers.putHeaders(proxyRequest.getMultiValueHeaders());
101+
headers.addHeaders(proxyRequest.getMultiValueHeaders());
102102
}
103103
URI uri;
104104
if (proxyRequest.getMultiValueQueryStringParameters() != null && !proxyRequest

aws/server/aws-server-restjson/src/main/java/software/amazon/smithy/java/aws/server/restjson/AwsRestJson1Protocol.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public CompletableFuture<Void> serializeOutput(Job job, SerializableStruct outpu
168168
HttpResponse response = serializer.serializeResponse();
169169
httpJob.response().setSerializedValue(response.body());
170170
httpJob.response().setStatusCode(response.statusCode());
171-
httpJob.response().headers().putHeaders(response.headers().map());
171+
httpJob.response().headers().addHeaders(response.headers().map());
172172
return CompletableFuture.completedFuture(null);
173173
}
174174
}

http/http-api/src/main/java/software/amazon/smithy/java/http/api/ModifiableHttpHeaders.java

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,80 @@
1313
*/
1414
public interface ModifiableHttpHeaders extends HttpHeaders {
1515
/**
16-
* Replace a header by name with the given value.
16+
* Add a header by name with the given value.
1717
*
18-
* <p>Any previously set values for this header are replaced.
18+
* <p>Any previously set values for this header are retained. This value is added
19+
* to a list of values for this header name. To overwrite an existing value, use
20+
* {@link #setHeader(String, String)}.
1921
*
2022
* @param name Case-insensitive name of the header to set.
2123
* @param value Value to set.
2224
*/
23-
void putHeader(String name, String value);
25+
void addHeader(String name, String value);
2426

2527
/**
26-
* Replace a header by name with the given values.
28+
* Add a header by name with the given values.
2729
*
28-
* <p>Any previously set values for this header are replaced.
30+
* <p>Any previously set values for this header are retained. This value is added
31+
* to a list of values for this header name. To overwrite an existing value, use
32+
* {@link #setHeader(String, List)}.
2933
*
3034
* @param name Case-insensitive name of the header to set.
3135
* @param values Values to set.
3236
*/
33-
void putHeader(String name, List<String> values);
37+
void addHeader(String name, List<String> values);
3438

3539
/**
36-
* Put the given {@code headers}, similarly to if {@link #putHeader(String, List)} were to be called for each
40+
* Adds the given {@code headers}, similarly to if {@link #addHeader(String, List)} were to be called for each
3741
* entry in the given map.
3842
*
3943
* @param headers Map of case-insensitive header names to their values.
4044
*/
41-
default void putHeaders(Map<String, List<String>> headers) {
45+
default void addHeaders(Map<String, List<String>> headers) {
4246
for (var entry : headers.entrySet()) {
43-
putHeader(entry.getKey(), entry.getValue());
47+
addHeader(entry.getKey(), entry.getValue());
48+
}
49+
}
50+
51+
/**
52+
* Sets a header to the given value, overwriting old values if present.
53+
*
54+
* <p>Any previously set values for this header are replaced as if {@link #removeHeader(String) and
55+
* {@link #addHeader(String, String)}} were called in sequence. To add a new value to a
56+
* list of values, use {@link #addHeader(String, String)}.
57+
*
58+
* @param name Case-insensitive name of the header to set.
59+
* @param value Value to set.
60+
*/
61+
default void setHeader(String name, String value) {
62+
removeHeader(name);
63+
addHeader(name, value);
64+
}
65+
66+
/**
67+
* Sets a header to the given value, overwriting old values if present.
68+
*
69+
* <p>Any previously set values for this header are replaced as if {@link #removeHeader(String) and
70+
* {@link #addHeader(String, String)}} were called in sequence. To add new values to a
71+
* list of values, use {@link #addHeader(String, List)}.
72+
*
73+
* @param name Case-insensitive name of the header to set.
74+
* @param values Values to set.
75+
*/
76+
default void setHeader(String name, List<String> values) {
77+
removeHeader(name);
78+
addHeader(name, values);
79+
}
80+
81+
/**
82+
* Puts the given {@code headers}, similarly to if {@link #setHeader(String, List)} were to be called for each
83+
* entry in the given map.
84+
*
85+
* @param headers Map of case-insensitive header names to their values.
86+
*/
87+
default void setHeaders(Map<String, List<String>> headers) {
88+
for (var entry : headers.entrySet()) {
89+
setHeader(entry.getKey(), entry.getValue());
4490
}
4591
}
4692

http/http-api/src/main/java/software/amazon/smithy/java/http/api/SimpleModifiableHttpHeaders.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,47 @@ final class SimpleModifiableHttpHeaders implements ModifiableHttpHeaders {
1919
private final Map<String, List<String>> headers = new ConcurrentHashMap<>();
2020

2121
@Override
22-
public void putHeader(String name, String value) {
22+
public void addHeader(String name, String value) {
2323
headers.computeIfAbsent(formatPutKey(name), k -> new ArrayList<>()).add(value);
2424
}
2525

2626
@Override
27-
public void putHeader(String name, List<String> values) {
27+
public void addHeader(String name, List<String> values) {
2828
headers.computeIfAbsent(formatPutKey(name), k -> new ArrayList<>()).addAll(values);
2929
}
3030

31+
@Override
32+
public void setHeader(String name, String value) {
33+
var key = formatPutKey(name);
34+
var list = headers.get(formatPutKey(name));
35+
if (list == null) {
36+
list = new ArrayList<>(1);
37+
headers.put(key, list);
38+
} else {
39+
list.clear();
40+
}
41+
42+
list.add(value);
43+
}
44+
45+
@Override
46+
public void setHeader(String name, List<String> values) {
47+
var key = formatPutKey(name);
48+
var list = headers.get(formatPutKey(name));
49+
if (list == null) {
50+
list = new ArrayList<>(values.size());
51+
headers.put(key, list);
52+
} else {
53+
list.clear();
54+
}
55+
56+
// believe it or not, this is more efficient than the bulk constructor
57+
// https://bugs.openjdk.org/browse/JDK-8368292
58+
for (var element : values) {
59+
list.add(element);
60+
}
61+
}
62+
3163
private static String formatPutKey(String name) {
3264
return name.trim().toLowerCase(Locale.ENGLISH);
3365
}

http/http-api/src/main/java/software/amazon/smithy/java/http/api/SimpleUnmodifiableHttpHeaders.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public ModifiableHttpHeaders toModifiable() {
8080
for (var entry : headers.entrySet()) {
8181
copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
8282
}
83-
mod.putHeaders(copy);
83+
mod.addHeaders(copy);
8484
return mod;
8585
}
8686

server/server-core/src/main/java/software/amazon/smithy/java/server/core/CorsHeaders.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public static void addCorsHeaders(HttpJob job) {
3535
return;
3636
}
3737

38-
job.response().headers().putHeaders(BASE_CORS_HEADERS);
39-
job.response().headers().putHeader("Access-Control-Allow-Origin", List.of(requestOrigin));
38+
job.response().headers().addHeaders(BASE_CORS_HEADERS);
39+
job.response().headers().addHeader("Access-Control-Allow-Origin", List.of(requestOrigin));
4040
}
4141

4242
private static boolean shouldAddCorsHeaders(HttpJob job) {

server/server-core/src/test/java/software/amazon/smithy/java/server/core/TestStructs.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ public static class TestModifiableHttpHeaders implements ModifiableHttpHeaders {
140140
Map<String, List<String>> headers = new HashMap<>();
141141

142142
@Override
143-
public void putHeader(String name, String value) {
143+
public void addHeader(String name, String value) {
144144
headers.put(name, List.of(value));
145145
}
146146

147147
@Override
148-
public void putHeader(String name, List<String> values) {
148+
public void addHeader(String name, List<String> values) {
149149
headers.put(name, values);
150150
}
151151

server/server-netty/src/main/java/software/amazon/smithy/java/server/netty/NettyHttpHeaders.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,25 @@ public List<String> allValues(String name) {
3838
}
3939

4040
@Override
41-
public void putHeader(String name, String value) {
41+
public void addHeader(String name, String value) {
4242
nettyHeaders.add(name, value);
4343
}
4444

4545
@Override
46-
public void putHeader(String name, List<String> values) {
46+
public void addHeader(String name, List<String> values) {
4747
nettyHeaders.add(name, values);
4848
}
4949

50+
@Override
51+
public void setHeader(String name, String value) {
52+
nettyHeaders.set(name, value);
53+
}
54+
55+
@Override
56+
public void setHeader(String name, List<String> values) {
57+
nettyHeaders.set(name, values);
58+
}
59+
5060
@Override
5161
public void removeHeader(String name) {
5262
nettyHeaders.remove(name);

server/server-rpcv2-cbor/src/main/java/software/amazon/smithy/java/server/rpcv2/RpcV2CborProtocol.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public CompletableFuture<Void> serializeOutput(Job job, SerializableStruct outpu
9999
} else {
100100
statusCode = 200;
101101
}
102-
httpJob.response().headers().putHeader("smithy-protocol", "rpc-v2-cbor");
102+
httpJob.response().headers().setHeader("smithy-protocol", "rpc-v2-cbor");
103103
httpJob.response().setStatusCode(statusCode);
104104
return CompletableFuture.completedFuture(null);
105105
}

0 commit comments

Comments
 (0)