001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest;
018
019import static java.lang.Integer.*;
020import static java.util.Optional.*;
021import static org.apache.juneau.common.utils.IOUtils.*;
022import static org.apache.juneau.common.utils.ThrowableUtils.*;
023import static org.apache.juneau.httppart.HttpPartType.*;
024
025import java.io.*;
026import java.lang.reflect.*;
027import java.lang.reflect.Proxy;
028import java.net.*;
029import java.nio.charset.*;
030import java.text.*;
031import java.util.*;
032
033import org.apache.http.*;
034import org.apache.http.message.*;
035import org.apache.juneau.*;
036import org.apache.juneau.assertions.*;
037import org.apache.juneau.bean.swagger.*;
038import org.apache.juneau.bean.swagger.Swagger;
039import org.apache.juneau.common.utils.*;
040import org.apache.juneau.config.*;
041import org.apache.juneau.cp.*;
042import org.apache.juneau.http.annotation.*;
043import org.apache.juneau.http.annotation.Header;
044import org.apache.juneau.http.header.*;
045import org.apache.juneau.http.header.Date;
046import org.apache.juneau.http.response.*;
047import org.apache.juneau.httppart.*;
048import org.apache.juneau.httppart.bean.*;
049import org.apache.juneau.rest.annotation.*;
050import org.apache.juneau.rest.assertions.*;
051import org.apache.juneau.rest.guard.*;
052import org.apache.juneau.rest.httppart.*;
053import org.apache.juneau.rest.logger.*;
054import org.apache.juneau.rest.staticfile.*;
055import org.apache.juneau.rest.swagger.*;
056import org.apache.juneau.rest.util.*;
057import org.apache.juneau.svl.*;
058import org.apache.juneau.uon.*;
059
060import jakarta.servlet.*;
061import jakarta.servlet.http.*;
062
063/**
064 * Represents an HTTP request for a REST resource.
065 *
066 * <p>
067 *    The {@link RestRequest} object is an extension of the <l>HttpServletRequest</l> class
068 *    with various built-in convenience methods for use in building REST interfaces.
069 *    It can be accessed by passing it as a parameter on your REST Java method:
070 * </p>
071 *
072 * <p class='bjava'>
073 *    <ja>@RestPost</ja>(...)
074 *    <jk>public</jk> Object myMethod(RestRequest <jv>req</jv>) {...}
075 * </p>
076 *
077 * <p>
078 *    The primary methods on this class are:
079 * </p>
080 * <ul class='javatree'>
081 *    <li class='jc'>{@link RestRequest}
082 *    <ul class='spaced-list'>
083 *       <li>Methods for accessing the request content:
084 *       <ul class='javatreec'>
085 *          <li class='jm'>{@link RestRequest#getContent() getContent()}
086 *          <li class='jm'>{@link RestRequest#getInputStream() getInputStream()}
087 *          <li class='jm'>{@link RestRequest#getReader() getReader()}
088 *       </ul>
089 *       <li>Methods for accessing HTTP parts:
090 *       <ul class='javatreec'>
091 *          <li class='jm'>{@link RestRequest#containsFormParam(String) containsFormParam(String)}
092 *          <li class='jm'>{@link RestRequest#containsHeader(String) containsHeader(String)}
093 *          <li class='jm'>{@link RestRequest#containsQueryParam(String) containsQueryParam(String)}
094 *          <li class='jm'>{@link RestRequest#getHeader(Class) getHeader(Class)}
095 *          <li class='jm'>{@link RestRequest#getHeader(String) getHeader(String)}
096 *          <li class='jm'>{@link RestRequest#getHeaders() getHeaders()}
097 *          <li class='jm'>{@link RestRequest#getFormParam(Class) getFormParam(Class)}
098 *          <li class='jm'>{@link RestRequest#getFormParam(String) getFormParam(String)}
099 *          <li class='jm'>{@link RestRequest#getFormParams() getFormParams()}
100 *          <li class='jm'>{@link RestRequest#getPathParam(Class) getPathParam(Class)}
101 *          <li class='jm'>{@link RestRequest#getPathParam(String) getPathParam(String)}
102 *          <li class='jm'>{@link RestRequest#getPathParams() getPathParams()}
103 *          <li class='jm'>{@link RestRequest#getPathRemainder() getPathRemainder()}
104 *          <li class='jm'>{@link RestRequest#getQueryParam(Class) getQueryParam(Class)}
105 *          <li class='jm'>{@link RestRequest#getQueryParam(String) getQueryParam(String)}
106 *          <li class='jm'>{@link RestRequest#getQueryParams() getQueryParams()}
107 *          <li class='jm'>{@link RestRequest#getQueryString() getQueryString()}
108 *       </ul>
109 *       <li>Methods for localization:
110 *       <ul class='javatreec'>
111 *          <li class='jm'>{@link RestRequest#getLocale() getLocale()}
112 *          <li class='jm'>{@link RestRequest#getMessage(String,Object...) getMessage(String,Object...)}
113 *          <li class='jm'>{@link RestRequest#getMessages() getMessages()}
114 *          <li class='jm'>{@link RestRequest#getTimeZone() getTimeZone()}
115 *       </ul>
116 *       <li>Methods for accessing static files:
117 *       <ul class='javatreec'>
118 *          <li class='jm'>{@link RestRequest#getStaticFiles() getStaticFiles()}
119 *          <li class='jm'>{@link RestRequest#getVarResolverSession() getVarResolverSession()}
120 *       </ul>
121 *       <li>Methods for assertions:
122 *       <ul class='javatreec'>
123 *          <li class='jm'>{@link RestRequest#assertContent() assertContent()}
124 *          <li class='jm'>{@link RestRequest#assertCharset() assertCharset()}
125 *          <li class='jm'>{@link RestRequest#assertFormParam(String) assertFormParam(String)}
126 *          <li class='jm'>{@link RestRequest#assertHeader(String) assertHeader(String)}
127 *          <li class='jm'>{@link RestRequest#assertQueryParam(String) assertQueryParam(String)}
128 *          <li class='jm'>{@link RestRequest#assertRequestLine() assertRequestLine()}
129 *       </ul>
130 *       <li>Other:
131 *       <ul class='javatreec'>
132 *          <li class='jm'>{@link RestRequest#getAttribute(String) getAttribute(String)}
133 *          <li class='jm'>{@link RestRequest#getAttributes() getAttributes()}
134 *          <li class='jm'>{@link RestRequest#getAuthorityPath() getAuthorityPath()}
135 *          <li class='jm'>{@link RestRequest#getBeanSession() getBeanSession()}
136 *          <li class='jm'>{@link RestRequest#getCharset() getCharset()}
137 *          <li class='jm'>{@link RestRequest#getConfig() getConfig()}
138 *          <li class='jm'>{@link RestRequest#getContext() getContext()}
139 *          <li class='jm'>{@link RestRequest#getContextPath() getContextPath()}
140 *          <li class='jm'>{@link RestRequest#getHttpServletRequest() getHttpServletRequest()}
141 *          <li class='jm'>{@link RestRequest#getMethod() getMethod()}
142 *          <li class='jm'>{@link RestRequest#getOpContext() getOpContext()}
143 *          <li class='jm'>{@link RestRequest#getOperationSwagger() getOperationSwagger()}
144 *          <li class='jm'>{@link RestRequest#getPartParserSession() getPartParserSession()}
145 *          <li class='jm'>{@link RestRequest#getPartSerializerSession() getPartSerializerSession()}
146 *          <li class='jm'>{@link RestRequest#getPathInfo() getPathInfo()}
147 *          <li class='jm'>{@link RestRequest#getProtocolVersion() getProtocolVersion()}
148 *          <li class='jm'>{@link RestRequest#getRequest(Class) getRequest(Class)}
149 *          <li class='jm'>{@link RestRequest#getRequestLine() getRequestLine()}
150 *          <li class='jm'>{@link RestRequest#getRequestURI() getRequestURI()}
151 *          <li class='jm'>{@link RestRequest#getRequestURL() getRequestURL()}
152 *          <li class='jm'>{@link RestRequest#getServletPath() getServletPath()}
153 *          <li class='jm'>{@link RestRequest#getSession() getSession()}
154 *          <li class='jm'>{@link RestRequest#getSwagger() getSwagger()}
155 *          <li class='jm'>{@link RestRequest#getUriContext() getUriContext()}
156 *          <li class='jm'>{@link RestRequest#getUriResolver() getUriResolver()}
157 *          <li class='jm'>{@link RestRequest#isDebug() isDebug()}
158 *          <li class='jm'>{@link RestRequest#isPlainText() isPlainText()}
159 *          <li class='jm'>{@link RestRequest#isUserInRole(String) isUserInRole(String)}
160 *          <li class='jm'>{@link RestRequest#setAttribute(String,Object) setAttribute(String,Object)}
161 *          <li class='jm'>{@link RestRequest#setCharset(Charset) setCharset(Charset)}
162 *          <li class='jm'>{@link RestRequest#setDebug() setDebug()}
163 *          <li class='jm'>{@link RestRequest#setException(Throwable) setException(Throwable)}
164 *          <li class='jm'>{@link RestRequest#setNoTrace() setNoTrace()}
165 *       </ul>
166 *    </ul>
167 * </ul>
168 *
169 * <h5 class='section'>See Also:</h5><ul>
170
171 * </ul>
172 */
173@SuppressWarnings({ "unchecked", "unused" })
174public class RestRequest extends HttpServletRequestWrapper {
175
176   // Constructor initialized.
177   private HttpServletRequest inner;
178   private final RestContext context;
179   private final RestOpContext opContext;
180   private final RequestContent content;
181   private final BeanSession beanSession;
182   private final RequestQueryParams queryParams;
183   private final RequestPathParams pathParams;
184   private final RequestHeaders headers;
185   private final RequestAttributes attrs;
186   private final HttpPartParserSession partParserSession;
187   private final RestSession session;
188
189   // Lazy initialized.
190   private VarResolverSession varSession;
191   private RequestFormParams formParams;
192   private UriContext uriContext;
193   private String authorityPath;
194   private Config config;
195   private Swagger swagger;
196   private Charset charset;
197
198   /**
199    * Constructor.
200    */
201   RestRequest(RestOpContext opContext, RestSession session) throws Exception {
202      super(session.getRequest());
203      this.session = session;
204      this.opContext = opContext;
205
206      inner = session.getRequest();
207      context = session.getContext();
208
209      attrs = new RequestAttributes(this);
210
211      queryParams = new RequestQueryParams(this, session.getQueryParams(), true);
212
213      headers = new RequestHeaders(this, queryParams, false);
214
215      content = new RequestContent(this);
216
217      if (context.isAllowContentParam()) {
218         String b = queryParams.get("content").asString().orElse(null);
219         if (b != null) {
220            headers.set("Content-Type", UonSerializer.DEFAULT.getResponseContentType());
221            content.mediaType(MediaType.UON).parser(UonParser.DEFAULT).content(b.getBytes(UTF8));
222         }
223      }
224
225      pathParams = new RequestPathParams(session, this, true);
226
227      beanSession = opContext.getBeanContext().getSession();
228
229      partParserSession = opContext.getPartParser().getPartSession();
230
231      pathParams.parser(partParserSession);
232
233      queryParams
234         .addDefault(opContext.getDefaultRequestQueryData().getAll())
235         .parser(partParserSession);
236
237      headers
238         .addDefault(opContext.getDefaultRequestHeaders().getAll())
239         .addDefault(context.getDefaultRequestHeaders().getAll())
240         .parser(partParserSession);
241
242      content
243         .encoders(opContext.getEncoders())
244         .parsers(opContext.getParsers())
245         .maxInput(opContext.getMaxInput());
246
247      attrs
248         .addDefault(opContext.getDefaultRequestAttributes())
249         .addDefault(context.getDefaultRequestAttributes());
250
251      if (isDebug())
252         inner = CachingHttpServletRequest.wrap(inner);
253   }
254
255   //-----------------------------------------------------------------------------------------------------------------
256   // Request line.
257   //-----------------------------------------------------------------------------------------------------------------
258
259   /**
260    * Returns the request line of this request.
261    *
262    * @return The request line of this request.
263    */
264   public RequestLine getRequestLine() {
265      String x = inner.getProtocol();
266      int i = x.indexOf('/');
267      int j = x.indexOf('.', i);
268      ProtocolVersion pv = new ProtocolVersion(x.substring(0,i), parseInt(x.substring(i+1,j)), parseInt(x.substring(j+1)));
269      return new BasicRequestLine(inner.getMethod(), inner.getRequestURI(), pv);
270   }
271
272   /**
273    * Returns the protocol version from the request line of this request.
274    *
275    * @return The protocol version from the request line of this request.
276    */
277   public ProtocolVersion getProtocolVersion() {
278      return getRequestLine().getProtocolVersion();
279   }
280
281   //-----------------------------------------------------------------------------------------------------------------
282   // Assertions
283   //-----------------------------------------------------------------------------------------------------------------
284
285   /**
286    * Returns an assertion on the request line returned by {@link #getRequestLine()}.
287    *
288    * <h5 class='section'>Example:</h5>
289    * <p class='bjava'>
290    *    <jc>// Validates the request content contains "foo".</jc>
291    *    <jv>request</jv>
292    *       .assertRequestLine().protocol().minor().is(1);
293    * </p>
294    *
295    * @return A new assertion object.
296    */
297   public FluentRequestLineAssertion<RestRequest> assertRequestLine() {
298      return new FluentRequestLineAssertion<>(getRequestLine(), this);
299   }
300
301   /**
302    * Returns a fluent assertion for the request content.
303    *
304    * <h5 class='section'>Example:</h5>
305    * <p class='bjava'>
306    *    <jc>// Validates the request content contains "foo".</jc>
307    *    <jv>request</jv>
308    *       .assertContent().asString().is(<js>"foo"</js>);
309    * </p>
310    *
311    * @return A new fluent assertion on the content, never <jk>null</jk>.
312    */
313   public FluentRequestContentAssertion<RestRequest> assertContent() {
314      return new FluentRequestContentAssertion<>(getContent(), this);
315   }
316
317   /**
318    * Returns a fluent assertion for the specified header.
319    *
320    * <h5 class='section'>Example:</h5>
321    * <p class='bjava'>
322    *    <jc>// Validates the content type is JSON.</jc>
323    *    <jv>request</jv>
324    *       .assertHeader(<js>"Content-Type"</js>).asString().is(<js>"application/json"</js>);
325    * </p>
326    *
327    * @param name The header name.
328    * @return A new fluent assertion on the parameter, never <jk>null</jk>.
329    */
330   public FluentRequestHeaderAssertion<RestRequest> assertHeader(String name) {
331      return new FluentRequestHeaderAssertion<>(getHeaderParam(name), this);
332   }
333
334   /**
335    * Returns a fluent assertion for the specified query parameter.
336    *
337    * <h5 class='section'>Example:</h5>
338    * <p class='bjava'>
339    *    <jc>// Validates the content type is JSON.</jc>
340    *    <jv>request</jv>
341    *       .assertQueryParam(<js>"foo"</js>).asString().contains(<js>"bar"</js>);
342    * </p>
343    *
344    * @param name The query parameter name.
345    * @return A new fluent assertion on the parameter, never <jk>null</jk>.
346    */
347   public FluentRequestQueryParamAssertion<RestRequest> assertQueryParam(String name) {
348      return new FluentRequestQueryParamAssertion<>(getQueryParam(name), this);
349   }
350
351
352   /**
353    * Returns a fluent assertion for the specified form parameter.
354    *
355    * <h5 class='section'>Example:</h5>
356    * <p class='bjava'>
357    *    <jc>// Validates the content type is JSON.</jc>
358    *    <jv>request</jv>
359    *       .assertFormParam(<js>"foo"</js>).asString().contains(<js>"bar"</js>);
360    * </p>
361    *
362    * @param name The query parameter name.
363    * @return A new fluent assertion on the parameter, never <jk>null</jk>.
364    */
365   public FluentRequestFormParamAssertion<RestRequest> assertFormParam(String name) {
366      return new FluentRequestFormParamAssertion<>(getFormParam(name), this);
367   }
368
369   //-----------------------------------------------------------------------------------------------------------------
370   // Headers
371   //-----------------------------------------------------------------------------------------------------------------
372
373   /**
374    * Request headers.
375    *
376    * <p>
377    * Returns a {@link RequestHeaders} object that encapsulates access to HTTP headers on the request.
378    *
379    * <h5 class='section'>Example:</h5>
380    * <p class='bjava'>
381    *    <ja>@RestPost</ja>(...)
382    *    <jk>public</jk> Object myMethod(RestRequest <jv>req</jv>) {
383    *
384    *       <jc>// Get access to headers.</jc>
385    *       RequestHeaders <jv>headers</jv> = <jv>req</jv>.getRequestHeaders();
386    *
387    *       <jc>// Add a default value.</jc>
388    *       <jv>headers</jv>.addDefault(<js>"ETag"</js>, <jsf>DEFAULT_UUID</jsf>);
389    *
390    *    <jc>// Get a header value as a POJO.</jc>
391    *       UUID etag = <jv>headers</jv>.get(<js>"ETag"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>);
392    *
393    *       <jc>// Get a standard header.</jc>
394    *       Optional&lt;CacheControl&gt; = <jv>headers</jv>.getCacheControl();
395    *    }
396    * </p>
397    *
398    * <h5 class='section'>Notes:</h5><ul>
399    *    <li class='note'>
400    *       This object is modifiable.
401    *    <li class='note'>
402    *       Values are converted from strings using the registered part parser on the resource class.
403    *    <li class='note'>
404    *       The {@link RequestHeaders} object can also be passed as a parameter on the method.
405    *    <li class='note'>
406    *       The {@link Header @Header} annotation can be used to access individual header values.
407    * </ul>
408    *
409    * <h5 class='section'>See Also:</h5><ul>
410    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpParts">HTTP Parts</a>
411    * </ul>
412    *
413    * @return
414    *    The headers on this request.
415    *    <br>Never <jk>null</jk>.
416    */
417   public RequestHeaders getHeaders() {
418      return headers;
419   }
420
421   /**
422    * Returns the last header with a specified name of this message.
423    *
424    * <p>
425    * If there is more than one matching header in the message the last element of <c>getHeaders(String)</c> is returned.
426    * <br>If there is no matching header in the message, an empty request header object is returned.
427    *
428    * <h5 class='section'>Example:</h5>
429    * <p class='bjava'>
430    *    <jc>// Gets a header and throws a BadRequest if it doesn't exist.</jc>
431    *    <jv>request</jv>
432    *       .getHeader(<js>"Foo"</js>)
433    *       .assertValue().exists()
434    *       .get();
435    * </p>
436    *
437    * @param name The header name.
438    * @return The request header object, never <jk>null</jk>.
439    */
440   public RequestHeader getHeaderParam(String name) {
441      return headers.getLast(name);
442   }
443
444   /**
445    * Returns <jk>true</jk> if this request contains the specified header.
446    *
447    * @param name The header name.
448    * @return <jk>true</jk> if this request contains the specified header.
449    */
450   public boolean containsHeader(String name) {
451      return headers.contains(name);
452   }
453
454   /**
455    * Provides the ability to perform fluent-style assertions on the response character encoding.
456    *
457    * <h5 class='section'>Examples:</h5>
458    * <p class='bjava'>
459    *    <jc>// Validates that the response content charset is UTF-8.</jc>
460    *    <jv>request</jv>
461    *       .assertCharset().is(<js>"utf-8"</js>);
462    * </p>
463    *
464    * @return A new fluent assertion object.
465    * @throws BasicHttpException If REST call failed.
466    */
467   public FluentStringAssertion<RestRequest> assertCharset() {
468      return new FluentStringAssertion<>(getCharset().name(), this);
469   }
470
471   /**
472    * Sets the charset to expect on the request content.
473    *
474    * @param value The new value to use for the request content.
475    */
476   public void setCharset(Charset value) {
477      this.charset = value;
478   }
479
480   /**
481    * Returns the charset specified on the <c>Content-Type</c> header, or <js>"UTF-8"</js> if not specified.
482    *
483    * @return The charset to use to decode the request content.
484    */
485   public Charset getCharset() {
486      if (charset == null) {
487         // Determine charset
488         // NOTE:  Don't use super.getCharacterEncoding() because the spec is implemented inconsistently.
489         // Jetty returns the default charset instead of null if the character is not specified on the request.
490         String h = getHeaderParam("Content-Type").orElse(null);
491         if (h != null) {
492            int i = h.indexOf(";charset=");
493            if (i > 0)
494               charset = Charset.forName(h.substring(i+9).trim());
495         }
496         if (charset == null)
497            charset = opContext.getDefaultCharset();
498         if (charset == null)
499            charset = Charset.forName("UTF-8");
500      }
501      return charset;
502   }
503
504   /**
505    * Returns the preferred Locale that the client will accept content in, based on the Accept-Language header.
506    *
507    * <p>
508    * If the client request doesn't provide an <c>Accept-Language</c> header, this method returns the default locale for the server.
509    *
510    * @return The preferred Locale that the client will accept content in.  Never <jk>null</jk>.
511    */
512   @Override
513   public Locale getLocale() {
514      Locale best = inner.getLocale();
515      String h = headers.get("Accept-Language").asString().orElse(null);
516      if (h != null) {
517         StringRanges sr = StringRanges.of(h);
518         float qValue = 0;
519         for (StringRange r : sr.toList()) {
520            if (r.getQValue() > qValue) {
521               best = toLocale(r.getName());
522               qValue = r.getQValue();
523            }
524         }
525      }
526      return best;
527   }
528
529   //-----------------------------------------------------------------------------------------------------------------
530   // Standard headers.
531   //-----------------------------------------------------------------------------------------------------------------
532
533   /**
534    * Returns the request header of the specified type.
535    *
536    * <p>
537    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.Header} annotation
538    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
539    *
540    * <p>
541    * Typically any of the following:
542    * <ul class='javatreec'>
543    *    <li class='jc'>{@link Accept}
544    *    <li class='jc'>{@link AcceptCharset}
545    *    <li class='jc'>{@link AcceptEncoding}
546    *    <li class='jc'>{@link AcceptLanguage}
547    *    <li class='jc'>{@link AcceptRanges}
548    *    <li class='jc'>{@link Authorization}
549    *    <li class='jc'>{@link CacheControl}
550    *    <li class='jc'>{@link ClientVersion}
551    *    <li class='jc'>{@link Connection}
552    *    <li class='jc'>{@link ContentDisposition}
553    *    <li class='jc'>{@link ContentEncoding}
554    *    <li class='jc'>{@link ContentLength}
555    *    <li class='jc'>{@link ContentType}
556    *    <li class='jc'>{@link Date}
557    *    <li class='jc'>{@link Debug}
558    *    <li class='jc'>{@link Expect}
559    *    <li class='jc'>{@link Forwarded}
560    *    <li class='jc'>{@link From}
561    *    <li class='jc'>{@link Host}
562    *    <li class='jc'>{@link IfMatch}
563    *    <li class='jc'>{@link IfModifiedSince}
564    *    <li class='jc'>{@link IfNoneMatch}
565    *    <li class='jc'>{@link IfRange}
566    *    <li class='jc'>{@link IfUnmodifiedSince}
567    *    <li class='jc'>{@link MaxForwards}
568    *    <li class='jc'>{@link NoTrace}
569    *    <li class='jc'>{@link Origin}
570    *    <li class='jc'>{@link Pragma}
571    *    <li class='jc'>{@link ProxyAuthorization}
572    *    <li class='jc'>{@link Range}
573    *    <li class='jc'>{@link Referer}
574    *    <li class='jc'>{@link TE}
575    *    <li class='jc'>{@link Thrown}
576    *    <li class='jc'>{@link Upgrade}
577    *    <li class='jc'>{@link UserAgent}
578    *    <li class='jc'>{@link Warning}
579    * </ul>
580    *
581    * @param <T> The bean type to create.
582    * @param type The bean type to create.
583    * @return The parsed header on the request, never <jk>null</jk>.
584    */
585   public <T> Optional<T> getHeader(Class<T> type) {
586      return headers.get(type);
587   }
588
589   /**
590    * Returns the <c>Time-Zone</c> header value on the request if there is one.
591    *
592    * <p>
593    * Example: <js>"GMT"</js>.
594    *
595    * @return The parsed header on the request, never <jk>null</jk>.
596    */
597   public Optional<TimeZone> getTimeZone() {
598      String tz = headers.get("Time-Zone").asString().orElse(null);
599      if (tz != null)
600         return Utils.opt(TimeZone.getTimeZone(tz));
601      return Optional.empty();
602   }
603
604   //-----------------------------------------------------------------------------------------------------------------
605   // Attributes
606   //-----------------------------------------------------------------------------------------------------------------
607
608   /**
609    * Request attributes.
610    *
611    * <p>
612    * Returns a {@link RequestAttributes} object that encapsulates access to attributes on the request.
613    *
614    * <h5 class='section'>Example:</h5>
615    * <p class='bjava'>
616    *    <ja>@RestPost</ja>(...)
617    *    <jk>public</jk> Object myMethod(RestRequest <jv>req</jv>) {
618    *
619    *       <jc>// Get access to attributes.</jc>
620    *       RequestAttributes <jv>attributes</jv> = <jv>req</jv>.getAttributes();
621    *
622    *    <jc>// Get a header value as a POJO.</jc>
623    *       UUID <jv>etag</jv> = <jv>attributes</jv>.get(<js>"ETag"</js>, UUID.<jk>class</jk>);
624    *    }
625    * </p>
626    *
627    * <h5 class='section'>Notes:</h5><ul>
628    *    <li class='note'>
629    *       This object is modifiable.
630    *    <li class='note'>
631    *       Values are converted from strings using the registered part parser on the resource class.
632    *    <li class='note'>
633    *       The {@link RequestAttributes} object can also be passed as a parameter on the method.
634    *    <li class='note'>
635    *       The {@link Attr @Attr} annotation can be used to access individual attribute values.
636    * </ul>
637    *
638    * <h5 class='section'>See Also:</h5><ul>
639    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpParts">HTTP Parts</a>
640    * </ul>
641    *
642    * @return
643    *    The headers on this request.
644    *    <br>Never <jk>null</jk>.
645    */
646   public RequestAttributes getAttributes() {
647      return attrs;
648   }
649
650   /**
651    * Returns the request attribute with the specified name.
652    *
653    * @param name The attribute name.
654    * @return The attribute value, never <jk>null</jk>.
655    */
656   @Override
657   public RequestAttribute getAttribute(String name) {
658      return attrs.get(name);
659   }
660
661   /**
662    * Sets a request attribute.
663    *
664    * @param name The attribute name.
665    * @param value The attribute value.
666    */
667   @Override
668   public void setAttribute(String name, Object value) {
669      attrs.set(name, value);
670   }
671
672   //-----------------------------------------------------------------------------------------------------------------
673   // Query parameters
674   //-----------------------------------------------------------------------------------------------------------------
675
676   /**
677    * Query parameters.
678    *
679    * <p>
680    * Returns a {@link RequestQueryParams} object that encapsulates access to URL GET parameters.
681    *
682    * <p>
683    * Similar to {@link HttpServletRequest#getParameterMap()} but only looks for query parameters in the URL and not form posts.
684    *
685    * <h5 class='section'>Example:</h5>
686    * <p class='bjava'>
687    *    <ja>@RestGet</ja>(...)
688    *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>) {
689    *
690    *       <jc>// Get access to query parameters on the URL.</jc>
691    *       RequestQueryParams <jv>query</jv> = <jv>req</jv>.getQuery();
692    *
693    *       <jc>// Get query parameters converted to various types.</jc>
694    *       <jk>int</jk> <jv>p1/</jv> = <jv>query</jv>.getInteger(<js>"p1"</js>).orElse(<jk>null</jk>);
695    *       String <jv>p2</jv> = <jv>query</jv>.getString(<js>"p2"</js>).orElse(<jk>null</jk>);
696    *       UUID <jv>p3</jv> = <jv>query</jv>.get(<js>"p3"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>);
697    *    }
698    * </p>
699    *
700    * <h5 class='section'>Notes:</h5><ul>
701    *    <li class='note'>
702    *       This object is modifiable.
703    * </ul>
704    *
705    * <h5 class='section'>See Also:</h5><ul>
706    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpParts">HTTP Parts</a>
707    * </ul>
708    *
709    * @return
710    *    The query parameters as a modifiable map.
711    *    <br>Never <jk>null</jk>.
712    */
713   public RequestQueryParams getQueryParams() {
714      return queryParams;
715   }
716
717   /**
718    * Shortcut for calling <c>getRequestQuery().getLast(<jv>name</jv>)</c>.
719    *
720    * @param name The query parameter name.
721    * @return The query parameter, never <jk>null</jk>.
722    */
723   public RequestQueryParam getQueryParam(String name) {
724      return queryParams.get(name);
725   }
726
727   /**
728    * Returns the request query parameter of the specified type.
729    *
730    * <p>
731    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.Query} annotation
732    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
733    *
734    * @param <T> The bean type to create.
735    * @param type The bean type to create.
736    * @return The parsed query parameter on the request, never <jk>null</jk>.
737    */
738   public <T> Optional<T> getQueryParam(Class<T> type) {
739      return queryParams.get(type);
740   }
741
742   /**
743    * Returns <jk>true</jk> if this request contains the specified header.
744    *
745    * @param name The header name.
746    * @return <jk>true</jk> if this request contains the specified header.
747    */
748   public boolean containsQueryParam(String name) {
749      return queryParams.contains(name);
750   }
751
752
753   //-----------------------------------------------------------------------------------------------------------------
754   // Form data parameters
755   //-----------------------------------------------------------------------------------------------------------------
756
757   /**
758    * Form-data.
759    *
760    * <p>
761    * Returns a {@link RequestFormParams} object that encapsulates access to form post parameters.
762    *
763    * <p>
764    * Similar to {@link HttpServletRequest#getParameterMap()}, but only looks for form data in the HTTP content.
765    *
766    * <h5 class='section'>Example:</h5>
767    * <p class='bjava'>
768    *    <ja>@RestPost</ja>(...)
769    *    <jk>public void</jk> doPost(RestRequest <jv>req</jv>) {
770    *
771    *       <jc>// Get access to parsed form data parameters.</jc>
772    *       RequestFormParams <jv>formParams</jv> = <jv>req</jv>.getFormParams();
773    *
774    *       <jc>// Get form data parameters converted to various types.</jc>
775    *       <jk>int</jk> <jv>p1</jv> = <jv>formParams</jv>.get(<js>"p1"</js>).asInteger().orElse(0);
776    *       String <jv>p2</jv> = <jv>formParams</jv>.get(<js>"p2"</js>).asString().orElse(<jk>null</jk>);
777    *       UUID <jv>p3</jv> = <jv>formParams</jv>.get(<js>"p3"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>);
778    *    }
779    * </p>
780    *
781    * <h5 class='section'>Notes:</h5><ul>
782    *    <li class='note'>
783    *       This object is modifiable.
784    *    <li class='note'>
785    *       Values are converted from strings using the registered part parser on the resource class.
786    *    <li class='note'>
787    *       The {@link RequestFormParams} object can also be passed as a parameter on the method.
788    *    <li class='note'>
789    *       The {@link FormData @FormDAta} annotation can be used to access individual form data parameter values.
790    * </ul>
791    *
792    * <h5 class='section'>See Also:</h5><ul>
793    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpParts">HTTP Parts</a>
794    * </ul>
795    *
796    * @return
797    *    The URL-encoded form data from the request.
798    *    <br>Never <jk>null</jk>.
799    * @throws InternalServerError If query parameters could not be parsed.
800    * @see org.apache.juneau.http.annotation.FormData
801    */
802   public RequestFormParams getFormParams() throws InternalServerError {
803      try {
804         if (formParams == null)
805            formParams = new RequestFormParams(this, true).parser(partParserSession);
806         formParams.addDefault(opContext.getDefaultRequestFormData().getAll());
807         return formParams;
808      } catch (Exception e) {
809         throw new InternalServerError(e);
810      }
811   }
812
813   /**
814    * Shortcut for calling <c>getFormData().getString(name)</c>.
815    *
816    * @param name The form data parameter name.
817    * @return The form data parameter value, or <jk>null</jk> if not found.
818    */
819   public RequestFormParam getFormParam(String name) {
820      return getFormParams().get(name);
821   }
822
823   /**
824    * Returns the request form-data parameter of the specified type.
825    *
826    * <p>
827    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.FormData} annotation
828    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
829    *
830    * @param <T> The bean type to create.
831    * @param type The bean type to create.
832    * @return The parsed form-data parameter on the request, never <jk>null</jk>.
833    */
834   public <T> Optional<T> getFormParam(Class<T> type) {
835      return getFormParams().get(type);
836   }
837
838   /**
839    * Returns <jk>true</jk> if this request contains the specified header.
840    *
841    * @param name The header name.
842    * @return <jk>true</jk> if this request contains the specified header.
843    */
844   public boolean containsFormParam(String name) {
845      return getFormParams().contains(name);
846   }
847
848   //-----------------------------------------------------------------------------------------------------------------
849   // Path parameters
850   //-----------------------------------------------------------------------------------------------------------------
851
852   /**
853    * Path parameters.
854    *
855    * <p>
856    * Returns a {@link RequestPathParams} object that encapsulates access to URL path parameters.
857    *
858    * <h5 class='section'>Example:</h5>
859    * <p class='bjava'>
860    *    <ja>@RestGet</ja>(<js>"/{foo}/{bar}/{baz}/*"</js>)
861    *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>) {
862    *
863    *       <jc>// Get access to path data.</jc>
864    *       RequestPathParams <jv>pathParams</jv> = <jv>req</jv>.getPathParams();
865    *
866    *       <jc>// Example URL:  /123/qux/true/quux</jc>
867    *
868    *       <jk>int</jk> <jv>foo</jv> = <jv>pathParams</jv>.get(<js>"foo"</js>).asInteger().orElse(-1);  <jc>// =123</jc>
869    *       String <jv>bar</jv> = <jv>pathParams</jv>.get(<js>"bar"</js>).orElse(<jk>null</jk>);  <jc>// =qux</jc>
870    *       <jk>boolean</jk> <jv>baz</jv> = <jv>pathParams</jv>.get(<js>"baz"</js>).asBoolean().orElse(<jk>false</jk>);  <jc>// =true</jc>
871    *       String <jv>remainder</jv> = <jv>pathParams</jv>.getRemainder().orElse(<jk>null</jk>);  <jc>// =quux</jc>
872    *    }
873    * </p>
874    *
875    * <h5 class='section'>Notes:</h5><ul>
876    *    <li class='note'>
877    *       This object is modifiable.
878    * </ul>
879    *
880    * @return
881    *    The path parameters.
882    *    <br>Never <jk>null</jk>.
883    */
884   public RequestPathParams getPathParams() {
885      return pathParams;
886   }
887
888   /**
889    * Shortcut for calling <c>getPathParams().get(<jv>name</jv>)</c>.
890    *
891    * @param name The path parameter name.
892    * @return The path parameter, never <jk>null</jk>.
893    */
894   public RequestPathParam getPathParam(String name) {
895      return pathParams.get(name);
896   }
897
898   /**
899    * Returns the request path parameter of the specified type.
900    *
901    * <p>
902    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.Path} annotation
903    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
904    *
905    * @param <T> The bean type to create.
906    * @param type The bean type to create.
907    * @return The parsed form-data parameter on the request, never <jk>null</jk>.
908    */
909   public <T> Optional<T> getPathParam(Class<T> type) {
910      return pathParams.get(type);
911   }
912
913   /**
914    * Shortcut for calling <c>getPathParams().getRemainder()</c>.
915    *
916    * @return The path remainder value, never <jk>null</jk>.
917    */
918   public RequestPathParam getPathRemainder() {
919      return pathParams.getRemainder();
920   }
921
922   //-----------------------------------------------------------------------------------------------------------------
923   // Content methods
924   //-----------------------------------------------------------------------------------------------------------------
925
926   /**
927    * Request content.
928    *
929    * <p>
930    * Returns a {@link RequestContent} object that encapsulates access to the HTTP request content.
931    *
932    * <h5 class='section'>Example:</h5>
933    * <p class='bjava'>
934    *    <ja>@RestPost</ja>(...)
935    *    <jk>public void</jk> doPost(RestRequest <jv>req</jv>) {
936    *
937    *       <jc>// Convert content to a linked list of Person objects.</jc>
938    *       List&lt;Person&gt; <jv>list</jv> = <jv>req</jv>.getContent().as(LinkedList.<jk>class</jk>, Person.<jk>class</jk>);
939    *       ..
940    *    }
941    * </p>
942    *
943    * <h5 class='section'>Notes:</h5><ul>
944    *    <li class='note'>
945    *       The {@link RequestContent} object can also be passed as a parameter on the method.
946    *    <li class='note'>
947    *       The {@link Content @Content} annotation can be used to access the content as well.
948    * </ul>
949    *
950    * <h5 class='section'>See Also:</h5><ul>
951    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpParts">HTTP Parts</a>
952    * </ul>
953    *
954    * @return
955    *    The content of this HTTP request.
956    *    <br>Never <jk>null</jk>.
957    */
958   public RequestContent getContent() {
959      return content;
960   }
961
962   /**
963    * Returns the HTTP content content as a {@link Reader}.
964    *
965    * <p>
966    * If {@code allowHeaderParams} init parameter is true, then first looks for {@code &content=xxx} in the URL query
967    * string.
968    *
969    * <p>
970    * Automatically handles GZipped input streams.
971    *
972    * <p>
973    * This method is equivalent to calling <c>getContent().getReader()</c>.
974    *
975    * @return The HTTP content content as a {@link Reader}.
976    * @throws IOException If content could not be read.
977    */
978   @Override
979   public BufferedReader getReader() throws IOException {
980      return getContent().getReader();
981   }
982
983   /**
984    * Returns the HTTP content content as an {@link InputStream}.
985    *
986    * <p>
987    * Automatically handles GZipped input streams.
988    *
989    * <p>
990    * This method is equivalent to calling <c>getContent().getInputStream()</c>.
991    *
992    * @return The negotiated input stream.
993    * @throws IOException If any error occurred while trying to get the input stream or wrap it in the GZIP wrapper.
994    */
995   @Override
996   public ServletInputStream getInputStream() throws IOException {
997      return getContent().getInputStream();
998   }
999
1000   //-----------------------------------------------------------------------------------------------------------------
1001   // URI-related methods
1002   //-----------------------------------------------------------------------------------------------------------------
1003
1004   /**
1005    * Returns the portion of the request URI that indicates the context of the request.
1006    *
1007    * <p>The context path always comes first in a request URI.
1008    * The path starts with a <js>"/"</js> character but does not end with a <js>"/"</js> character.
1009    * For servlets in the default (root) context, this method returns <js>""</js>.
1010    * The container does not decode this string.
1011    *
1012    * @return The context path, never <jk>null</jk>.
1013    * @see HttpServletRequest#getContextPath()
1014    */
1015   @Override
1016   public String getContextPath() {
1017      String cp = context.getUriContext();
1018      return cp == null ? inner.getContextPath() : cp;
1019   }
1020
1021   /**
1022    * Returns the URI authority portion of the request.
1023    *
1024    * @return The URI authority portion of the request.
1025    */
1026   public String getAuthorityPath() {
1027      if (authorityPath == null)
1028         authorityPath = context.getUriAuthority();
1029      if (authorityPath == null) {
1030         String scheme = inner.getScheme();
1031         int port = inner.getServerPort();
1032         StringBuilder sb = new StringBuilder(inner.getScheme()).append("://").append(inner.getServerName());
1033         if (! (port == 80 && "http".equals(scheme) || port == 443 && "https".equals(scheme)))
1034            sb.append(':').append(port);
1035         authorityPath = sb.toString();
1036      }
1037      return authorityPath;
1038   }
1039
1040   /**
1041    * Returns the part of this request's URL that calls the servlet.
1042    *
1043    * <p>
1044    * This path starts with a <js>"/"</js> character and includes either the servlet name or a path to the servlet,
1045    * but does not include any extra path information or a query string.
1046    *
1047    * @return The servlet path, never <jk>null</jk>.
1048    * @see HttpServletRequest#getServletPath()
1049    */
1050   @Override
1051   public String getServletPath() {
1052      String cp = context.getUriContext();
1053      String sp = inner.getServletPath();
1054      return cp == null || ! sp.startsWith(cp) ? sp : sp.substring(cp.length());
1055   }
1056
1057   /**
1058    * Returns the URI context of the request.
1059    *
1060    * <p>
1061    * The URI context contains all the information about the URI of the request, such as the servlet URI, context
1062    * path, etc...
1063    *
1064    * @return The URI context of the request.
1065    */
1066   public UriContext getUriContext() {
1067      if (uriContext == null)
1068         uriContext = UriContext.of(getAuthorityPath(), getContextPath(), getServletPath(), StringUtils.urlEncodePath(inner.getPathInfo()));
1069      return uriContext;
1070   }
1071
1072   /**
1073    * Returns a URI resolver that can be used to convert URIs to absolute or root-relative form.
1074    *
1075    * @param resolution The URI resolution rule.
1076    * @param relativity The relative URI relativity rule.
1077    * @return The URI resolver for this request.
1078    */
1079   public UriResolver getUriResolver(UriResolution resolution, UriRelativity relativity) {
1080      return UriResolver.of(resolution, relativity, getUriContext());
1081   }
1082
1083   /**
1084    * Shortcut for calling {@link #getUriResolver()} using {@link UriResolution#ROOT_RELATIVE} and
1085    * {@link UriRelativity#RESOURCE}
1086    *
1087    * @return The URI resolver for this request.
1088    */
1089   public UriResolver getUriResolver() {
1090      return UriResolver.of(context.getUriResolution(), context.getUriRelativity(), getUriContext());
1091   }
1092
1093   /**
1094    * Returns the URI for this request.
1095    *
1096    * <p>
1097    * Similar to {@link #getRequestURI()} but returns the value as a {@link URI}.
1098    * It also gives you the capability to override the query parameters (e.g. add new query parameters to the existing
1099    * URI).
1100    *
1101    * @param includeQuery If <jk>true</jk> include the query parameters on the request.
1102    * @param addQueryParams Augment the request URI with the specified query parameters.
1103    * @return A new URI.
1104    */
1105   public URI getUri(boolean includeQuery, Map<String,Object> addQueryParams) {
1106      String uri = inner.getRequestURI();
1107      if (includeQuery || addQueryParams != null) {
1108         StringBuilder sb = new StringBuilder(uri);
1109         RequestQueryParams rq = this.queryParams.copy();
1110         if (addQueryParams != null)
1111            for (Map.Entry<String,?> e : addQueryParams.entrySet())
1112               rq.set(e.getKey(), e.getValue());
1113         if (! rq.isEmpty())
1114            sb.append('?').append(rq.asQueryString());
1115         uri = sb.toString();
1116      }
1117      try {
1118         return new URI(uri);
1119      } catch (URISyntaxException e) {
1120         // Shouldn't happen.
1121         throw asRuntimeException(e);
1122      }
1123   }
1124
1125   //-----------------------------------------------------------------------------------------------------------------
1126   // Labels
1127   //-----------------------------------------------------------------------------------------------------------------
1128
1129   /**
1130    * Returns the localized swagger associated with the resource.
1131    *
1132    * <p>
1133    * A shortcut for calling <c>getInfoProvider().getSwagger(request);</c>
1134    *
1135    * <h5 class='section'>Example:</h5>
1136    * <p class='bjava'>
1137    *    <ja>@RestGet</ja>
1138    *    <jk>public</jk> List&lt;Tag&gt; swaggerTags(RestRequest <jv>req</jv>) {
1139    *       <jk>return</jk> <jv>req</jv>.getSwagger().getTags();
1140    *    }
1141    * </p>
1142    *
1143    * <h5 class='section'>Notes:</h5><ul>
1144    *    <li class='note'>
1145    *       The {@link Swagger} object can also be passed as a parameter on the method.
1146    * </ul>
1147    *
1148    * <h5 class='section'>See Also:</h5><ul>
1149    *    <li class='jm'>{@link RestContext.Builder#swaggerProvider(Class)}
1150    *    <li class='jm'>{@link RestContext.Builder#swaggerProvider(SwaggerProvider)}
1151    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a>
1152    * </ul>
1153    *
1154    * @return
1155    *    The swagger associated with the resource.
1156    *    <br>Never <jk>null</jk>.
1157    */
1158   public Optional<Swagger> getSwagger() {
1159      return context.getSwagger(getLocale());
1160   }
1161
1162   /**
1163    * Returns the swagger for the Java method invoked.
1164    *
1165    * @return The swagger for the Java method as an {@link Optional}.  Never <jk>null</jk>.
1166    */
1167   public Optional<Operation> getOperationSwagger() {
1168
1169      Optional<Swagger> swagger = getSwagger();
1170      if (! swagger.isPresent())
1171         return Optional.empty();
1172
1173      return ofNullable(swagger.get().getOperation(opContext.getPathPattern(), getMethod().toLowerCase()));
1174   }
1175
1176   //-----------------------------------------------------------------------------------------------------------------
1177   // Other methods
1178   //-----------------------------------------------------------------------------------------------------------------
1179
1180   /**
1181    * Returns the part serializer associated with this request.
1182    *
1183    * @return The part serializer associated with this request.
1184    */
1185   public HttpPartParserSession getPartParserSession() {
1186      return partParserSession;
1187   }
1188
1189   /**
1190    * Returns the HTTP method of this request.
1191    *
1192    * <p>
1193    * If <c>allowHeaderParams</c> init parameter is <jk>true</jk>, then first looks for
1194    * <c>&amp;method=xxx</c> in the URL query string.
1195    *
1196    * @return The HTTP method of this request.
1197    */
1198   @Override
1199   public String getMethod() {
1200      return session.getMethod();
1201   }
1202
1203   /**
1204    * Returns <jk>true</jk> if <c>&amp;plainText=true</c> was specified as a URL parameter.
1205    *
1206    * <p>
1207    * This indicates that the <c>Content-Type</c> of the output should always be set to <js>"text/plain"</js>
1208    * to make it easy to render in a browser.
1209    *
1210    * <p>
1211    * This feature is useful for debugging.
1212    *
1213    * @return <jk>true</jk> if {@code &amp;plainText=true} was specified as a URL parameter
1214    */
1215   public boolean isPlainText() {
1216      return "true".equals(queryParams.get("plainText").asString().orElse("false"));
1217   }
1218
1219   /**
1220    * Returns the resource bundle for the request locale.
1221    *
1222    * <h5 class='section'>Example:</h5>
1223    * <p class='bjava'>
1224    *    <ja>@RestGet</ja>
1225    *    <jk>public</jk> String hello(RestRequest <jv>req</jv>, <ja>@Query</ja>(<js>"user"</js>) String <jv>user</jv>) {
1226    *
1227    *       <jc>// Return a localized message.</jc>
1228    *       <jk>return</jk> <jv>req</jv>.getMessages().getString(<js>"hello.message"</js>, <jv>user</jv>);
1229    *    }
1230    * </p>
1231    *
1232    * <h5 class='section'>Notes:</h5><ul>
1233    *    <li class='note'>
1234    *       The {@link Messages} object can also be passed as a parameter on the method.
1235    * </ul>
1236    *
1237    * <h5 class='section'>See Also:</h5><ul>
1238    *    <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMessage(String,Object...)}
1239    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/LocalizedMessages">Localized Messages</a>
1240    * </ul>
1241    *
1242    * @return
1243    *    The resource bundle.
1244    *    <br>Never <jk>null</jk>.
1245    */
1246   public Messages getMessages() {
1247      return context.getMessages().forLocale(getLocale());
1248   }
1249
1250   /**
1251    * Shortcut method for calling {@link RestRequest#getMessages()} and {@link Messages#getString(String,Object...)}.
1252    *
1253    * @param key The message key.
1254    * @param args Optional {@link MessageFormat}-style arguments.
1255    * @return The localized message.
1256    */
1257   public String getMessage(String key, Object...args) {
1258      return getMessages().getString(key, args);
1259   }
1260
1261   /**
1262    * Returns the resource context handling the request.
1263    *
1264    * <p>
1265    * Can be used to access servlet-init parameters or annotations during requests, such as in calls to
1266    * {@link RestGuard#guard(RestRequest, RestResponse)}..
1267    *
1268    * @return The resource context handling the request.
1269    */
1270   public RestContext getContext() {
1271      return context;
1272   }
1273
1274   /**
1275    * Returns access to the inner {@link RestOpContext} of this method.
1276    *
1277    * @return The {@link RestOpContext} of this method.  May be <jk>null</jk> if method has not yet been found.
1278    */
1279   public RestOpContext getOpContext() {
1280      return opContext;
1281   }
1282
1283   /**
1284    * Returns the {@link BeanSession} associated with this request.
1285    *
1286    * @return The request bean session.
1287    */
1288   public BeanSession getBeanSession() {
1289      return beanSession;
1290   }
1291
1292   /**
1293    * Returns <jk>true</jk> if debug mode is enabled.
1294    *
1295    * Debug mode is enabled by simply adding <js>"?debug=true"</js> to the query string or adding a <c>Debug: true</c> header on the request.
1296    *
1297    * @return <jk>true</jk> if debug mode is enabled.
1298    */
1299   public boolean isDebug() {
1300      return getAttribute("Debug").as(Boolean.class).orElse(false);
1301   }
1302
1303   /**
1304    * Sets the <js>"Exception"</js> attribute to the specified throwable.
1305    *
1306    * <p>
1307    * This exception is used by {@link CallLogger} for logging purposes.
1308    *
1309    * @param t The attribute value.
1310    * @return This object.
1311    */
1312   public RestRequest setException(Throwable t) {
1313      setAttribute("Exception", t);
1314      return this;
1315   }
1316
1317   /**
1318    * Sets the <js>"NoTrace"</js> attribute to the specified boolean.
1319    *
1320    * <p>
1321    * This flag is used by {@link CallLogger} and tells it not to log the current request.
1322    *
1323    * @param b The attribute value.
1324    * @return This object.
1325    */
1326   public RestRequest setNoTrace(Boolean b) {
1327      setAttribute("NoTrace", b);
1328      return this;
1329   }
1330
1331   /**
1332    * Shortcut for calling <c>setNoTrace(<jk>true</jk>)</c>.
1333    *
1334    * @return This object.
1335    */
1336   public RestRequest setNoTrace() {
1337      return setNoTrace(true);
1338   }
1339
1340   /**
1341    * Sets the <js>"Debug"</js> attribute to the specified boolean.
1342    *
1343    * <p>
1344    * This flag is used by {@link CallLogger} to help determine how a request should be logged.
1345    *
1346    * @param b The attribute value.
1347    * @return This object.
1348    * @throws IOException If content could not be cached.
1349    */
1350   public RestRequest setDebug(Boolean b) throws IOException {
1351      setAttribute("Debug", b);
1352      if (b)
1353         inner = CachingHttpServletRequest.wrap(inner);
1354      return this;
1355   }
1356
1357   /**
1358    * Shortcut for calling <c>setDebug(<jk>true</jk>)</c>.
1359    *
1360    * @return This object.
1361    * @throws IOException If content could not be cached.
1362    */
1363   public RestRequest setDebug() throws IOException {
1364      return setDebug(true);
1365   }
1366
1367   /**
1368    * Request-level variable resolver session.
1369    *
1370    * <p>
1371    * Used to resolve SVL variables in text.
1372    *
1373    * <h5 class='section'>Example:</h5>
1374    * <p class='bjava'>
1375    *    <ja>@RestGet</ja>
1376    *    <jk>public</jk> String hello(RestRequest <jv>req</jv>) {
1377    *
1378    *       <jc>// Get var resolver session.</jc>
1379    *       VarResolverSession <jv>session</jv> = getVarResolverSession();
1380    *
1381    *       <jc>// Use it to construct a customized message from a query parameter.</jc>
1382    *       <jk>return</jk> <jv>session</jv>.resolve(<js>"Hello $RQ{user}!"</js>);
1383    *    }
1384    * </p>
1385    *
1386    * <h5 class='section'>Notes:</h5><ul>
1387    *    <li class='note'>
1388    *       The {@link VarResolverSession} object can also be passed as a parameter on the method.
1389    * </ul>
1390    *
1391    * <h5 class='section'>See Also:</h5><ul>
1392    *    <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
1393    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerSvlVariables">SVL Variables</a>
1394    * </ul>
1395    *
1396    * @return The variable resolver for this request.
1397    */
1398   public VarResolverSession getVarResolverSession() {
1399      if (varSession == null)
1400         varSession = context
1401            .getVarResolver()
1402            .createSession(session.getBeanStore())
1403            .bean(RestRequest.class, this)
1404            .bean(RestSession.class, session);
1405      return varSession;
1406   }
1407
1408   /**
1409    * Returns the static files registered on the REST resource context object.
1410    *
1411    * <p>
1412    * Used to retrieve localized files to be served up as static files through the REST API.
1413    *
1414    * @return This object.
1415    */
1416   public StaticFiles getStaticFiles() {
1417      return context.getStaticFiles();
1418   }
1419
1420   /**
1421    * Config file associated with the resource.
1422    *
1423    * <p>
1424    * Returns a config file with session-level variable resolution.
1425    *
1426    * The config file is identified via one of the following:
1427    * <ul class='javatree'>
1428    *    <li class='ja'>{@link Rest#config()}
1429    *    <li class='jm'>{@link RestContext.Builder#config(Config)}
1430    * </ul>
1431    *
1432    * <h5 class='section'>Example:</h5>
1433    * <p class='bjava'>
1434    *    <ja>@RestGet</ja>(...)
1435    *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>) {
1436    *
1437    *       <jc>// Get config file.</jc>
1438    *       Config <jv>config</jv> = <jv>req</jv>.getConfig();
1439    *
1440    *       <jc>// Get simple values from config file.</jc>
1441    *       <jk>int</jk> <jv>timeout</jv> = <jv>config</jv>.get(<js>"MyResource/timeout"</js>).asInteger().orElse(=10000);
1442    *
1443    *       <jc>// Get complex values from config file.</jc>
1444    *       MyBean <jv>bean</jv> = <jv>config</jv>.get(<js>"MyResource/myBean"</js>).as(MyBean.<jk>class</jk>).orElse(<jk>null</jk>);
1445    *    }
1446    * </p>
1447    *
1448    * <h5 class='section'>Notes:</h5><ul>
1449    *    <li class='note'>
1450    *       The {@link Config} object can also be passed as a parameter on the method.
1451    * </ul>
1452    *
1453    * <h5 class='section'>See Also:</h5><ul>
1454    *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ConfigurationFiles">Configuration Files</a>
1455    * </ul>
1456    *
1457    * @return
1458    *    The config file associated with the resource, or <jk>null</jk> if resource does not have a config file
1459    *    associated with it.
1460    */
1461   public Config getConfig() {
1462      if (config == null)
1463         config = context.getConfig().resolving(getVarResolverSession());
1464      return config;
1465   }
1466
1467   /**
1468    * Creates a proxy interface to retrieve HTTP parts of this request as a proxy bean.
1469    *
1470    * <h5 class='section'>Examples:</h5>
1471    * <p class='bjava'>
1472    *    <ja>@RestPost</ja>(<js>"/mypath/{p1}/{p2}/*"</js>)
1473    *    <jk>public void</jk> myMethod(<ja>@Request</ja> MyRequest <jv>requestBean</jv>) {...}
1474    *
1475    *    <jk>public interface</jk> MyRequest {
1476    *
1477    *       <ja>@Path</ja> <jc>// Path variable name inferred from getter.</jc>
1478    *       String getP1();
1479    *
1480    *       <ja>@Path</ja>(<js>"p2"</js>)
1481    *       String getX();
1482    *
1483    *       <ja>@Path</ja>(<js>"/*"</js>)
1484    *       String getRemainder();
1485    *
1486    *       <ja>@Query</ja>
1487    *       String getQ1();
1488    *
1489    *    <jc>// Schema-based query parameter:  Pipe-delimited lists of comma-delimited lists of integers.</jc>
1490    *       <ja>@Query</ja>(
1491    *          collectionFormat=<js>"pipes"</js>
1492    *          items=<ja>@Items</ja>(
1493    *             items=<ja>@SubItems</ja>(
1494    *                collectionFormat=<js>"csv"</js>
1495    *                type=<js>"integer"</js>
1496    *             )
1497    *          )
1498    *       )
1499    *       <jk>int</jk>[][] getQ3();
1500    *
1501    *       <ja>@Header</ja>(<js>"*"</js>)
1502    *       Map&lt;String,Object&gt; getHeaders();
1503    * </p>
1504    *
1505    * @param <T> The request bean interface to instantiate.
1506    * @param c The request bean interface to instantiate.
1507    * @return A new request bean proxy for this REST request.
1508    */
1509   public <T> T getRequest(Class<T> c) {
1510      return getRequest(RequestBeanMeta.create(c, getContext().getAnnotations()));
1511   }
1512
1513   /**
1514    * Same as {@link #getRequest(Class)} but used on pre-instantiated {@link RequestBeanMeta} objects.
1515    *
1516    * @param <T> The request bean interface to instantiate.
1517    * @param rbm The metadata about the request bean interface to create.
1518    * @return A new request bean proxy for this REST request.
1519    */
1520   public <T> T getRequest(final RequestBeanMeta rbm) {
1521      try {
1522         Class<T> c = (Class<T>)rbm.getClassMeta().getInnerClass();
1523         final BeanSession bs = getBeanSession();
1524         final BeanMeta<T> bm = bs.getBeanMeta(c);
1525         return (T)Proxy.newProxyInstance(
1526            c.getClassLoader(),
1527            new Class[] { c },
1528            (InvocationHandler) (proxy, method, args) -> {
1529               RequestBeanPropertyMeta pm = rbm.getProperty(method.getName());
1530               if (pm != null) {
1531                  HttpPartParserSession pp = pm.getParser(getPartParserSession());
1532                  HttpPartSchema schema = pm.getSchema();
1533                  String name = pm.getPartName();
1534                  ClassMeta<?> type = bs.getClassMeta(method.getGenericReturnType());
1535                  HttpPartType pt = pm.getPartType();
1536                  if (pt == HttpPartType.BODY)
1537                     return getContent().setSchema(schema).as(type);
1538                  if (pt == QUERY)
1539                     return getQueryParam(name).parser(pp).schema(schema).as(type).orElse(null);
1540                  if (pt == FORMDATA)
1541                     return getFormParam(name).parser(pp).schema(schema).as(type).orElse(null);
1542                  if (pt == HEADER)
1543                     return getHeaderParam(name).parser(pp).schema(schema).as(type).orElse(null);
1544                  if (pt == PATH)
1545                     return getPathParam(name).parser(pp).schema(schema).as(type).orElse(null);
1546               }
1547               return null;
1548            });
1549      } catch (Exception e) {
1550         throw asRuntimeException(e);
1551      }
1552   }
1553
1554   /* Called by RestSession.finish() */
1555   void close() {
1556      if (config != null) {
1557         config.close();
1558      }
1559   }
1560
1561   /**
1562    * Returns the wrapped servlet request.
1563    *
1564    * @return The wrapped servlet request.
1565    */
1566   public HttpServletRequest getHttpServletRequest() {
1567      return inner;
1568   }
1569
1570   /**
1571    * Returns the part serializer session for this request.
1572    *
1573    * @return The part serializer session for this request.
1574    */
1575   public HttpPartSerializerSession getPartSerializerSession() {
1576      return opContext.getPartSerializer().getPartSession();
1577   }
1578
1579   @Override /* Object */
1580   public String toString() {
1581      StringBuilder sb = new StringBuilder("\n").append(getRequestLine()).append("\n");
1582      sb.append("---Headers---\n");
1583      getHeaders().forEach(x -> sb.append("\t").append(x).append("\n"));
1584      String m = getMethod();
1585      if (m.equals("PUT") || m.equals("POST")) {
1586         try {
1587            sb.append("---Content UTF-8---\n");
1588            sb.append(content.asString()).append("\n");
1589            sb.append("---Content Hex---\n");
1590            sb.append(content.asSpacedHex()).append("\n");
1591         } catch (Exception e1) {
1592            sb.append(e1.getLocalizedMessage());
1593         }
1594      }
1595      return sb.toString();
1596   }
1597
1598   //-----------------------------------------------------------------------------------------------------------------
1599   // Utility methods
1600   //-----------------------------------------------------------------------------------------------------------------
1601
1602   /*
1603    * Converts an Accept-Language value entry to a Locale.
1604    */
1605   private static Locale toLocale(String lang) {
1606      String country = "";
1607      int i = lang.indexOf('-');
1608      if (i > -1) {
1609         country = lang.substring(i+1).trim();
1610         lang = lang.substring(0,i).trim();
1611      }
1612      return new Locale(lang, country);
1613   }
1614}