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