1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.mimo.netty.handler.codec.icap;
15
16 import java.text.ParseException;
17 import java.text.SimpleDateFormat;
18 import java.util.Date;
19 import java.util.LinkedHashSet;
20 import java.util.Locale;
21 import java.util.Map;
22 import java.util.Set;
23
24
25
26
27
28
29
30
31
32 public final class IcapHeaders {
33
34 private Entry base;
35 private Entry head;
36
37 private static final String DATE_FORMAT = "E, dd MMM yyyy HH:mm:ss z";
38
39
40
41
42
43
44
45 public static final class Names {
46
47
48
49 public static final String CACHE_CONTROL = "Cache-Control";
50
51
52
53 public static final String CONNECTION = "Connection";
54
55
56
57 public static final String DATE = "Date";
58
59
60
61 public static final String EXPIRES = "Expires";
62
63
64
65 public static final String PRAGMA = "Pragma";
66
67
68
69 public static final String TRAILER = "Trailer";
70
71
72
73 public static final String UPGRADE = "Upgrade";
74
75
76
77 public static final String ENCAPSULATED = "Encapsulated";
78
79
80
81 public static final String AUTHORIZATION = "Authorization";
82
83
84
85 public static final String ALLOW = "Allow";
86
87
88
89 public static final String FROM = "From";
90
91
92
93 public static final String HOST = "Host";
94
95
96
97 public static final String REFERER = "Referer";
98
99
100
101 public static final String USER_AGENT = "User-Agent";
102
103
104
105 public static final String PREVIEW = "Preview";
106
107
108
109
110 public static final String ISTAG = "ISTag";
111
112
113
114
115 public static final String METHODS = "Methods";
116
117
118
119
120 public static final String SERVICE = "Service";
121
122
123
124
125 public static final String OPT_BODY_TYPE = "Opt-body-type";
126
127
128
129
130 public static final String MAX_CONNECTIONS = "Max-connections";
131
132
133
134
135 public static final String OPTIONS_TTL = "Options-TTL";
136
137
138
139
140 public static final String SERVICE_ID = "Service-ID";
141
142
143
144
145 public static final String TRANSFER_PREVIEW = "Transfer-Preview";
146
147
148
149
150 public static final String TRANSFER_IGNORE = "Transfer-Ignore";
151
152
153
154
155 public static final String TRANSFER_COMPLETE = "Transfer-Complete";
156 }
157
158 public IcapHeaders() {
159 }
160
161 public void clearHeaders() {
162 base = null;
163 head = null;
164 }
165
166
167
168
169
170
171
172
173
174 public void addHeader(String name, Object value) {
175 Entry entry = new Entry(name,value);
176 if(base == null) {
177 base = entry;
178 head = entry;
179 } else {
180 Entry currentHead = head;
181 head = entry;
182 entry.before = currentHead;
183 currentHead.after = entry;
184 }
185 }
186
187 public void addDateHeader(String name, Date value) {
188 SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT,Locale.ENGLISH);
189 addHeader(name,format.format(value));
190 }
191
192
193
194
195
196
197
198
199 public void setHeader(String name, Object value) {
200 removeHeader(name);
201 addHeader(name,value);
202 }
203
204
205
206
207
208
209
210
211 public void setHeader(String name, Iterable<?> values) {
212 removeHeader(name);
213 for(Object value : values) {
214 addHeader(name,value);
215 }
216 }
217
218
219
220
221
222
223
224
225
226
227
228 public String getHeader(String name) {
229 Entry entry = base;
230 while(entry != null) {
231 if(identicalKeys(entry.getKey(),name)) {
232 return entry.getValue();
233 }
234 entry = entry.after;
235 }
236 return null;
237 }
238
239
240
241
242
243
244
245
246
247
248 public Date getDateHeader(String name) {
249 Date date = null;
250 SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT,Locale.ENGLISH);
251 String value = getHeader(name);
252 if(value != null) {
253 try {
254 date = format.parse(value);
255 } catch (ParseException e) {
256 throw new IllegalArgumentException("The header value [" + value + "] is not a valid date",e);
257 }
258 }
259 return date;
260 }
261
262
263
264
265
266
267
268
269 public Set<String> getHeaders(String name) {
270 Set<String> values = new LinkedHashSet<String>();
271 Entry entry = base;
272 while(entry != null) {
273 if(identicalKeys(entry.getKey(),name)) {
274 values.add(entry.getValue());
275 }
276 entry = entry.after;
277 }
278 return values;
279 }
280
281
282
283
284
285
286 public Set<Map.Entry<String, String>> getHeaders() {
287 Set<Map.Entry<String, String>> headers = new LinkedHashSet<Map.Entry<String,String>>();
288 Entry entry = base;
289 while(entry != null) {
290 headers.add(entry);
291 entry = entry.after;
292 }
293 return headers;
294 }
295
296
297
298
299
300
301
302 public boolean containsHeader(String name) {
303 return getHeader(name) != null;
304 }
305
306
307
308
309
310
311 public void removeHeader(String name) {
312 if(base == null) {
313 return;
314 }
315 Entry entry = null;
316 if(base.after == null) {
317 if(identicalKeys(base.getKey(),name)) {
318 base = null;
319 return;
320 }
321 } else {
322 entry = base.after;
323 }
324 while(entry != null) {
325 if(identicalKeys(entry.getKey(),name)) {
326 Entry before = entry.before;
327 Entry after = entry.after;
328 before.after = after;
329 after.before = before;
330 entry = after;
331 } else {
332 entry = entry.after;
333 }
334 }
335 if(identicalKeys(base.getKey(),name)) {
336 base = base.after;
337 base.before = null;
338 }
339 }
340
341
342
343
344
345
346
347 public Set<String> getHeaderNames() {
348 Set<String> names = new LinkedHashSet<String>();
349 Entry entry = base;
350 while(entry != null) {
351 names.add(entry.getKey());
352 entry = entry.after;
353 }
354 return names;
355 }
356
357
358
359
360
361
362
363
364 public int getPreviewHeaderValue() {
365 String value = getHeader(Names.PREVIEW);
366 int result = 0;
367 try {
368 if(value != null) {
369 result = Integer.parseInt(value);
370 }
371 } catch(NumberFormatException nfe) {
372 throw new IcapDecodingError("Unable to understand the preview amount value [" + value + "]");
373 }
374 return result;
375 }
376
377 private boolean identicalKeys(String key1, String key2) {
378 if(key1 != null & key2 != null) {
379 return key1.equalsIgnoreCase(key2);
380 }
381 return false;
382 }
383
384 private static final class Entry implements Map.Entry<String, String> {
385
386 private String key;
387 private String value;
388
389 private Entry before, after;
390
391 Entry(String key, Object value) {
392 IcapCodecUtil.validateHeaderName(key);
393 this.key = key;
394 if(value != null) {
395 this.value = value.toString();
396 IcapCodecUtil.validateHeaderValue(this.value);
397 }
398 }
399
400 public String getKey() {
401 return key;
402 }
403
404 public String getValue() {
405 return value;
406 }
407
408 @Override
409 public String setValue(String value) {
410 return null;
411 }
412 }
413
414 @Override
415 public String toString() {
416 StringBuilder builder = new StringBuilder();
417 for(String name : getHeaderNames()) {
418 builder.append("[" + name + "] = [" + getHeaders(name) + "]");
419 }
420 return builder.toString();
421 }
422 }