Skip to content

Commit 82bfc5d

Browse files
author
Julia Boes
committed
8268960: com/sun/net/httpserver/Headers.java: Ensure mutators normalize keys and disallow null for keys and values
Reviewed-by: chegar, dfuchs, michaelm
1 parent 18f356a commit 82bfc5d

File tree

2 files changed

+332
-33
lines changed

2 files changed

+332
-33
lines changed

src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import java.util.LinkedList;
3131
import java.util.List;
3232
import java.util.Map;
33+
import java.util.Objects;
3334
import java.util.Set;
35+
import java.util.function.BiFunction;
3436

3537
/**
3638
* HTTP request and response headers are represented by this class which
@@ -63,14 +65,8 @@
6365
* value given overwriting any existing values in the value list.
6466
* </ul>
6567
*
66-
* <p> All methods in this class accept {@code null} values for keys and values.
67-
* However, {@code null} keys will never will be present in HTTP request
68-
* headers, and will not be output/sent in response headers. Null values can be
69-
* represented as either a {@code null} entry for the key (i.e. the list is
70-
* {@code null}) or where the key has a list, but one (or more) of the list's
71-
* values is {@code null}. Null values are output as a header line containing
72-
* the key but no associated value.
73-
*
68+
* <p> All methods in this class reject {@code null} values for keys and values.
69+
* {@code null} keys will never be present in HTTP request or response headers.
7470
* @since 1.6
7571
*/
7672
public class Headers implements Map<String,List<String>> {
@@ -88,9 +84,7 @@ public class Headers implements Map<String,List<String>> {
8884
* key is presumed to be {@code ASCII}.
8985
*/
9086
private String normalize(String key) {
91-
if (key == null) {
92-
return null;
93-
}
87+
Objects.requireNonNull(key);
9488
int len = key.length();
9589
if (len == 0) {
9690
return key;
@@ -110,54 +104,58 @@ private String normalize(String key) {
110104
return new String(b);
111105
}
112106

107+
@Override
113108
public int size() {return map.size();}
114109

110+
@Override
115111
public boolean isEmpty() {return map.isEmpty();}
116112

113+
@Override
117114
public boolean containsKey(Object key) {
118-
if (key == null) {
119-
return false;
120-
}
121-
if (!(key instanceof String)) {
122-
return false;
123-
}
124-
return map.containsKey(normalize((String)key));
115+
Objects.requireNonNull(key);
116+
return key instanceof String k && map.containsKey(normalize(k));
125117
}
126118

119+
@Override
127120
public boolean containsValue(Object value) {
121+
Objects.requireNonNull(value);
128122
return map.containsValue(value);
129123
}
130124

125+
@Override
131126
public List<String> get(Object key) {
132127
return map.get(normalize((String)key));
133128
}
134129

135130
/**
136-
* Returns the first value from the {@link List} of {@code String}
137-
* values for the given key (if at least one exists).
131+
* Returns the first value from the {@link List} of {@code String} values
132+
* for the given {@code key}, or {@code null} if no mapping for the
133+
* {@code key} exists.
138134
*
139135
* @param key the key to search for
140-
* @return the first {@code String} value associated with the key
136+
* @return the first {@code String} value associated with the key,
137+
* or {@code null} if no mapping for the key exists
141138
*/
142139
public String getFirst(String key) {
143140
List<String> l = map.get(normalize(key));
144-
if (l == null) {
141+
if (l == null || l.size() == 0) { // no mapping exists
145142
return null;
146143
}
147144
return l.get(0);
148145
}
149146

147+
@Override
150148
public List<String> put(String key, List<String> value) {
151149
for (String v : value)
152150
checkValue(v);
153151
return map.put(normalize(key), value);
154152
}
155153

156154
/**
157-
* Adds the given value to the list of headers for the given key. If
158-
* the mapping does not already exist, then it is created.
155+
* Adds the given {@code value} to the list of headers for the given
156+
* {@code key}. If the mapping does not already exist, then it is created.
159157
*
160-
* @param key the header name
158+
* @param key the header name
161159
* @param value the value to add to the header
162160
*/
163161
public void add(String key, String value) {
@@ -196,10 +194,10 @@ private static void checkValue(String value) {
196194
}
197195

198196
/**
199-
* Sets the given value as the sole header value for the given
200-
* key. If the mapping does not already exist, then it is created.
197+
* Sets the given {@code value} as the sole header value for the given
198+
* {@code key}. If the mapping does not already exist, then it is created.
201199
*
202-
* @param key the header name
200+
* @param key the header name
203201
* @param value the header value to set
204202
*/
205203
public void set(String key, String value) {
@@ -208,25 +206,52 @@ public void set(String key, String value) {
208206
put(key, l);
209207
}
210208

209+
@Override
211210
public List<String> remove(Object key) {
212211
return map.remove(normalize((String)key));
213212
}
214213

214+
@Override
215215
public void putAll(Map<? extends String,? extends List<String>> t) {
216-
map.putAll(t);
216+
t.forEach(this::put);
217217
}
218218

219+
@Override
219220
public void clear() {map.clear();}
220221

222+
@Override
221223
public Set<String> keySet() {return map.keySet();}
222224

225+
@Override
223226
public Collection<List<String>> values() {return map.values();}
224227

228+
@Override
225229
public Set<Map.Entry<String, List<String>>> entrySet() {
226230
return map.entrySet();
227231
}
228232

229-
public boolean equals(Object o) {return map.equals(o);}
233+
@Override
234+
public void replaceAll(BiFunction<? super String, ? super List<String>, ? extends List<String>> function) {
235+
var f = function.andThen(values -> {
236+
Objects.requireNonNull(values);
237+
values.forEach(Headers::checkValue);
238+
return values;
239+
});
240+
Map.super.replaceAll(f);
241+
}
242+
243+
@Override
244+
public boolean equals(Object o) { return map.equals(o); }
230245

246+
@Override
231247
public int hashCode() {return map.hashCode();}
248+
249+
@Override
250+
public String toString() {
251+
final var sb = new StringBuilder(Headers.class.getSimpleName());
252+
sb.append(" { ");
253+
sb.append(map.toString());
254+
sb.append(" }");
255+
return sb.toString();
256+
}
232257
}

0 commit comments

Comments
 (0)