1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http;
17
18 import io.netty.handler.codec.CharSequenceValueConverter;
19 import io.netty.handler.codec.DateFormatter;
20 import io.netty.handler.codec.DefaultHeaders;
21 import io.netty.handler.codec.DefaultHeaders.NameValidator;
22 import io.netty.handler.codec.DefaultHeadersImpl;
23 import io.netty.handler.codec.HeadersUtils;
24 import io.netty.handler.codec.ValueConverter;
25
26 import java.util.ArrayList;
27 import java.util.Calendar;
28 import java.util.Collections;
29 import java.util.Date;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.Set;
35
36 import static io.netty.util.AsciiString.CASE_INSENSITIVE_HASHER;
37 import static io.netty.util.AsciiString.CASE_SENSITIVE_HASHER;
38
39
40
41
42 public class DefaultHttpHeaders extends HttpHeaders {
43 static final NameValidator<CharSequence> HttpNameValidator = new NameValidator<CharSequence>() {
44 @Override
45 public void validateName(CharSequence name) {
46 if (name == null || name.length() == 0) {
47 throw new IllegalArgumentException("empty headers are not allowed [" + name + ']');
48 }
49 int index = HttpHeaderValidationUtil.validateToken(name);
50 if (index != -1) {
51 throw new IllegalArgumentException("a header name can only contain \"token\" characters, " +
52 "but found invalid character 0x" + Integer.toHexString(name.charAt(index)) +
53 " at index " + index + " of header '" + name + "'.");
54 }
55 }
56 };
57
58 private final DefaultHeaders<CharSequence, CharSequence, ?> headers;
59
60 public DefaultHttpHeaders() {
61 this(true);
62 }
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public DefaultHttpHeaders(boolean validate) {
77 this(validate, nameValidator(validate));
78 }
79
80 protected DefaultHttpHeaders(boolean validate, NameValidator<CharSequence> nameValidator) {
81 this(new DefaultHeadersImpl<CharSequence, CharSequence>(
82 CASE_INSENSITIVE_HASHER,
83 HeaderValueConverter.INSTANCE,
84 nameValidator,
85 16,
86 valueValidator(validate)));
87 }
88
89 protected DefaultHttpHeaders(DefaultHeaders<CharSequence, CharSequence, ?> headers) {
90 this.headers = headers;
91 }
92
93 @Override
94 public HttpHeaders add(HttpHeaders headers) {
95 if (headers instanceof DefaultHttpHeaders) {
96 this.headers.add(((DefaultHttpHeaders) headers).headers);
97 return this;
98 } else {
99 return super.add(headers);
100 }
101 }
102
103 @Override
104 public HttpHeaders set(HttpHeaders headers) {
105 if (headers instanceof DefaultHttpHeaders) {
106 this.headers.set(((DefaultHttpHeaders) headers).headers);
107 return this;
108 } else {
109 return super.set(headers);
110 }
111 }
112
113 @Override
114 public HttpHeaders add(String name, Object value) {
115 headers.addObject(name, value);
116 return this;
117 }
118
119 @Override
120 public HttpHeaders add(CharSequence name, Object value) {
121 headers.addObject(name, value);
122 return this;
123 }
124
125 @Override
126 public HttpHeaders add(String name, Iterable<?> values) {
127 headers.addObject(name, values);
128 return this;
129 }
130
131 @Override
132 public HttpHeaders add(CharSequence name, Iterable<?> values) {
133 headers.addObject(name, values);
134 return this;
135 }
136
137 @Override
138 public HttpHeaders addInt(CharSequence name, int value) {
139 headers.addInt(name, value);
140 return this;
141 }
142
143 @Override
144 public HttpHeaders addShort(CharSequence name, short value) {
145 headers.addShort(name, value);
146 return this;
147 }
148
149 @Override
150 public HttpHeaders remove(String name) {
151 headers.remove(name);
152 return this;
153 }
154
155 @Override
156 public HttpHeaders remove(CharSequence name) {
157 headers.remove(name);
158 return this;
159 }
160
161 @Override
162 public HttpHeaders set(String name, Object value) {
163 headers.setObject(name, value);
164 return this;
165 }
166
167 @Override
168 public HttpHeaders set(CharSequence name, Object value) {
169 headers.setObject(name, value);
170 return this;
171 }
172
173 @Override
174 public HttpHeaders set(String name, Iterable<?> values) {
175 headers.setObject(name, values);
176 return this;
177 }
178
179 @Override
180 public HttpHeaders set(CharSequence name, Iterable<?> values) {
181 headers.setObject(name, values);
182 return this;
183 }
184
185 @Override
186 public HttpHeaders setInt(CharSequence name, int value) {
187 headers.setInt(name, value);
188 return this;
189 }
190
191 @Override
192 public HttpHeaders setShort(CharSequence name, short value) {
193 headers.setShort(name, value);
194 return this;
195 }
196
197 @Override
198 public HttpHeaders clear() {
199 headers.clear();
200 return this;
201 }
202
203 @Override
204 public String get(String name) {
205 return get((CharSequence) name);
206 }
207
208 @Override
209 public String get(CharSequence name) {
210 return HeadersUtils.getAsString(headers, name);
211 }
212
213 @Override
214 public Integer getInt(CharSequence name) {
215 return headers.getInt(name);
216 }
217
218 @Override
219 public int getInt(CharSequence name, int defaultValue) {
220 return headers.getInt(name, defaultValue);
221 }
222
223 @Override
224 public Short getShort(CharSequence name) {
225 return headers.getShort(name);
226 }
227
228 @Override
229 public short getShort(CharSequence name, short defaultValue) {
230 return headers.getShort(name, defaultValue);
231 }
232
233 @Override
234 public Long getTimeMillis(CharSequence name) {
235 return headers.getTimeMillis(name);
236 }
237
238 @Override
239 public long getTimeMillis(CharSequence name, long defaultValue) {
240 return headers.getTimeMillis(name, defaultValue);
241 }
242
243 @Override
244 public List<String> getAll(String name) {
245 return getAll((CharSequence) name);
246 }
247
248 @Override
249 public List<String> getAll(CharSequence name) {
250 return HeadersUtils.getAllAsString(headers, name);
251 }
252
253 @Override
254 public List<Entry<String, String>> entries() {
255 if (isEmpty()) {
256 return Collections.emptyList();
257 }
258 List<Entry<String, String>> entriesConverted = new ArrayList<Entry<String, String>>(
259 headers.size());
260 for (Entry<String, String> entry : this) {
261 entriesConverted.add(entry);
262 }
263 return entriesConverted;
264 }
265
266 @Deprecated
267 @Override
268 public Iterator<Map.Entry<String, String>> iterator() {
269 return HeadersUtils.iteratorAsString(headers);
270 }
271
272 @Override
273 public Iterator<Entry<CharSequence, CharSequence>> iteratorCharSequence() {
274 return headers.iterator();
275 }
276
277 @Override
278 public Iterator<String> valueStringIterator(CharSequence name) {
279 final Iterator<CharSequence> itr = valueCharSequenceIterator(name);
280 return new Iterator<String>() {
281 @Override
282 public boolean hasNext() {
283 return itr.hasNext();
284 }
285
286 @Override
287 public String next() {
288 return itr.next().toString();
289 }
290
291 @Override
292 public void remove() {
293 itr.remove();
294 }
295 };
296 }
297
298 @Override
299 public Iterator<CharSequence> valueCharSequenceIterator(CharSequence name) {
300 return headers.valueIterator(name);
301 }
302
303 @Override
304 public boolean contains(String name) {
305 return contains((CharSequence) name);
306 }
307
308 @Override
309 public boolean contains(CharSequence name) {
310 return headers.contains(name);
311 }
312
313 @Override
314 public boolean isEmpty() {
315 return headers.isEmpty();
316 }
317
318 @Override
319 public int size() {
320 return headers.size();
321 }
322
323 @Override
324 public boolean contains(String name, String value, boolean ignoreCase) {
325 return contains((CharSequence) name, (CharSequence) value, ignoreCase);
326 }
327
328 @Override
329 public boolean contains(CharSequence name, CharSequence value, boolean ignoreCase) {
330 return headers.contains(name, value, ignoreCase ? CASE_INSENSITIVE_HASHER : CASE_SENSITIVE_HASHER);
331 }
332
333 @Override
334 public Set<String> names() {
335 return HeadersUtils.namesAsString(headers);
336 }
337
338 @Override
339 public boolean equals(Object o) {
340 return o instanceof DefaultHttpHeaders
341 && headers.equals(((DefaultHttpHeaders) o).headers, CASE_SENSITIVE_HASHER);
342 }
343
344 @Override
345 public int hashCode() {
346 return headers.hashCode(CASE_SENSITIVE_HASHER);
347 }
348
349 @Override
350 public HttpHeaders copy() {
351 return new DefaultHttpHeaders(headers.copy());
352 }
353
354 static ValueConverter<CharSequence> valueConverter() {
355 return HeaderValueConverter.INSTANCE;
356 }
357
358 @SuppressWarnings("unchecked")
359 static DefaultHeaders.ValueValidator<CharSequence> valueValidator(boolean validate) {
360 return validate ? HeaderValueValidator.INSTANCE :
361 (DefaultHeaders.ValueValidator<CharSequence>) DefaultHeaders.ValueValidator.NO_VALIDATION;
362 }
363
364 @SuppressWarnings("unchecked")
365 static NameValidator<CharSequence> nameValidator(boolean validate) {
366 return validate ? HttpNameValidator : NameValidator.NOT_NULL;
367 }
368
369 private static class HeaderValueConverter extends CharSequenceValueConverter {
370 static final HeaderValueConverter INSTANCE = new HeaderValueConverter();
371
372 @Override
373 public CharSequence convertObject(Object value) {
374 if (value instanceof CharSequence) {
375 return (CharSequence) value;
376 }
377 if (value instanceof Date) {
378 return DateFormatter.format((Date) value);
379 }
380 if (value instanceof Calendar) {
381 return DateFormatter.format(((Calendar) value).getTime());
382 }
383 return value.toString();
384 }
385 }
386
387 private static final class HeaderValueValidator implements DefaultHeaders.ValueValidator<CharSequence> {
388 static final HeaderValueValidator INSTANCE = new HeaderValueValidator();
389
390 @Override
391 public void validate(CharSequence value) {
392 int index = HttpHeaderValidationUtil.validateValidHeaderValue(value);
393 if (index != -1) {
394 throw new IllegalArgumentException("a header value contains prohibited character 0x" +
395 Integer.toHexString(value.charAt(index)) + " at index " + index + '.');
396 }
397 }
398 }
399 }