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.collections.*;
023import org.apache.juneau.httppart.*;
024import org.apache.juneau.internal.*;
025import org.apache.juneau.json.*;
026import org.apache.juneau.oapi.*;
027import org.apache.juneau.parser.*;
028import org.apache.juneau.http.exception.*;
029import org.apache.juneau.http.header.*;
030import org.apache.juneau.http.header.Date;
031
032/**
033 * Represents the headers in an HTTP request.
034 *
035 * <p>
036 * Entries are stored in a case-insensitive map.
037 *
038 * <ul class='seealso'>
039 *    <li class='link'>{@doc RestmRequestHeaders}
040 * </ul>
041 */
042public class RequestHeaders extends TreeMap<String,String[]> {
043   private static final long serialVersionUID = 1L;
044
045   private final RestRequest req;
046   private HttpPartParserSession parser;
047   private RequestQuery queryParams;
048   private Set<String> allowedQueryParams;
049
050   RequestHeaders(RestRequest req) {
051      super(String.CASE_INSENSITIVE_ORDER);
052      this.req = req;
053   }
054
055   RequestHeaders parser(HttpPartParserSession parser) {
056      this.parser = parser;
057      return this;
058   }
059
060   RequestHeaders queryParams(RequestQuery queryParams, Set<String> allowedQueryParams) {
061      this.queryParams = queryParams;
062      this.allowedQueryParams = allowedQueryParams;
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, stringifyAll(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 <c>toString()</c>.
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 last value as a string.
129    *
130    * <ul class='notes'>
131    *    <li>
132    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
133    * </ul>
134    *
135    * @param name The header name.
136    * @return The header value, or <jk>null</jk> if it doesn't exist.
137    */
138   public String getString(String name) {
139      String[] v = null;
140      if (queryParams != null)
141         if (allowedQueryParams.contains("*") || allowedQueryParams.contains(name))
142            v = queryParams.get(name, true);
143      if (v == null || v.length == 0)
144         v = get(name);
145      if (v == null || v.length == 0)
146         return null;
147      return v[v.length-1];
148   }
149
150   /**
151    * Returns the specified header value as a string.
152    *
153    * <ul class='notes'>
154    *    <li>
155    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
156    * </ul>
157    *
158    * @param name The HTTP header name.
159    * @param def The default value to return if the header value isn't found.
160    * @return The header value, or the default value if the header isn't present.
161    */
162   public String getString(String name, String def) {
163      String s = getString(name);
164      return StringUtils.isEmpty(s) ? def : s;
165   }
166
167   /**
168    * Returns the specified header value as an integer.
169    *
170    * <ul class='notes'>
171    *    <li>
172    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
173    * </ul>
174    *
175    * @param name The HTTP header name.
176    * @return The header value, or <code>0</code> value if the header isn't present.
177    */
178   public int getInt(String name) {
179      return getInt(name, 0);
180   }
181
182   /**
183    * Returns the specified header value as an integer.
184    *
185    * <ul class='notes'>
186    *    <li>
187    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
188    * </ul>
189    *
190    * @param name The HTTP header name.
191    * @param def The default value to return if the header value isn't found.
192    * @return The header value, or the default value if the header isn't present.
193    */
194   public int getInt(String name, int def) {
195      String s = getString(name);
196      return StringUtils.isEmpty(s) ? def : Integer.parseInt(s);
197   }
198
199   /**
200    * Returns the specified header value as a boolean.
201    *
202    * <ul class='notes'>
203    *    <li>
204    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
205    * </ul>
206    *
207    * @param name The HTTP header name.
208    * @return The header value, or the default value if the header isn't present.
209    */
210   public boolean getBoolean(String name) {
211      return getBoolean(name, false);
212   }
213
214   /**
215    * Returns the specified header value as a boolean.
216    *
217    * <ul class='notes'>
218    *    <li>
219    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
220    * </ul>
221    *
222    * @param name The HTTP header name.
223    * @param def The default value to return if the header value isn't found.
224    * @return The header value, or the default value if the header isn't present.
225    */
226   public boolean getBoolean(String name, boolean def) {
227      String s = getString(name);
228      return StringUtils.isEmpty(s) ? def : Boolean.parseBoolean(s);
229   }
230
231   /**
232    * Sets a request header value.
233    *
234    * <p>
235    * This overwrites any previous value.
236    *
237    * @param name The header name.
238    * @param value The header value.
239    */
240   public void put(String name, Object value) {
241      super.put(name, stringifyAll(value));
242   }
243
244   /**
245    * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource.
246    *
247    * <h5 class='section'>Examples:</h5>
248    * <p class='bcode w800'>
249    *    <jc>// Parse into an integer.</jc>
250    *    <jk>int</jk> myheader = req.getHeaders().get(<js>"My-Header"</js>, <jk>int</jk>.<jk>class</jk>);
251    *
252    *    <jc>// Parse a UUID.</jc>
253    *    UUID myheader = req.getHeaders().get(<js>"My-Header"</js>, UUID.<jk>class</jk>);
254    * </p>
255    *
256    * <ul class='notes'>
257    *    <li>
258    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
259    * </ul>
260    *
261    * <ul class='seealso'>
262    *    <li class='jf'>{@link RestContext#REST_partParser}
263    * </ul>
264    *
265    * @param name The HTTP header name.
266    * @param type The class type to convert the header value to.
267    * @param <T> The class type to convert the header value to.
268    * @return The parameter value converted to the specified class type.
269    * @throws BadRequest Thrown if input could not be parsed.
270    * @throws InternalServerError Thrown if any other exception occurs.
271    */
272   public <T> T get(String name, Class<T> type) throws BadRequest, InternalServerError {
273      return getInner(null, null, name, null, getClassMeta(type));
274   }
275
276   /**
277    * Returns all headers with the specified name converted to a POJO using the {@link HttpPartParser} registered with the resource.
278    *
279    * <h5 class='section'>Examples:</h5>
280    * <p class='bcode w800'>
281    *    <jc>// Parse into an integer.</jc>
282    *    <jk>int</jk>[] myheaders = req.getHeaders().getAll(<js>"My-Header"</js>, <jk>int</jk>[].<jk>class</jk>);
283    *
284    *    <jc>// Parse a UUID.</jc>
285    *    UUID[] myheaders = req.getHeaders().getAll(<js>"My-Header"</js>, UUID[].<jk>class</jk>);
286    * </p>
287    *
288    * <ul class='notes'>
289    *    <li>
290    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
291    *    <li>
292    *       The class must be an array or collection type.
293    * </ul>
294    *
295    * <ul class='seealso'>
296    *    <li class='jf'>{@link RestContext#REST_partParser}
297    * </ul>
298    *
299    * @param name The HTTP header name.
300    * @param type The class type to convert the header value to.
301    * @param <T> The class type to convert the header value to.
302    * @return The parameter value converted to the specified class type.
303    * @throws BadRequest Thrown if input could not be parsed.
304    * @throws InternalServerError Thrown if any other exception occurs.
305    */
306   public <T> T getAll(String name, Class<T> type) throws BadRequest, InternalServerError {
307      return getAllInner(null, null, name, getClassMeta(type));
308   }
309
310   /**
311    * Returns the specified header value converted to a POJO using the specified part parser.
312    *
313    * <h5 class='section'>Examples:</h5>
314    * <p class='bcode w800'>
315    *    <jc>// Parse into an integer.</jc>
316    *    <jk>int</jk> myheader = req.getHeaders().get(<js>"My-Header"</js>, <jk>int</jk>.<jk>class</jk>);
317    *
318    *    <jc>// Parse a UUID.</jc>
319    *    UUID myheader = req.getHeaders().get(<js>"My-Header"</js>, UUID.<jk>class</jk>);
320    * </p>
321    *
322    * <ul class='notes'>
323    *    <li>
324    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
325    * </ul>
326    *
327    * <ul class='seealso'>
328    *    <li class='jf'>{@link RestContext#REST_partParser}
329    * </ul>
330    *
331    * @param parser
332    *    The parser to use for parsing the string header.
333    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
334    * @param schema
335    *    The schema object that defines the format of the input.
336    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
337    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
338    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
339    * @param name The HTTP header name.
340    * @param type The class type to convert the header value to.
341    * @param <T> The class type to convert the header value to.
342    * @return The parameter value converted to the specified class type.
343    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
344    * @throws InternalServerError Thrown if any other exception occurs.
345    */
346   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError {
347      return getInner(parser, schema, name, null, getClassMeta(type));
348   }
349
350   /**
351    * Same as {@link #get(String, Class)} but returns a default value if not found.
352    *
353    * @param name The HTTP header name.
354    * @param def The default value if the header was not specified or is <jk>null</jk>.
355    * @param type The class type to convert the header value to.
356    * @param <T> The class type to convert the header value to.
357    * @return The parameter value converted to the specified class type.
358    * @throws BadRequest Thrown if input could not be parsed.
359    * @throws InternalServerError Thrown if any other exception occurs.
360    */
361   public <T> T get(String name, T def, Class<T> type) throws BadRequest, InternalServerError {
362      return getInner(null, null, name, def, getClassMeta(type));
363   }
364
365   /**
366    * Same as {@link #get(String, Object, Class)} but allows you to override the part parser used.
367    *
368    * @param parser
369    *    The parser to use for parsing the string header.
370    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
371    * @param schema
372    *    The schema object that defines the format of the input.
373    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
374    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
375    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
376    * @param name The HTTP header name.
377    * @param def The default value if the header was not specified or is <jk>null</jk>.
378    * @param type The class type to convert the header value to.
379    * @param <T> The class type to convert the header value to.
380    * @return The parameter value converted to the specified class type.
381    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
382    * @throws InternalServerError Thrown if any other exception occurs.
383    */
384   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, T def, Class<T> type) throws BadRequest, InternalServerError {
385      return getInner(parser, schema, name, def, getClassMeta(type));
386   }
387
388   /**
389    * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource.
390    *
391    * <p>
392    * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
393    *
394    * <h5 class='section'>Examples:</h5>
395    * <p class='bcode w800'>
396    *    <jc>// Parse into a linked-list of strings.</jc>
397    *    List&lt;String&gt; myheader = req.getHeader(<js>"My-Header"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
398    * </p>
399    *
400    * <ul class='notes'>
401    *    <li>
402    *       <c>Collections</c> must be followed by zero or one parameter representing the value type.
403    *    <li>
404    *       <c>Maps</c> must be followed by zero or two parameters representing the key and value types.
405    *    <li>
406    *       If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
407    * </ul>
408    *
409    * <ul class='seealso'>
410    *    <li class='jf'>{@link RestContext#REST_partParser}
411    * </ul>
412    *
413    * @param name The HTTP header name.
414    * @param type
415    *    The type of object to create.
416    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
417    * @param args
418    *    The type arguments of the class if it's a collection or map.
419    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
420    *    <br>Ignored if the main type is not a map or collection.
421    * @param <T> The class type to convert the header value to.
422    * @return The parameter value converted to the specified class type.
423    * @throws BadRequest Thrown if input could not be parsed.
424    * @throws InternalServerError Thrown if any other exception occurs.
425    */
426   public <T> T get(String name, Type type, Type...args) throws BadRequest, InternalServerError {
427      return getInner(null, null, name, null, this.<T>getClassMeta(type, args));
428   }
429
430   /**
431    * Same as {@link #get(String, Type, Type...)} but allows you to override the part parser used.
432    *
433    * @param parser
434    *    The parser to use for parsing the string header.
435    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
436    * @param schema
437    *    The schema object that defines the format of the input.
438    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
439    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
440    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
441    * @param name
442    *    The HTTP header name.
443    * @param type
444    *    The type of object to create.
445    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
446    * @param args
447    *    The type arguments of the class if it's a collection or map.
448    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
449    *    <br>Ignored if the main type is not a map or collection.
450    * @param <T> The class type to convert the header value to.
451    * @return The parameter value converted to the specified class type.
452    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
453    * @throws InternalServerError Thrown if any other exception occurs.
454    */
455   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, Type type, Type...args) throws BadRequest, InternalServerError {
456      return getInner(parser, schema, name, null, this.<T>getClassMeta(type, args));
457   }
458
459   /**
460    * Converts all the headers with the specified name to the specified type.
461    *
462    * @param parser
463    *    The parser to use for parsing the string header.
464    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
465    * @param schema
466    *    The schema object that defines the format of the input.
467    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
468    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
469    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
470    * @param name
471    *    The HTTP header name.
472    * @param type
473    *    The type of object to create.
474    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
475    * @param args
476    *    The type arguments of the class if it's a collection or map.
477    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
478    *    <br>Ignored if the main type is not a map or collection.
479    * @param <T> The class type to convert the header value to.
480    * @return The parameter value converted to the specified class type.
481    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
482    * @throws InternalServerError Thrown if any other exception occurs.
483    */
484   public <T> T getAll(HttpPartParserSession parser, HttpPartSchema schema, String name, Type type, Type...args) throws BadRequest, InternalServerError {
485      return getAllInner(parser, schema, name, this.<T>getClassMeta(type, args));
486   }
487
488   /* Workhorse method */
489   private <T> T getInner(HttpPartParserSession parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws BadRequest, InternalServerError {
490      if (parser == null)
491         parser = req.getPartParser();
492      try {
493         if (cm.isMapOrBean() && isOneOf(name, "*", "")) {
494            OMap m = new OMap();
495            for (Map.Entry<String,String[]> e : this.entrySet()) {
496               String k = e.getKey();
497               HttpPartSchema pschema = schema == null ? null : schema.getProperty(k);
498               ClassMeta<?> cm2 = cm.getValueType();
499               m.put(k, getInner(parser, pschema, k, null, cm2));
500            }
501            return req.getBeanSession().convertToType(m, cm);
502         }
503         T t = parse(parser, schema, getString(name), cm);
504         return (t == null ? def : t);
505      } catch (SchemaValidationException e) {
506         throw new BadRequest(e, "Validation failed on header ''{0}''. ", name);
507      } catch (ParseException e) {
508         throw new BadRequest(e, "Could not parse header ''{0}''.", name) ;
509      } catch (Exception e) {
510         throw new InternalServerError(e, "Could not parse header ''{0}''.", name);
511      }
512   }
513
514   /* Workhorse method */
515   @SuppressWarnings({ "rawtypes", "unchecked" })
516   <T> T getAllInner(HttpPartParserSession parser, HttpPartSchema schema, String name, ClassMeta<T> cm) throws BadRequest, InternalServerError {
517      String[] p = get(name);
518      if (p == null)
519         p = new String[0];
520      if (schema == null)
521         schema = HttpPartSchema.DEFAULT;
522      try {
523         if (cm.isArray()) {
524            List c = new ArrayList();
525            for (int i = 0; i < p.length; i++)
526               c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
527            return (T)toArray(c, cm.getElementType().getInnerClass());
528         } else if (cm.isCollection()) {
529            Collection c = (Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new OList());
530            for (int i = 0; i < p.length; i++)
531               c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
532            return (T)c;
533         }
534      } catch (SchemaValidationException e) {
535         throw new BadRequest(e, "Validation failed on header ''{0}''. ", name);
536      } catch (ParseException e) {
537         throw new BadRequest(e, "Could not parse header ''{0}''.", name) ;
538      } catch (Exception e) {
539         throw new InternalServerError(e, "Could not parse header ''{0}''.", name);
540      }
541      throw new InternalServerError("Invalid call to getAll(String, ClassMeta).  Class type must be a Collection or array.");
542   }
543
544   /* Workhorse method */
545   private <T> T parse(HttpPartParserSession parser, HttpPartSchema schema, String val, ClassMeta<T> cm) throws SchemaValidationException, ParseException {
546      if (parser == null)
547         parser = this.parser;
548      return parser.parse(HttpPartType.HEADER, schema, val, cm);
549   }
550
551   /**
552    * Returns a copy of this object but only with the specified header names copied.
553    *
554    * @param headers The headers to include in the copy.
555    * @return A new headers object.
556    */
557   public RequestHeaders subset(String...headers) {
558      RequestHeaders rh2 = new RequestHeaders(req).parser(parser).queryParams(queryParams, allowedQueryParams);
559      for (String h : headers)
560         if (containsKey(h))
561            rh2.put(h, get(h));
562      return rh2;
563   }
564
565   /**
566    * Same as {@link #subset(String...)} but allows you to specify header names as a comma-delimited list.
567    *
568    * @param headers The headers to include in the copy.
569    * @return A new headers object.
570    */
571   public RequestHeaders subset(String headers) {
572      return subset(split(headers));
573   }
574
575   /**
576    * Returns the <c>Accept</c> header on the request.
577    *
578    * <p>
579    * Content-Types that are acceptable for the response.
580    *
581    * <h5 class='figure'>Example:</h5>
582    * <p class='bcode w800'>
583    *    Accept: text/plain
584    * </p>
585    *
586    * @return The parsed <c>Accept</c> header on the request, or <jk>null</jk> if not found.
587    */
588   public Accept getAccept() {
589      return Accept.of(getString("Accept"));
590   }
591
592   /**
593    * Returns the <c>Accept-Charset</c> header on the request.
594    *
595    * <p>
596    * Character sets that are acceptable.
597    *
598    * <h5 class='figure'>Example:</h5>
599    * <p class='bcode w800'>
600    *    Accept-Charset: utf-8
601    * </p>
602    *
603    * @return The parsed <c>Accept-Charset</c> header on the request, or <jk>null</jk> if not found.
604    */
605   public AcceptCharset getAcceptCharset() {
606      return AcceptCharset.of(getString("Accept-Charset"));
607   }
608
609   /**
610    * Returns the <c>Accept-Encoding</c> header on the request.
611    *
612    * <p>
613    * List of acceptable encodings.
614    *
615    * <h5 class='figure'>Example:</h5>
616    * <p class='bcode w800'>
617    *    Accept-Encoding: gzip, deflate
618    * </p>
619    *
620    * @return The parsed <c>Accept-Encoding</c> header on the request, or <jk>null</jk> if not found.
621    */
622   public AcceptEncoding getAcceptEncoding() {
623      return AcceptEncoding.of(getString("Accept-Encoding"));
624   }
625
626   /**
627    * Returns the <c>Accept-Language</c> header on the request.
628    *
629    * <p>
630    * List of acceptable human languages for response.
631    *
632    * <h5 class='figure'>Example:</h5>
633    * <p class='bcode w800'>
634    *    Accept-Language: en-US
635    * </p>
636    *
637    * @return The parsed <c>Accept-Language</c> header on the request, or <jk>null</jk> if not found.
638    */
639   public AcceptLanguage getAcceptLanguage() {
640      return AcceptLanguage.of(getString("Accept-Language"));
641   }
642
643   /**
644    * Returns the <c>Authorization</c> header on the request.
645    *
646    * <p>
647    * Authentication credentials for HTTP authentication.
648    *
649    * <h5 class='figure'>Example:</h5>
650    * <p class='bcode w800'>
651    *    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
652    * </p>
653    *
654    * @return The parsed <c>Authorization</c> header on the request, or <jk>null</jk> if not found.
655    */
656   public Authorization getAuthorization() {
657      return Authorization.of(getString("Authorization"));
658   }
659
660   /**
661    * Returns the <c>Cache-Control</c> header on the request.
662    *
663    * <p>
664    * Used to specify directives that must be obeyed by all caching mechanisms along the request-response chain.
665    *
666    * <h5 class='figure'>Example:</h5>
667    * <p class='bcode w800'>
668    *    Cache-Control: no-cache
669    * </p>
670    *
671    * @return The parsed <c>Cache-Control</c> header on the request, or <jk>null</jk> if not found.
672    */
673   public CacheControl getCacheControl() {
674      return CacheControl.of(getString("Cache-Control"));
675   }
676
677   /**
678    * Returns the <c>Connection</c> header on the request.
679    *
680    * <p>
681    * Control options for the current connection and list of hop-by-hop request fields.
682    *
683    * <h5 class='figure'>Example:</h5>
684    * <p class='bcode w800'>
685    *    Connection: keep-alive
686    *    Connection: Upgrade
687    * </p>
688    *
689    * @return The parsed <code></code> header on the request, or <jk>null</jk> if not found.
690    */
691   public Connection getConnection() {
692      return Connection.of(getString("Connection"));
693   }
694
695   /**
696    * Returns the <c>Content-Length</c> header on the request.
697    *
698    * <p>
699    * The length of the request body in octets (8-bit bytes).
700    *
701    * <h5 class='figure'>Example:</h5>
702    * <p class='bcode w800'>
703    *    Content-Length: 348
704    * </p>
705    *
706    * @return The parsed <c>Content-Length</c> header on the request, or <jk>null</jk> if not found.
707    */
708   public ContentLength getContentLength() {
709      return ContentLength.of(getString("Content-Length"));
710   }
711
712   /**
713    * Returns the <c>Content-Type</c> header on the request.
714    *
715    * <p>
716    * The MIME type of the body of the request (used with POST and PUT requests).
717    *
718    * <h5 class='figure'>Example:</h5>
719    * <p class='bcode w800'>
720    *    Content-Type: application/x-www-form-urlencoded
721    * </p>
722    *
723    * @return The parsed <c>Content-Type</c> header on the request, or <jk>null</jk> if not found.
724    */
725   public ContentType getContentType() {
726      return ContentType.of(getString("Content-Type"));
727   }
728
729   /**
730    * Returns the <c>Date</c> header on the request.
731    *
732    * <p>
733    * The date and time that the message was originated (in "HTTP-date" format as defined by RFC 7231 Date/Time Formats).
734    *
735    * <h5 class='figure'>Example:</h5>
736    * <p class='bcode w800'>
737    *    Date: Tue, 15 Nov 1994 08:12:31 GMT
738    * </p>
739    *
740    * @return The parsed <c>Date</c> header on the request, or <jk>null</jk> if not found.
741    */
742   public Date getDate() {
743      return Date.of(getString("Date"));
744   }
745
746   /**
747    * Returns the <c>Expect</c> header on the request.
748    *
749    * <p>
750    * Indicates that particular server behaviors are required by the client.
751    *
752    * <h5 class='figure'>Example:</h5>
753    * <p class='bcode w800'>
754    *    Expect: 100-continue
755    * </p>
756    *
757    * @return The parsed <c>Expect</c> header on the request, or <jk>null</jk> if not found.
758    */
759   public Expect getExpect() {
760      return Expect.of(getString("Expect"));
761   }
762
763   /**
764    * Returns the <c>From</c> header on the request.
765    *
766    * <p>
767    * The email address of the user making the request.
768    *
769    * <h5 class='figure'>Example:</h5>
770    * <p class='bcode w800'>
771    *    From: user@example.com
772    * </p>
773    *
774    * @return The parsed <c>From</c> header on the request, or <jk>null</jk> if not found.
775    */
776   public From getFrom() {
777      return From.of(getString("From"));
778   }
779
780   /**
781    * Returns the <c>Host</c> header on the request.
782    *
783    * <p>
784    * The domain name of the server (for virtual hosting), and the TCP port number on which the server is listening.
785    * The port number may be omitted if the port is the standard port for the service requested.
786    *
787    * <h5 class='figure'>Example:</h5>
788    * <p class='bcode w800'>
789    *    Host: en.wikipedia.org:8080
790    *    Host: en.wikipedia.org
791    * </p>
792    *
793    * @return The parsed <c>Host</c> header on the request, or <jk>null</jk> if not found.
794    */
795   public Host getHost() {
796      return Host.of(getString("Host"));
797   }
798
799   /**
800    * Returns the <c>If-Match</c> header on the request.
801    *
802    * <p>
803    * Only perform the action if the client supplied entity matches the same entity on the server.
804    * This is mainly for methods like PUT to only update a resource if it has not been modified since the user last
805    * updated it.
806    *
807    * <h5 class='figure'>Example:</h5>
808    * <p class='bcode w800'>
809    *    If-Match: "737060cd8c284d8af7ad3082f209582d"
810    * </p>
811    *
812    * @return The parsed <c>If-Match</c> header on the request, or <jk>null</jk> if not found.
813    */
814   public IfMatch getIfMatch() {
815      return IfMatch.of(getString("If-Match"));
816   }
817
818   /**
819    * Returns the <c>If-Modified-Since</c> header on the request.
820    *
821    * <p>
822    * Allows a 304 Not Modified to be returned if content is unchanged.
823    *
824    * <h5 class='figure'>Example:</h5>
825    * <p class='bcode w800'>
826    *    If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
827    * </p>
828    *
829    * @return The parsed <c>If-Modified-Since</c> header on the request, or <jk>null</jk> if not found.
830    */
831   public IfModifiedSince getIfModifiedSince() {
832      return IfModifiedSince.of(getString("If-Modified-Since"));
833   }
834
835   /**
836    * Returns the <c>If-None-Match</c> header on the request.
837    *
838    * <p>
839    * Allows a 304 Not Modified to be returned if content is unchanged, see HTTP ETag.
840    *
841    * <h5 class='figure'>Example:</h5>
842    * <p class='bcode w800'>
843    *    If-None-Match: "737060cd8c284d8af7ad3082f209582d"
844    * </p>
845    *
846    * @return The parsed <c>If-None-Match</c> header on the request, or <jk>null</jk> if not found.
847    */
848   public IfNoneMatch getIfNoneMatch() {
849      return IfNoneMatch.of(getString("If-None-Match"));
850   }
851
852   /**
853    * Returns the <c>If-Range</c> header on the request.
854    *
855    * <p>
856    * If the entity is unchanged, send me the part(s) that I am missing; otherwise, send me the entire new entity.
857    *
858    * <h5 class='figure'>Example:</h5>
859    * <p class='bcode w800'>
860    *    If-Range: "737060cd8c284d8af7ad3082f209582d"
861    * </p>
862    *
863    * @return The parsed <c>If-Range</c> header on the request, or <jk>null</jk> if not found.
864    */
865   public IfRange getIfRange() {
866      return IfRange.of(getString("If-Range"));
867   }
868
869   /**
870    * Returns the <c>If-Unmodified-Since</c> header on the request.
871    *
872    * <p>
873    * Only send the response if the entity has not been modified since a specific time.
874    *
875    * <h5 class='figure'>Example:</h5>
876    * <p class='bcode w800'>
877    *    If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
878    * </p>
879    *
880    * @return The parsed <c>If-Unmodified-Since</c> header on the request, or <jk>null</jk> if not found.
881    */
882   public IfUnmodifiedSince getIfUnmodifiedSince() {
883      return IfUnmodifiedSince.of(getString("If-Unmodified-Since"));
884   }
885
886   /**
887    * Returns the <c>Max-Forwards</c> header on the request.
888    *
889    * <p>
890    * Limit the number of times the message can be forwarded through proxies or gateways.
891    *
892    * <h5 class='figure'>Example:</h5>
893    * <p class='bcode w800'>
894    *    Max-Forwards: 10
895    * </p>
896    *
897    * @return The parsed <c>Max-Forwards</c> header on the request, or <jk>null</jk> if not found.
898    */
899   public MaxForwards getMaxForwards() {
900      return MaxForwards.of(getString("Max-Forwards"));
901   }
902
903   /**
904    * Returns the <c>Pragma</c> header on the request.
905    *
906    * <p>
907    * Implementation-specific fields that may have various effects anywhere along the request-response chain.
908    *
909    * <h5 class='figure'>Example:</h5>
910    * <p class='bcode w800'>
911    *    Pragma: no-cache
912    * </p>
913    *
914    * @return The parsed <c>Pragma</c> header on the request, or <jk>null</jk> if not found.
915    */
916   public Pragma getPragma() {
917      return Pragma.of(getString("Pragma"));
918   }
919
920   /**
921    * Returns the <c>Proxy-Authorization</c> header on the request.
922    *
923    * <p>
924    * Authorization credentials for connecting to a proxy.
925    *
926    * <h5 class='figure'>Example:</h5>
927    * <p class='bcode w800'>
928    *    Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
929    * </p>
930    *
931    * @return The parsed <c>Proxy-Authorization</c> header on the request, or <jk>null</jk> if not found.
932    */
933   public ProxyAuthorization getProxyAuthorization() {
934      return ProxyAuthorization.of(getString("Proxy-Authorization"));
935   }
936
937   /**
938    * Returns the <c>Range</c> header on the request.
939    *
940    * <p>
941    * Request only part of an entity. Bytes are numbered from 0.
942    *
943    * <h5 class='figure'>Example:</h5>
944    * <p class='bcode w800'>
945    *    Range: bytes=500-999
946    * </p>
947    *
948    * @return The parsed <c>Range</c> header on the request, or <jk>null</jk> if not found.
949    */
950   public Range getRange() {
951      return Range.of(getString("Range"));
952   }
953
954   /**
955    * Returns the <c>Referer</c> header on the request.
956    *
957    * <p>
958    * This is the address of the previous web page from which a link to the currently requested page was followed.
959    *
960    * <h5 class='figure'>Example:</h5>
961    * <p class='bcode w800'>
962    *    Referer: http://en.wikipedia.org/wiki/Main_Page
963    * </p>
964    *
965    * @return The parsed <c>Referer</c> header on the request, or <jk>null</jk> if not found.
966    */
967   public Referer getReferer() {
968      return Referer.of(getString("Referer"));
969   }
970
971   /**
972    * Returns the <c>TE</c> header on the request.
973    *
974    * <p>
975    * The transfer encodings the user agent is willing to accept: the same values as for the response header field
976    * Transfer-Encoding can be used, plus the "trailers" value (related to the "chunked" transfer method) to notify the
977    * server it expects to receive additional fields in the trailer after the last, zero-sized, chunk.
978    *
979    * <h5 class='figure'>Example:</h5>
980    * <p class='bcode w800'>
981    *    TE: trailers, deflate
982    * </p>
983    *
984    * @return The parsed <c>TE</c> header on the request, or <jk>null</jk> if not found.
985    */
986   public TE getTE() {
987      return TE.of(getString("TE"));
988   }
989
990   /**
991    * Returns the <c>Time-Zone</c> header value on the request if there is one.
992    *
993    * <p>
994    * Example: <js>"GMT"</js>.
995    *
996    * @return The <c>Time-Zone</c> header value on the request, or <jk>null</jk> if not present.
997    */
998   public TimeZone getTimeZone() {
999      String tz = getString("Time-Zone");
1000      if (tz != null)
1001         return TimeZone.getTimeZone(tz);
1002      return null;
1003   }
1004
1005   /**
1006    * Returns the <c>User-Agent</c> header on the request.
1007    *
1008    * <p>
1009    * The user agent string of the user agent.
1010    *
1011    * <h5 class='figure'>Example:</h5>
1012    * <p class='bcode w800'>
1013    *    User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0
1014    * </p>
1015    *
1016    * @return The parsed <c>User-Agent</c> header on the request, or <jk>null</jk> if not found.
1017    */
1018   public UserAgent getUserAgent() {
1019      return UserAgent.of(getString("User-Agent"));
1020   }
1021
1022   /**
1023    * Returns the <c>Upgrade</c> header on the request.
1024    *
1025    * <p>
1026    * Ask the server to upgrade to another protocol.
1027    *
1028    * <h5 class='figure'>Example:</h5>
1029    * <p class='bcode w800'>
1030    *    Upgrade: HTTP/2.0, HTTPS/1.3, IRC/6.9, RTA/x11, websocket
1031    * </p>
1032    *
1033    * @return The parsed <c>Upgrade</c> header on the request, or <jk>null</jk> if not found.
1034    */
1035   public Upgrade getUpgrade() {
1036      return Upgrade.of(getString("Upgrade"));
1037   }
1038
1039   /**
1040    * Returns the <c>Via</c> header on the request.
1041    *
1042    * <p>
1043    * Informs the server of proxies through which the request was sent.
1044    *
1045    * <h5 class='figure'>Example:</h5>
1046    * <p class='bcode w800'>
1047    *    Via: 1.0 fred, 1.1 example.com (Apache/1.1)
1048    * </p>
1049    *
1050    * @return The parsed <c>Via</c> header on the request, or <jk>null</jk> if not found.
1051    */
1052   public Via getVia() {
1053      return Via.of(getString("Via"));
1054   }
1055
1056   /**
1057    * Returns the <c>Warning</c> header on the request.
1058    *
1059    * <p>
1060    * A general warning about possible problems with the entity body.
1061    *
1062    * <h5 class='figure'>Example:</h5>
1063    * <p class='bcode w800'>
1064    *    Warning: 199 Miscellaneous warning
1065    * </p>
1066    *
1067    * @return The parsed <c>Warning</c> header on the request, or <jk>null</jk> if not found.
1068    */
1069   public Warning getWarning() {
1070      return Warning.of(getString("Warning"));
1071   }
1072
1073   /**
1074    * Converts the headers to a readable string.
1075    *
1076    * @param sorted Sort the headers by name.
1077    * @return A JSON string containing the contents of the headers.
1078    */
1079   public String toString(boolean sorted) {
1080      Map<String,Object> m = null;
1081      if (sorted)
1082         m = new TreeMap<>();
1083      else
1084         m = new LinkedHashMap<>();
1085      for (Map.Entry<String,String[]> e : this.entrySet()) {
1086         String[] v = e.getValue();
1087         m.put(e.getKey(), v.length == 1 ? v[0] : v);
1088      }
1089      return SimpleJsonSerializer.DEFAULT.toString(m);
1090   }
1091
1092   @Override /* Object */
1093   public String toString() {
1094      return toString(false);
1095   }
1096
1097   //-----------------------------------------------------------------------------------------------------------------
1098   // Helper methods
1099   //-----------------------------------------------------------------------------------------------------------------
1100
1101   private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
1102      return req.getBeanSession().getClassMeta(type, args);
1103   }
1104
1105   private <T> ClassMeta<T> getClassMeta(Class<T> type) {
1106      return req.getBeanSession().getClassMeta(type);
1107   }
1108}