001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest;
014
015import static org.apache.juneau.internal.ArrayUtils.*;
016import static org.apache.juneau.internal.StringUtils.*;
017
018import java.lang.reflect.*;
019import java.util.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.http.*;
023import org.apache.juneau.http.Date;
024import org.apache.juneau.httppart.*;
025import org.apache.juneau.internal.*;
026import org.apache.juneau.json.*;
027import org.apache.juneau.parser.*;
028
029/**
030 * Represents the headers in an HTTP request.
031 * 
032 * <p>
033 * Entries are stored in a case-insensitive map.
034 * 
035 * <h5 class='section'>See Also:</h5>
036 * <ul>
037 *    <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestHeaders">Overview &gt; juneau-rest-server &gt; RequestHeaders</a>
038 * </ul>
039 */
040public class RequestHeaders extends TreeMap<String,String[]> {
041   private static final long serialVersionUID = 1L;
042
043   private HttpPartParser parser;
044   private BeanSession beanSession;
045   private RequestQuery queryParams;
046
047   RequestHeaders() {
048      super(String.CASE_INSENSITIVE_ORDER);
049   }
050
051   RequestHeaders parser(HttpPartParser parser) {
052      this.parser = parser;
053      return this;
054   }
055
056   RequestHeaders beanSession(BeanSession beanSession) {
057      this.beanSession = beanSession;
058      return this;
059   }
060
061   RequestHeaders setQueryParams(RequestQuery queryParams) {
062      this.queryParams = queryParams;
063      return this;
064   }
065
066   /**
067    * Adds default entries to these headers.
068    * 
069    * <p>
070    * Similar to {@link #put(String, Object)} but doesn't override existing values.
071    * 
072    * @param defaultEntries 
073    *    The default entries.  
074    *    <br>Can be <jk>null</jk>.
075    * @return This object (for method chaining).
076    */
077   public RequestHeaders addDefault(Map<String,Object> defaultEntries) {
078      if (defaultEntries != null) {
079         for (Map.Entry<String,Object> e : defaultEntries.entrySet()) {
080            String key = e.getKey();
081            Object value = e.getValue();
082            String[] v = get(key);
083            if (v == null || v.length == 0 || StringUtils.isEmpty(v[0]))
084               put(key, asStrings(value));
085         }
086      }
087      return this;
088   }
089   
090   /**
091    * Adds a default header value on this request.
092    * 
093    * <p>
094    * Similar to {@link #put(String, Object)} but doesn't override existing values.
095    * 
096    * @param name 
097    *    The header name.  
098    * @param value
099    *    The header value.  
100    *    <br>Converted to a String using <code>toString()</code>.
101    *    <br>Ignored if value is <jk>null</jk> or blank.
102    * @return This object (for method chaining).
103    */
104   public RequestHeaders addDefault(String name, Object value) {
105      return addDefault(Collections.singletonMap(name, value));
106   }
107
108   /**
109    * Adds a set of header values to this object.
110    * 
111    * @param name The header name.
112    * @param values The header values.
113    * @return This object (for method chaining).
114    */
115   public RequestHeaders put(String name, Enumeration<String> values) {
116      // Optimized for enumerations of one entry, the most-common case.
117      if (values.hasMoreElements()) {
118         String v = values.nextElement();
119         String[] s = new String[]{v};
120         while (values.hasMoreElements())
121            s = append(s, values.nextElement());
122         put(name, s);
123      }
124      return this;
125   }
126
127   /**
128    * Returns the specified header value as a string.
129    * 
130    * <h5 class='section'>Notes:</h5>
131    * <ul class='spaced-list'>
132    *    <li>
133    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
134    * </ul>
135    * 
136    * @param name The header name.
137    * @return The header value, or <jk>null</jk> if it doesn't exist.
138    */
139   public String getString(String name) {
140      String[] v = null;
141      if (queryParams != null)
142         v = queryParams.get(name);
143      if (v == null || v.length == 0)
144         v = get(name);
145      if (v == null || v.length == 0)
146         return null;
147      return v[0];
148   }
149
150   /**
151    * Returns the specified header value as a string.
152    * 
153    * <h5 class='section'>Notes:</h5>
154    * <ul class='spaced-list'>
155    *    <li>
156    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
157    * </ul>
158    * 
159    * @param name The HTTP header name.
160    * @param def The default value to return if the header value isn't found.
161    * @return The header value, or the default value if the header isn't present.
162    */
163   public String getString(String name, String def) {
164      String s = getString(name);
165      return StringUtils.isEmpty(s) ? def : s;
166   }
167
168   /**
169    * Same as {@link #getString(String)} but converts the value to an integer.
170    * 
171    * @param name The HTTP header name.
172    * @return The header value, or the default value if the header isn't present.
173    */
174   public int getInt(String name) {
175      return getInt(name, 0);
176   }
177
178   /**
179    * Same as {@link #getString(String,String)} but converts the value to an integer.
180    * 
181    * @param name The HTTP header name.
182    * @param def The default value to return if the header value isn't found.
183    * @return The header value, or the default value if the header isn't present.
184    */
185   public int getInt(String name, int def) {
186      String s = getString(name);
187      return StringUtils.isEmpty(s) ? def : Integer.parseInt(s);
188   }
189
190   /**
191    * Same as {@link #getString(String)} but converts the value to a boolean.
192    * 
193    * @param name The HTTP header name.
194    * @return The header value, or the default value if the header isn't present.
195    */
196   public boolean getBoolean(String name) {
197      return getBoolean(name, false);
198   }
199
200   /**
201    * Same as {@link #getString(String,String)} but converts the value to a boolean.
202    * 
203    * @param name The HTTP header name.
204    * @param def The default value to return if the header value isn't found.
205    * @return The header value, or the default value if the header isn't present.
206    */
207   public boolean getBoolean(String name, boolean def) {
208      String s = getString(name);
209      return StringUtils.isEmpty(s) ? def : Boolean.parseBoolean(s);
210   }
211
212   /**
213    * Sets a request header value.
214    * 
215    * <p>
216    * This overwrites any previous value.
217    * 
218    * @param name The header name.
219    * @param value The header value.
220    */
221   public void put(String name, Object value) {
222      super.put(name, asStrings(value));
223   }
224
225   /**
226    * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource.
227    * 
228    * <h5 class='section'>Examples:</h5>
229    * <p class='bcode'>
230    *    <jc>// Parse into an integer.</jc>
231    *    <jk>int</jk> myheader = req.getHeader(<js>"My-Header"</js>, <jk>int</jk>.<jk>class</jk>);
232    * 
233    *    <jc>// Parse a UUID.</jc>
234    *    UUID myheader = req.getHeader(<js>"My-Header"</js>, UUID.<jk>class</jk>);
235    * </p>
236    * 
237    * <h5 class='section'>Notes:</h5>
238    * <ul class='spaced-list'>
239    *    <li>
240    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
241    * </ul>
242    * 
243    * <h5 class='section'>See Also:</h5>
244    * <ul>
245    *    <li class='jf'>{@link RestContext#REST_partParser}
246    * </ul>
247    * 
248    * @param name The HTTP header name.
249    * @param type The class type to convert the header value to.
250    * @param <T> The class type to convert the header value to.
251    * @return The parameter value converted to the specified class type.
252    * @throws ParseException 
253    */
254   public <T> T get(String name, Class<T> type) throws ParseException {
255      return get(parser, name, null, type);
256   }
257
258   /**
259    * Same as {@link #get(String, Class)} but allows you to override the part parser used.
260    * 
261    * @param parser
262    *    The parser to use for parsing the string header.
263    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
264    * @param name The HTTP header name.
265    * @param type The class type to convert the header value to.
266    * @param <T> The class type to convert the header value to.
267    * @return The parameter value converted to the specified class type.
268    * @throws ParseException 
269    */
270   public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException {
271      return get(parser, name, null, type);
272   }
273
274   /**
275    * Same as {@link #get(String, Class)} but returns a default value if not found.
276    * 
277    * @param name The HTTP header name.
278    * @param def The default value if the header was not specified or is <jk>null</jk>.
279    * @param type The class type to convert the header value to.
280    * @param <T> The class type to convert the header value to.
281    * @return The parameter value converted to the specified class type.
282    * @throws ParseException 
283    */
284   public <T> T get(String name, T def, Class<T> type) throws ParseException {
285      return get(parser, name, def, type);
286   }
287
288   /**
289    * Same as {@link #get(String, Object, Class)} but allows you to override the part parser used.
290    * 
291    * @param parser
292    *    The parser to use for parsing the string header.
293    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
294    * @param name The HTTP header name.
295    * @param def The default value if the header was not specified or is <jk>null</jk>.
296    * @param type The class type to convert the header value to.
297    * @param <T> The class type to convert the header value to.
298    * @return The parameter value converted to the specified class type.
299    * @throws ParseException 
300    */
301   public <T> T get(HttpPartParser parser, String name, T def, Class<T> type) throws ParseException {
302      String s = getString(name);
303      if (s == null)
304         return def;
305      if (parser == null)
306         parser = this.parser;
307      return parser.parse(HttpPartType.HEADER, s, getClassMeta(type));
308   }
309
310   /**
311    * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource.
312    * 
313    * <p>
314    * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
315    * 
316    * <h5 class='section'>Examples:</h5>
317    * <p class='bcode'>
318    *    <jc>// Parse into a linked-list of strings.</jc>
319    *    List&lt;String&gt; myheader = req.getHeader(<js>"My-Header"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
320    * </p>
321    * 
322    * <h5 class='section'>Notes:</h5>
323    * <ul class='spaced-list'>
324    *    <li>
325    *       <code>Collections</code> must be followed by zero or one parameter representing the value type.
326    *    <li>
327    *       <code>Maps</code> must be followed by zero or two parameters representing the key and value types.
328    *    <li>
329    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
330    * </ul>
331    * 
332    * <h5 class='section'>See Also:</h5>
333    * <ul>
334    *    <li class='jf'>{@link RestContext#REST_partParser}
335    * </ul>
336    * 
337    * @param name The HTTP header name.
338    * @param type
339    *    The type of object to create.
340    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
341    * @param args
342    *    The type arguments of the class if it's a collection or map.
343    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
344    *    <br>Ignored if the main type is not a map or collection.
345    * @param <T> The class type to convert the header value to.
346    * @return The parameter value converted to the specified class type.
347    * @throws ParseException If the header could not be converted to the specified type.
348    */
349   public <T> T get(String name, Type type, Type...args) throws ParseException {
350      return get(null, name, type, args);
351   }
352
353   /**
354    * Same as {@link #get(String, Type, Type...)} but allows you to override the part parser used.
355    * 
356    * @param parser
357    *    The parser to use for parsing the string header.
358    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
359    * @param name 
360    *    The HTTP header name.
361    * @param type
362    *    The type of object to create.
363    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
364    * @param args
365    *    The type arguments of the class if it's a collection or map.
366    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
367    *    <br>Ignored if the main type is not a map or collection.
368    * @param <T> The class type to convert the header value to.
369    * @return The parameter value converted to the specified class type.
370    * @throws ParseException If the header could not be converted to the specified type.
371    */
372   @SuppressWarnings("unchecked")
373   public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException {
374      String s = getString(name);
375      if (s == null)
376         return null;
377      if (parser == null)
378         parser = this.parser;
379      return (T)parser.parse(HttpPartType.HEADER, s, getClassMeta(type, args));
380   }
381
382   /**
383    * Returns a copy of this object but only with the specified header names copied.
384    * 
385    * @param headers The headers to include in the copy.
386    * @return A new headers object.
387    */
388   public RequestHeaders subset(String...headers) {
389      RequestHeaders rh2 = new RequestHeaders().parser(parser).beanSession(beanSession).setQueryParams(queryParams);
390      for (String h : headers)
391         if (containsKey(h))
392            rh2.put(h, get(h));
393      return rh2;
394   }
395
396   /**
397    * Same as {@link #subset(String...)} but allows you to specify header names as a comma-delimited list.
398    * 
399    * @param headers The headers to include in the copy.
400    * @return A new headers object.
401    */
402   public RequestHeaders subset(String headers) {
403      return subset(split(headers));
404   }
405
406   /**
407    * Returns the <code>Accept</code> header on the request.
408    * 
409    * <p>
410    * Content-Types that are acceptable for the response.
411    * 
412    * <h5 class='figure'>Example:</h5>
413    * <p class='bcode'>
414    *    Accept: text/plain
415    * </p>
416    * 
417    * @return The parsed <code>Accept</code> header on the request, or <jk>null</jk> if not found.
418    */
419   public Accept getAccept() {
420      return Accept.forString(getString("Accept"));
421   }
422
423   /**
424    * Returns the <code>Accept-Charset</code> header on the request.
425    * 
426    * <p>
427    * Character sets that are acceptable.
428    * 
429    * <h5 class='figure'>Example:</h5>
430    * <p class='bcode'>
431    *    Accept-Charset: utf-8
432    * </p>
433    * 
434    * @return The parsed <code>Accept-Charset</code> header on the request, or <jk>null</jk> if not found.
435    */
436   public AcceptCharset getAcceptCharset() {
437      return AcceptCharset.forString(getString("Accept-Charset"));
438   }
439
440   /**
441    * Returns the <code>Accept-Encoding</code> header on the request.
442    * 
443    * <p>
444    * List of acceptable encodings.
445    * 
446    * <h5 class='figure'>Example:</h5>
447    * <p class='bcode'>
448    *    Accept-Encoding: gzip, deflate
449    * </p>
450    * 
451    * @return The parsed <code>Accept-Encoding</code> header on the request, or <jk>null</jk> if not found.
452    */
453   public AcceptEncoding getAcceptEncoding() {
454      return AcceptEncoding.forString(getString("Accept-Encoding"));
455   }
456
457   /**
458    * Returns the <code>Accept-Language</code> header on the request.
459    * 
460    * <p>
461    * List of acceptable human languages for response.
462    * 
463    * <h5 class='figure'>Example:</h5>
464    * <p class='bcode'>
465    *    Accept-Language: en-US
466    * </p>
467    * 
468    * @return The parsed <code>Accept-Language</code> header on the request, or <jk>null</jk> if not found.
469    */
470   public AcceptLanguage getAcceptLanguage() {
471      return AcceptLanguage.forString(getString("Accept-Language"));
472   }
473
474   /**
475    * Returns the <code>Authorization</code> header on the request.
476    * 
477    * <p>
478    * Authentication credentials for HTTP authentication.
479    * 
480    * <h5 class='figure'>Example:</h5>
481    * <p class='bcode'>
482    *    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
483    * </p>
484    * 
485    * @return The parsed <code>Authorization</code> header on the request, or <jk>null</jk> if not found.
486    */
487   public Authorization getAuthorization() {
488      return Authorization.forString(getString("Authorization"));
489   }
490
491   /**
492    * Returns the <code>Cache-Control</code> header on the request.
493    * 
494    * <p>
495    * Used to specify directives that must be obeyed by all caching mechanisms along the request-response chain.
496    * 
497    * <h5 class='figure'>Example:</h5>
498    * <p class='bcode'>
499    *    Cache-Control: no-cache
500    * </p>
501    * 
502    * @return The parsed <code>Cache-Control</code> header on the request, or <jk>null</jk> if not found.
503    */
504   public CacheControl getCacheControl() {
505      return CacheControl.forString(getString("Cache-Control"));
506   }
507
508   /**
509    * Returns the <code>Connection</code> header on the request.
510    * 
511    * <p>
512    * Control options for the current connection and list of hop-by-hop request fields.
513    * 
514    * <h5 class='figure'>Example:</h5>
515    * <p class='bcode'>
516    *    Connection: keep-alive
517    *    Connection: Upgrade
518    * </p>
519    * 
520    * @return The parsed <code></code> header on the request, or <jk>null</jk> if not found.
521    */
522   public Connection getConnection() {
523      return Connection.forString(getString("Connection"));
524   }
525
526   /**
527    * Returns the <code>Content-Length</code> header on the request.
528    * 
529    * <p>
530    * The length of the request body in octets (8-bit bytes).
531    * 
532    * <h5 class='figure'>Example:</h5>
533    * <p class='bcode'>
534    *    Content-Length: 348
535    * </p>
536    * 
537    * @return The parsed <code>Content-Length</code> header on the request, or <jk>null</jk> if not found.
538    */
539   public ContentLength getContentLength() {
540      return ContentLength.forString(getString("Content-Length"));
541   }
542
543   /**
544    * Returns the <code>Content-Type</code> header on the request.
545    * 
546    * <p>
547    * The MIME type of the body of the request (used with POST and PUT requests).
548    * 
549    * <h5 class='figure'>Example:</h5>
550    * <p class='bcode'>
551    *    Content-Type: application/x-www-form-urlencoded
552    * </p>
553    * 
554    * @return The parsed <code>Content-Type</code> header on the request, or <jk>null</jk> if not found.
555    */
556   public ContentType getContentType() {
557      return ContentType.forString(getString("Content-Type"));
558   }
559
560   /**
561    * Returns the <code>Date</code> header on the request.
562    * 
563    * <p>
564    * The date and time that the message was originated (in "HTTP-date" format as defined by RFC 7231 Date/Time Formats).
565    * 
566    * <h5 class='figure'>Example:</h5>
567    * <p class='bcode'>
568    *    Date: Tue, 15 Nov 1994 08:12:31 GMT
569    * </p>
570    * 
571    * @return The parsed <code>Date</code> header on the request, or <jk>null</jk> if not found.
572    */
573   public Date getDate() {
574      return Date.forString(getString("Date"));
575   }
576
577   /**
578    * Returns the <code>Expect</code> header on the request.
579    * 
580    * <p>
581    * Indicates that particular server behaviors are required by the client.
582    * 
583    * <h5 class='figure'>Example:</h5>
584    * <p class='bcode'>
585    *    Expect: 100-continue
586    * </p>
587    * 
588    * @return The parsed <code>Expect</code> header on the request, or <jk>null</jk> if not found.
589    */
590   public Expect getExpect() {
591      return Expect.forString(getString("Expect"));
592   }
593
594   /**
595    * Returns the <code>From</code> header on the request.
596    * 
597    * <p>
598    * The email address of the user making the request.
599    * 
600    * <h5 class='figure'>Example:</h5>
601    * <p class='bcode'>
602    *    From: user@example.com
603    * </p>
604    * 
605    * @return The parsed <code>From</code> header on the request, or <jk>null</jk> if not found.
606    */
607   public From getFrom() {
608      return From.forString(getString("From"));
609   }
610
611   /**
612    * Returns the <code>Host</code> header on the request.
613    * 
614    * <p>
615    * The domain name of the server (for virtual hosting), and the TCP port number on which the server is listening.
616    * The port number may be omitted if the port is the standard port for the service requested.
617    * 
618    * <h5 class='figure'>Example:</h5>
619    * <p class='bcode'>
620    *    Host: en.wikipedia.org:8080
621    *    Host: en.wikipedia.org
622    * </p>
623    * 
624    * @return The parsed <code>Host</code> header on the request, or <jk>null</jk> if not found.
625    */
626   public Host getHost() {
627      return Host.forString(getString("Host"));
628   }
629
630   /**
631    * Returns the <code>If-Match</code> header on the request.
632    * 
633    * <p>
634    * Only perform the action if the client supplied entity matches the same entity on the server.
635    * This is mainly for methods like PUT to only update a resource if it has not been modified since the user last
636    * updated it.
637    * 
638    * <h5 class='figure'>Example:</h5>
639    * <p class='bcode'>
640    *    If-Match: "737060cd8c284d8af7ad3082f209582d"
641    * </p>
642    * 
643    * @return The parsed <code>If-Match</code> header on the request, or <jk>null</jk> if not found.
644    */
645   public IfMatch getIfMatch() {
646      return IfMatch.forString(getString("If-Match"));
647   }
648
649   /**
650    * Returns the <code>If-Modified-Since</code> header on the request.
651    * 
652    * <p>
653    * Allows a 304 Not Modified to be returned if content is unchanged.
654    * 
655    * <h5 class='figure'>Example:</h5>
656    * <p class='bcode'>
657    *    If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
658    * </p>
659    * 
660    * @return The parsed <code>If-Modified-Since</code> header on the request, or <jk>null</jk> if not found.
661    */
662   public IfModifiedSince getIfModifiedSince() {
663      return IfModifiedSince.forString(getString("If-Modified-Since"));
664   }
665
666   /**
667    * Returns the <code>If-None-Match</code> header on the request.
668    * 
669    * <p>
670    * Allows a 304 Not Modified to be returned if content is unchanged, see HTTP ETag.
671    * 
672    * <h5 class='figure'>Example:</h5>
673    * <p class='bcode'>
674    *    If-None-Match: "737060cd8c284d8af7ad3082f209582d"
675    * </p>
676    * 
677    * @return The parsed <code>If-None-Match</code> header on the request, or <jk>null</jk> if not found.
678    */
679   public IfNoneMatch getIfNoneMatch() {
680      return IfNoneMatch.forString(getString("If-None-Match"));
681   }
682
683   /**
684    * Returns the <code>If-Range</code> header on the request.
685    * 
686    * <p>
687    * If the entity is unchanged, send me the part(s) that I am missing; otherwise, send me the entire new entity.
688    * 
689    * <h5 class='figure'>Example:</h5>
690    * <p class='bcode'>
691    *    If-Range: "737060cd8c284d8af7ad3082f209582d"
692    * </p>
693    * 
694    * @return The parsed <code>If-Range</code> header on the request, or <jk>null</jk> if not found.
695    */
696   public IfRange getIfRange() {
697      return IfRange.forString(getString("If-Range"));
698   }
699
700   /**
701    * Returns the <code>If-Unmodified-Since</code> header on the request.
702    * 
703    * <p>
704    * Only send the response if the entity has not been modified since a specific time.
705    * 
706    * <h5 class='figure'>Example:</h5>
707    * <p class='bcode'>
708    *    If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
709    * </p>
710    * 
711    * @return The parsed <code>If-Unmodified-Since</code> header on the request, or <jk>null</jk> if not found.
712    */
713   public IfUnmodifiedSince getIfUnmodifiedSince() {
714      return IfUnmodifiedSince.forString(getString("If-Unmodified-Since"));
715   }
716
717   /**
718    * Returns the <code>Max-Forwards</code> header on the request.
719    * 
720    * <p>
721    * Limit the number of times the message can be forwarded through proxies or gateways.
722    * 
723    * <h5 class='figure'>Example:</h5>
724    * <p class='bcode'>
725    *    Max-Forwards: 10
726    * </p>
727    * 
728    * @return The parsed <code>Max-Forwards</code> header on the request, or <jk>null</jk> if not found.
729    */
730   public MaxForwards getMaxForwards() {
731      return MaxForwards.forString(getString("Max-Forwards"));
732   }
733
734   /**
735    * Returns the <code>Pragma</code> header on the request.
736    * 
737    * <p>
738    * Implementation-specific fields that may have various effects anywhere along the request-response chain.
739    * 
740    * <h5 class='figure'>Example:</h5>
741    * <p class='bcode'>
742    *    Pragma: no-cache
743    * </p>
744    * 
745    * @return The parsed <code>Pragma</code> header on the request, or <jk>null</jk> if not found.
746    */
747   public Pragma getPragma() {
748      return Pragma.forString(getString("Pragma"));
749   }
750
751   /**
752    * Returns the <code>Proxy-Authorization</code> header on the request.
753    * 
754    * <p>
755    * Authorization credentials for connecting to a proxy.
756    * 
757    * <h5 class='figure'>Example:</h5>
758    * <p class='bcode'>
759    *    Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
760    * </p>
761    * 
762    * @return The parsed <code>Proxy-Authorization</code> header on the request, or <jk>null</jk> if not found.
763    */
764   public ProxyAuthorization getProxyAuthorization() {
765      return ProxyAuthorization.forString(getString("Proxy-Authorization"));
766   }
767
768   /**
769    * Returns the <code>Range</code> header on the request.
770    * 
771    * <p>
772    * Request only part of an entity. Bytes are numbered from 0.
773    * 
774    * <h5 class='figure'>Example:</h5>
775    * <p class='bcode'>
776    *    Range: bytes=500-999
777    * </p>
778    * 
779    * @return The parsed <code>Range</code> header on the request, or <jk>null</jk> if not found.
780    */
781   public Range getRange() {
782      return Range.forString(getString("Range"));
783   }
784
785   /**
786    * Returns the <code>Referer</code> header on the request.
787    * 
788    * <p>
789    * This is the address of the previous web page from which a link to the currently requested page was followed.
790    * 
791    * <h5 class='figure'>Example:</h5>
792    * <p class='bcode'>
793    *    Referer: http://en.wikipedia.org/wiki/Main_Page
794    * </p>
795    * 
796    * @return The parsed <code>Referer</code> header on the request, or <jk>null</jk> if not found.
797    */
798   public Referer getReferer() {
799      return Referer.forString(getString("Referer"));
800   }
801
802   /**
803    * Returns the <code>TE</code> header on the request.
804    * 
805    * <p>
806    * The transfer encodings the user agent is willing to accept: the same values as for the response header field
807    * Transfer-Encoding can be used, plus the "trailers" value (related to the "chunked" transfer method) to notify the
808    * server it expects to receive additional fields in the trailer after the last, zero-sized, chunk.
809    * 
810    * <h5 class='figure'>Example:</h5>
811    * <p class='bcode'>
812    *    TE: trailers, deflate
813    * </p>
814    * 
815    * @return The parsed <code>TE</code> header on the request, or <jk>null</jk> if not found.
816    */
817   public TE getTE() {
818      return TE.forString(getString("TE"));
819   }
820
821   /**
822    * Returns the <code>Time-Zone</code> header value on the request if there is one.
823    * 
824    * <p>
825    * Example: <js>"GMT"</js>.
826    * 
827    * @return The <code>Time-Zone</code> header value on the request, or <jk>null</jk> if not present.
828    */
829   public TimeZone getTimeZone() {
830      String tz = getString("Time-Zone");
831      if (tz != null)
832         return TimeZone.getTimeZone(tz);
833      return null;
834   }
835
836   /**
837    * Returns the <code>User-Agent</code> header on the request.
838    * 
839    * <p>
840    * The user agent string of the user agent.
841    * 
842    * <h5 class='figure'>Example:</h5>
843    * <p class='bcode'>
844    *    User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0
845    * </p>
846    * 
847    * @return The parsed <code>User-Agent</code> header on the request, or <jk>null</jk> if not found.
848    */
849   public UserAgent getUserAgent() {
850      return UserAgent.forString(getString("User-Agent"));
851   }
852
853   /**
854    * Returns the <code>Upgrade</code> header on the request.
855    * 
856    * <p>
857    * Ask the server to upgrade to another protocol.
858    * 
859    * <h5 class='figure'>Example:</h5>
860    * <p class='bcode'>
861    *    Upgrade: HTTP/2.0, HTTPS/1.3, IRC/6.9, RTA/x11, websocket
862    * </p>
863    * 
864    * @return The parsed <code>Upgrade</code> header on the request, or <jk>null</jk> if not found.
865    */
866   public Upgrade getUpgrade() {
867      return Upgrade.forString(getString("Upgrade"));
868   }
869
870   /**
871    * Returns the <code>Via</code> header on the request.
872    * 
873    * <p>
874    * Informs the server of proxies through which the request was sent.
875    * 
876    * <h5 class='figure'>Example:</h5>
877    * <p class='bcode'>
878    *    Via: 1.0 fred, 1.1 example.com (Apache/1.1)
879    * </p>
880    * 
881    * @return The parsed <code>Via</code> header on the request, or <jk>null</jk> if not found.
882    */
883   public Via getVia() {
884      return Via.forString(getString("Via"));
885   }
886
887   /**
888    * Returns the <code>Warning</code> header on the request.
889    * 
890    * <p>
891    * A general warning about possible problems with the entity body.
892    * 
893    * <h5 class='figure'>Example:</h5>
894    * <p class='bcode'>
895    *    Warning: 199 Miscellaneous warning
896    * </p>
897    * 
898    * @return The parsed <code>Warning</code> header on the request, or <jk>null</jk> if not found.
899    */
900   public Warning getWarning() {
901      return Warning.forString(getString("Warning"));
902   }
903
904   /**
905    * Converts the headers to a readable string.
906    * 
907    * @param sorted Sort the headers by name.
908    * @return A JSON string containing the contents of the headers.
909    */
910   public String toString(boolean sorted) {
911      Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>());
912      for (Map.Entry<String,String[]> e : this.entrySet()) {
913         String[] v = e.getValue();
914         m.put(e.getKey(), v.length == 1 ? v[0] : v);
915      }
916      return JsonSerializer.DEFAULT_LAX.toString(m);
917   }
918   
919   private ClassMeta<?> getClassMeta(Type type, Type...args) {
920      return beanSession.getClassMeta(type, args);
921   }
922
923   private <T> ClassMeta<T> getClassMeta(Class<T> type) {
924      return beanSession.getClassMeta(type);
925   }
926
927   @Override /* Object */
928   public String toString() {
929      return toString(false);
930   }
931}