summaryrefslogtreecommitdiffstats
path: root/simple/simple-http/src/main/java/org/simpleframework/http/message/MessageHeader.java
blob: b809efe3bd0575fd8c2cc16c7c2c096f492ab612 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
/*
 * Message.java February 2007
 *
 * Copyright (C) 2007, Niall Gallagher <niallg@users.sf.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing 
 * permissions and limitations under the License.
 */

package org.simpleframework.http.message;

import java.util.LinkedList;
import java.util.List;

import org.simpleframework.common.KeyMap;
import org.simpleframework.http.Cookie;
import org.simpleframework.http.parse.DateParser;
import org.simpleframework.http.parse.ValueParser;

/**
 * The <code>Message</code> object is used to store an retrieve the
 * headers for both a request and response. Headers are stored and
 * retrieved in a case insensitive manner according to RFC 2616. 
 * The message also allows multiple header values to be added to a
 * single header name, headers such as Cookie and Set-Cookie can be 
 * added multiple times with different values.
 * 
 * @author Niall Gallagher
 */
public class MessageHeader implements Message {

   /**
    * This is used to store the cookies added to the HTTP header.
    */
   private final KeyMap<Cookie> cookies;

   /**
    * This is used to store multiple header values for a name.  
    */
   private final KeyMap<Series> values;

   /**
    * This is used to store the individual names for the header.
    */
   private final KeyMap<String> names;

   /**
    * This is used to parse all date headers added to the message.
    */
   private final DateParser parser;

   /**
    * Constructor for the <code>Message</code> object. This is used 
    * to create a case insensitive means for storing HTTP header
    * names and values. Dates can also be added to message as a
    * long value and is converted to RFC 1123 compliant date string.
    */
   public MessageHeader() {
      this.cookies = new KeyMap<Cookie>();
      this.values = new KeyMap<Series>();
      this.names = new KeyMap<String>();
      this.parser = new DateParser();
   }

   /**
    * This is used to acquire the names of the of the headers that
    * have been set in the response. This can be used to acquire all
    * header values by name that have been set within the response.
    * If no headers have been set this will return an empty list.
    * 
    * @return a list of strings representing the set header names
    */
   public List<String> getNames() {
      return names.getValues();
   }

   /**
    * This can be used to set a HTTP message header to this object.
    * The name and value of the HTTP message header will be used to
    * create a HTTP message header object which can be retrieved using
    * the <code>getValue</code> in combination with the get methods.
    * This will perform a <code>remove</code> using the issued header
    * name before the header value is set.       
    *
    * @param name the name of the HTTP message header to be added
    * @param value the value the HTTP message header will have
    */
   public void setValue(String name, String value) {
      List<String> list = getAll(name);

      if(value == null) {
         String token = name.toLowerCase();

         values.remove(token);
         names.remove(token);
      } else {
         list.clear();
         list.add(value);
      }
   }

   /**
    * This can be used to set a HTTP message header to this object.
    * The name and value of the HTTP message header will be used to
    * create a HTTP message header object which can be retrieved using
    * the <code>getValue</code> in combination with the get methods.
    * This will perform a <code>remove</code> using the issued header
    * name before the header value is set.       
    *
    * @param name the name of the HTTP message header to be added
    * @param value the value the HTTP message header will have
    */
   public void setInteger(String name, int value) {
      setValue(name, String.valueOf(value));
   }
   
   /**
    * This can be used to set a HTTP message header to this object.
    * The name and value of the HTTP message header will be used to
    * create a HTTP message header object which can be retrieved using
    * the <code>getValue</code> in combination with the get methods.
    * This will perform a <code>remove</code> using the issued header
    * name before the header value is set.       
    *
    * @param name the name of the HTTP message header to be added
    * @param value the value the HTTP message header will have
    */    
   public void setLong(String name, long value) {
      setValue(name, String.valueOf(value));
   }
   
   /**
    * This is used as a convenience method for adding a header that
    * needs to be parsed into a HTTP date string. This will convert
    * the date given into a date string defined in RFC 2616 sec 3.3.1.
    * This will perform a <code>remove</code> using the issued header
    * name before the header value is set.       
    *
    * @param name the name of the HTTP message header to be added
    * @param date the value constructed as an RFC 1123 date string
    */
   public void setDate(String name, long date) {
      setValue(name, parser.convert(date));
   }

   /**
    * This can be used to add a HTTP message header to this object.
    * The name and value of the HTTP message header will be used to
    * create a HTTP message header object which can be retrieved using
    * the <code>getValue</code> in combination with the get methods.
    *
    * @param name the name of the HTTP message header to be added
    * @param value the value the HTTP message header will have
    */
   public void addValue(String name, String value) {
      List<String> list = getAll(name);

      if(value != null) {
         list.add(value);
      }
   }

   /**
    * This can be used to add a HTTP message header to this object.
    * The name and value of the HTTP message header will be used to
    * create a HTTP message header object which can be retrieved using
    * the <code>getInteger</code> in combination with the get methods.
    *
    * @param name the name of the HTTP message header to be added
    * @param value the value the HTTP message header will have
    */
   public void addInteger(String name, int value) {
      addValue(name, String.valueOf(value));
   }

   /**
    * This is used as a convenience method for adding a header that
    * needs to be parsed into a HTTPdate string. This will convert
    * the date given into a date string defined in RFC 2616 sec 3.3.1.
    *
    * @param name the name of the HTTP message header to be added
    * @param date the value constructed as an RFC 1123 date string
    */
   public void addDate(String name, long date) {
      addValue(name, parser.convert(date));
   }

   /**
    * This can be used to get the value of the first message header
    * that has the specified name. This will return the full string
    * representing the named header value. If the named header does
    * not exist then this will return a null value.
    *
    * @param name the HTTP message header to get the value from
    *
    * @return this returns the value that the HTTP message header
    */
   public String getValue(String name) {
      return getValue(name, 0);
   }
   
   /**
    * This can be used to get the value of the first message header
    * that has the specified name. This will return the full string
    * representing the named header value. If the named header does
    * not exist then this will return a null value.
    *
    * @param name the HTTP message header to get the value from
    * @param index this is the index to get the value from
    *
    * @return this returns the value that the HTTP message header
    */
   public String getValue(String name, int index) {
      List<String> list = getAll(name);

      if(list.size() > index) {
         return list.get(index);
      }
      return null;
   }

   /**
    * This can be used to get the value of the first message header
    * that has the specified name. This will return the integer
    * representing the named header value. If the named header does
    * not exist then this will return a value of minus one, -1.
    *
    * @param name the HTTP message header to get the value from
    *
    * @return this returns the value that the HTTP message header
    */
   public int getInteger(String name) {
      String value = getValue(name);

      if(value == null) {
         return -1;
      }
      return Integer.parseInt(value);
   }
   
   /**
    * This can be used to get the value of the first message header
    * that has the specified name. This will return the long
    * representing the named header value. If the named header does
    * not exist then this will return a value of minus one, -1.
    *
    * @param name the HTTP message header to get the value from
    *
    * @return this returns the value that the HTTP message header
    */
   public long getLong(String name) {
      String value = getValue(name);

      if(value == null) {
         return -1L;
      }
      return Long.parseLong(value);
   }

   /**
    * This can be used to get the value of the first message header
    * that has the specified name. This will return the long value
    * representing the named header value. If the named header does
    * not exist then this will return a value of minus one, -1.
    *
    * @param name the HTTP message header to get the value from
    *
    * @return this returns the value that the HTTP message header
    */
   public long getDate(String name) {
      String value = getValue(name);

      if(value == null) {
         return -1;
      }
      return parser.convert(value);
   }

   /**
    * This returns the <code>Cookie</code> object stored under the
    * specified name. This is used to retrieve cookies that have been 
    * set with the <code>setCookie</code> methods. If the cookie does
    * not exist under the specified name this will return null. 
    *
    * @param name this is the name of the cookie to be retrieved
    * 
    * @return returns the <code>Cookie</code> by the given name
    */
   public Cookie getCookie(String name) {
      return cookies.get(name);
   }

   /**
    * This returns all <code>Cookie</code> objects stored under the
    * specified name. This is used to retrieve cookies that have been 
    * set with the <code>setCookie</code> methods. If there are no
    * cookies then this will return an empty list. 
    * 
    * @return returns all the <code>Cookie</code> in the response
    */
   public List<Cookie> getCookies() {
      return cookies.getValues();
   }

   /**
    * The <code>setCookie</code> method is used to set a cookie value 
    * with the cookie name. This will add a cookie to the response
    * stored under the name of the cookie, when this is committed it 
    * will be added as a Set-Cookie header to the resulting response.
    * This is a convenience method that avoids cookie creation.     
    *
    * @param name this is the cookie to be added to the response
    * @param value this is the cookie value that is to be used
    * 
    * @return returns the cookie that has been set in the response
    */
   public Cookie setCookie(String name, String value) {
      return setCookie(new Cookie(name, value, true));
   }

   /**
    * The <code>setCookie</code> method is used to set a cookie value 
    * with the cookie name. This will add a cookie to the response
    * stored under the name of the cookie, when this is committed it 
    * will be added as a Set-Cookie header to the resulting response.
    *
    * @param cookie this is the cookie to be added to the response
    * 
    * @return returns the cookie that has been set in the response
    */
   public Cookie setCookie(Cookie cookie) {
      String name = cookie.getName();

      if(name != null) {
         cookies.put(name, cookie);
      }
      return cookie;
   }

   /**
    * This can be used to get the values of HTTP message headers
    * that have the specified name. This is a convenience method that 
    * will present that values as tokens extracted from the header.
    * This has obvious performance benefits as it avoids having to 
    * deal with <code>substring</code> and <code>trim</code> calls.
    * <p>
    * The tokens returned by this method are ordered according to
    * there HTTP quality values, or "q" values, see RFC 2616 section
    * 3.9. This also strips out the quality parameter from tokens
    * returned. So "image/html; q=0.9" results in "image/html". If
    * there are no "q" values present then order is by appearance.
    * <p> 
    * The result from this is either the trimmed header value, that
    * is, the header value with no leading or trailing whitespace
    * or an array of trimmed tokens ordered with the most preferred
    * in the lower indexes, so index 0 is has highest preference.
    *
    * @param name the name of the headers that are to be retrieved
    *
    * @return ordered list of tokens extracted from the header(s)
    */
   public List<String> getValues(String name) {
      return getValues(getAll(name));
   }

   /**
    * This can be used to get the values of HTTP message headers
    * that have the specified name. This is a convenience method that 
    * will present that values as tokens extracted from the header.
    * This has obvious performance benefits as it avoids having to 
    * deal with <code>substring</code> and <code>trim</code> calls.
    * <p>
    * The tokens returned by this method are ordered according to
    * there HTTP quality values, or "q" values, see RFC 2616 section
    * 3.9. This also strips out the quality parameter from tokens
    * returned. So "image/html; q=0.9" results in "image/html". If
    * there are no "q" values present then order is by appearance.
    * <p> 
    * The result from this is either the trimmed header value, that
    * is, the header value with no leading or trailing whitespace
    * or an array of trimmed tokens ordered with the most preferred
    * in the lower indexes, so index 0 is has highest preference.
    *
    * @param list this is the list of individual header values
    *
    * @return ordered list of tokens extracted from the header(s)
    */
   public List<String> getValues(List<String> list) {
      return new ValueParser(list).list();
   }

   /**
    * This is used to acquire all the individual header values from
    * the message. The header values provided by this are unparsed
    * and represent the actual string values that have been added to
    * the message keyed by a given header name.
    * 
    * @param name the name of the header to get the values for
    * 
    * @return this returns a list of the values for the header name
    */
   public List<String> getAll(String name) {
      String token = name.toLowerCase();
      Series series = values.get(token);

      if(series == null) {
         return getAll(name, token);
      }
      return series.getValues();
   }

   /**
    * This is used to acquire all the individual header values from
    * the message. The header values provided by this are unparsed
    * and represent the actual string values that have been added to
    * the message keyed by a given header name.
    * 
    * @param name the name of the header to get the values for
    * @param token this provides a lower case version of the header
    * 
    * @return this returns a list of the values for the header name
    */
   private List<String> getAll(String name, String token) {
      Series series = new Series();
      String value = names.get(token);

      if(value == null) {
         names.put(token, name);
      }
      values.put(token, series);

      return series.getValues();
   }

   /**
    * The <code>Series</code> object is used to represent a list of
    * HTTP header value for a given name. It allows multiple values
    * to exist for a given header, such as the Cookie header. Most
    * entries will contain a single value.
    */
   private class Series {

      /**
       * Contains the header values that belong to the entry name. 
       */
      private List<String> value;

      /**
       * Constructor for the <code>Entry</code> object. The entry is
       * created using the name of the HTTP header. Values can be
       * added to the entry list in order to build up the header.
       */
      public Series() {
         this.value = new LinkedList<String>();
      }

      /**
       * This returns the list of header values associated with the
       * header name. Each value is added as an individual header
       * prefixed by the header name and a semicolon character.
       * 
       * @return this returns the list of values for the header
       */
      public List<String> getValues() {
         return value;
      }
   }
}