]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/Request.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / server / Request.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import java.io.BufferedReader;
22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.UnsupportedEncodingException;
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.nio.charset.Charset;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.charset.UnsupportedCharsetException;
33 import java.security.Principal;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Enumeration;
38 import java.util.EventListener;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.Locale;
42 import java.util.Map;
43
44 import javax.servlet.AsyncContext;
45 import javax.servlet.AsyncListener;
46 import javax.servlet.DispatcherType;
47 import javax.servlet.MultipartConfigElement;
48 import javax.servlet.RequestDispatcher;
49 import javax.servlet.ServletContext;
50 import javax.servlet.ServletException;
51 import javax.servlet.ServletInputStream;
52 import javax.servlet.ServletRequest;
53 import javax.servlet.ServletRequestAttributeEvent;
54 import javax.servlet.ServletRequestAttributeListener;
55 import javax.servlet.ServletRequestEvent;
56 import javax.servlet.ServletRequestListener;
57 import javax.servlet.ServletResponse;
58 import javax.servlet.http.Cookie;
59 import javax.servlet.http.HttpServletRequest;
60 import javax.servlet.http.HttpServletResponse;
61 import javax.servlet.http.HttpSession;
62 import javax.servlet.http.HttpUpgradeHandler;
63 import javax.servlet.http.Part;
64
65 import org.eclipse.jetty.http.HttpCookie;
66 import org.eclipse.jetty.http.HttpFields;
67 import org.eclipse.jetty.http.HttpHeader;
68 import org.eclipse.jetty.http.HttpMethod;
69 import org.eclipse.jetty.http.HttpStatus;
70 import org.eclipse.jetty.http.HttpURI;
71 import org.eclipse.jetty.http.HttpVersion;
72 import org.eclipse.jetty.http.MimeTypes;
73 import org.eclipse.jetty.server.handler.ContextHandler;
74 import org.eclipse.jetty.server.handler.ContextHandler.Context;
75 import org.eclipse.jetty.server.session.AbstractSession;
76 import org.eclipse.jetty.util.Attributes;
77 import org.eclipse.jetty.util.AttributesMap;
78 import org.eclipse.jetty.util.IO;
79 import org.eclipse.jetty.util.MultiException;
80 import org.eclipse.jetty.util.MultiMap;
81 import org.eclipse.jetty.util.MultiPartInputStreamParser;
82 import org.eclipse.jetty.util.StringUtil;
83 import org.eclipse.jetty.util.URIUtil;
84 import org.eclipse.jetty.util.UrlEncoded;
85 import org.eclipse.jetty.util.log.Log;
86 import org.eclipse.jetty.util.log.Logger;
87
88 /* ------------------------------------------------------------ */
89 /**
90  * Jetty Request.
91  * <p>
92  * Implements {@link javax.servlet.http.HttpServletRequest} from the <code>javax.servlet.http</code> package.
93  * </p>
94  * <p>
95  * The standard interface of mostly getters, is extended with setters so that the request is mutable by the handlers that it is passed to. This allows the
96  * request object to be as lightweight as possible and not actually implement any significant behavior. For example
97  * <ul>
98  *
99  * <li>The {@link Request#getContextPath()} method will return null, until the request has been passed to a {@link ContextHandler} which matches the
100  * {@link Request#getPathInfo()} with a context path and calls {@link Request#setContextPath(String)} as a result.</li>
101  *
102  * <li>the HTTP session methods will all return null sessions until such time as a request has been passed to a
103  * {@link org.eclipse.jetty.server.session.SessionHandler} which checks for session cookies and enables the ability to create new sessions.</li>
104  *
105  * <li>The {@link Request#getServletPath()} method will return null until the request has been passed to a <code>org.eclipse.jetty.servlet.ServletHandler</code>
106  * and the pathInfo matched against the servlet URL patterns and {@link Request#setServletPath(String)} called as a result.</li>
107  * </ul>
108  *
109  * A request instance is created for each connection accepted by the server and recycled for each HTTP request received via that connection.
110  * An effort is made to avoid reparsing headers and cookies that are likely to be the same for requests from the same connection.
111  *
112  * <p>
113  * The form content that a request can process is limited to protect from Denial of Service attacks. The size in bytes is limited by
114  * {@link ContextHandler#getMaxFormContentSize()} or if there is no context then the "org.eclipse.jetty.server.Request.maxFormContentSize" {@link Server}
115  * attribute. The number of parameters keys is limited by {@link ContextHandler#getMaxFormKeys()} or if there is no context then the
116  * "org.eclipse.jetty.server.Request.maxFormKeys" {@link Server} attribute.
117  *
118  *
119  */
120 public class Request implements HttpServletRequest
121 {
122     public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.jetty.multipartConfig";
123     public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.jetty.multiPartInputStream";
124     public static final String __MULTIPART_CONTEXT = "org.eclipse.jetty.multiPartContext";
125
126     private static final Logger LOG = Log.getLogger(Request.class);
127     private static final Collection<Locale> __defaultLocale = Collections.singleton(Locale.getDefault());
128     private static final int __NONE = 0, _STREAM = 1, __READER = 2;
129
130     private final HttpChannel<?> _channel;
131     private final HttpFields _fields=new HttpFields();
132     private final List<ServletRequestAttributeListener>  _requestAttributeListeners=new ArrayList<>();
133     private final HttpInput<?> _input;
134
135     public static class MultiPartCleanerListener implements ServletRequestListener
136     {
137         @Override
138         public void requestDestroyed(ServletRequestEvent sre)
139         {
140             //Clean up any tmp files created by MultiPartInputStream
141             MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM);
142             if (mpis != null)
143             {
144                 ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(__MULTIPART_CONTEXT);
145
146                 //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files
147                 if (context == sre.getServletContext())
148                 {
149                     try
150                     {
151                         mpis.deleteParts();
152                     }
153                     catch (MultiException e)
154                     {
155                         sre.getServletContext().log("Errors deleting multipart tmp files", e);
156                     }
157                 }
158             }
159         }
160
161         @Override
162         public void requestInitialized(ServletRequestEvent sre)
163         {
164             //nothing to do, multipart config set up by ServletHolder.handle()
165         }
166
167     }
168
169
170
171     private boolean _secure;
172     private boolean _asyncSupported = true;
173     private boolean _newContext;
174     private boolean _cookiesExtracted = false;
175     private boolean _handled = false;
176     private boolean _paramsExtracted;
177     private boolean _requestedSessionIdFromCookie = false;
178     private volatile Attributes _attributes;
179     private Authentication _authentication;
180     private String _characterEncoding;
181     private ContextHandler.Context _context;
182     private String _contextPath;
183     private CookieCutter _cookies;
184     private DispatcherType _dispatcherType;
185     private int _inputState = __NONE;
186     private HttpMethod _httpMethod;
187     private String _httpMethodString;
188     private MultiMap<String> _queryParameters;
189     private MultiMap<String> _contentParameters;
190     private MultiMap<String> _parameters;
191     private String _pathInfo;
192     private int _port;
193     private HttpVersion _httpVersion = HttpVersion.HTTP_1_1;
194     private String _queryEncoding;
195     private String _queryString;
196     private BufferedReader _reader;
197     private String _readerEncoding;
198     private InetSocketAddress _remote;
199     private String _requestedSessionId;
200     private String _requestURI;
201     private Map<Object, HttpSession> _savedNewSessions;
202     private String _scheme = URIUtil.HTTP;
203     private UserIdentity.Scope _scope;
204     private String _serverName;
205     private String _servletPath;
206     private HttpSession _session;
207     private SessionManager _sessionManager;
208     private long _timeStamp;
209     private HttpURI _uri;
210     private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime
211     private AsyncContextState _async;
212
213     /* ------------------------------------------------------------ */
214     public Request(HttpChannel<?> channel, HttpInput<?> input)
215     {
216         _channel = channel;
217         _input = input;
218     }
219
220     /* ------------------------------------------------------------ */
221     public HttpFields getHttpFields()
222     {
223         return _fields;
224     }
225
226     /* ------------------------------------------------------------ */
227     public HttpInput<?> getHttpInput()
228     {
229         return _input;
230     }
231
232     /* ------------------------------------------------------------ */
233     public void addEventListener(final EventListener listener)
234     {
235         if (listener instanceof ServletRequestAttributeListener)
236             _requestAttributeListeners.add((ServletRequestAttributeListener)listener);
237         if (listener instanceof AsyncListener)
238             throw new IllegalArgumentException(listener.getClass().toString());
239     }
240
241     public void extractParameters()
242     {
243         if (_paramsExtracted)
244             return;
245
246         _paramsExtracted = true;
247
248         // Extract query string parameters; these may be replaced by a forward()
249         // and may have already been extracted by mergeQueryParameters().
250         if (_queryParameters == null)
251             _queryParameters = extractQueryParameters();
252
253         // Extract content parameters; these cannot be replaced by a forward()
254         // once extracted and may have already been extracted by getParts() or
255         // by a processing happening after a form-based authentication.
256         if (_contentParameters == null)
257             _contentParameters = extractContentParameters();
258
259         _parameters = restoreParameters();
260     }
261
262     private MultiMap<String> extractQueryParameters()
263     {
264         MultiMap<String> result = new MultiMap<>();
265         if (_uri != null && _uri.hasQuery())
266         {
267             if (_queryEncoding == null)
268             {
269                 _uri.decodeQueryTo(result);
270             }
271             else
272             {
273                 try
274                 {
275                     _uri.decodeQueryTo(result, _queryEncoding);
276                 }
277                 catch (UnsupportedEncodingException e)
278                 {
279                     if (LOG.isDebugEnabled())
280                         LOG.warn(e);
281                     else
282                         LOG.warn(e.toString());
283                 }
284             }
285         }
286         return result;
287     }
288
289     private MultiMap<String> extractContentParameters()
290     {
291         MultiMap<String> result = new MultiMap<>();
292
293         String contentType = getContentType();
294         if (contentType != null && !contentType.isEmpty())
295         {
296             contentType = HttpFields.valueParameters(contentType, null);
297             int contentLength = getContentLength();
298             if (contentLength != 0)
299             {
300                 if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE &&
301                         (HttpMethod.POST.is(getMethod()) || HttpMethod.PUT.is(getMethod())))
302                 {
303                     extractFormParameters(result);
304                 }
305                 else if (contentType.startsWith("multipart/form-data") &&
306                         getAttribute(__MULTIPART_CONFIG_ELEMENT) != null &&
307                         _multiPartInputStream == null)
308                 {
309                     extractMultipartParameters(result);
310                 }
311             }
312         }
313
314         return result;
315     }
316
317     public void extractFormParameters(MultiMap<String> params)
318     {
319         try
320         {
321             int maxFormContentSize = -1;
322             int maxFormKeys = -1;
323
324             if (_context != null)
325             {
326                 maxFormContentSize = _context.getContextHandler().getMaxFormContentSize();
327                 maxFormKeys = _context.getContextHandler().getMaxFormKeys();
328             }
329
330             if (maxFormContentSize < 0)
331             {
332                 Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
333                 if (obj == null)
334                     maxFormContentSize = 200000;
335                 else if (obj instanceof Number)
336                 {
337                     Number size = (Number)obj;
338                     maxFormContentSize = size.intValue();
339                 }
340                 else if (obj instanceof String)
341                 {
342                     maxFormContentSize = Integer.valueOf((String)obj);
343                 }
344             }
345
346             if (maxFormKeys < 0)
347             {
348                 Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
349                 if (obj == null)
350                     maxFormKeys = 1000;
351                 else if (obj instanceof Number)
352                 {
353                     Number keys = (Number)obj;
354                     maxFormKeys = keys.intValue();
355                 }
356                 else if (obj instanceof String)
357                 {
358                     maxFormKeys = Integer.valueOf((String)obj);
359                 }
360             }
361
362             int contentLength = getContentLength();
363             if (contentLength > maxFormContentSize && maxFormContentSize > 0)
364             {
365                 throw new IllegalStateException("Form too large: " + contentLength + " > " + maxFormContentSize);
366             }
367             InputStream in = getInputStream();
368             if (_input.isAsync())
369                 throw new IllegalStateException("Cannot extract parameters with async IO");
370
371             UrlEncoded.decodeTo(in,params,getCharacterEncoding(),contentLength<0?maxFormContentSize:-1,maxFormKeys);
372         }
373         catch (IOException e)
374         {
375             if (LOG.isDebugEnabled())
376                 LOG.warn(e);
377             else
378                 LOG.warn(e.toString());
379         }
380     }
381
382     private void extractMultipartParameters(MultiMap<String> result)
383     {
384         try
385         {
386             getParts(result);
387         }
388         catch (IOException | ServletException e)
389         {
390             LOG.warn(e);
391             throw new RuntimeException(e);
392         }
393     }
394
395     /* ------------------------------------------------------------ */
396     @Override
397     public AsyncContext getAsyncContext()
398     {
399         HttpChannelState state = getHttpChannelState();
400         if (_async==null || !state.isAsyncStarted())
401             throw new IllegalStateException(state.getStatusString());
402
403         return _async;
404     }
405
406     /* ------------------------------------------------------------ */
407     public HttpChannelState getHttpChannelState()
408     {
409         return _channel.getState();
410     }
411
412     /* ------------------------------------------------------------ */
413     /**
414      * Get Request Attribute.
415      * <p>Also supports jetty specific attributes to gain access to Jetty APIs:
416      * <dl>
417      * <dt>org.eclipse.jetty.server.Server</dt><dd>The Jetty Server instance</dd>
418      * <dt>org.eclipse.jetty.server.HttpChannel</dt><dd>The HttpChannel for this request</dd>
419      * <dt>org.eclipse.jetty.server.HttpConnection</dt><dd>The HttpConnection or null if another transport is used</dd>
420      * </dl>
421      * While these attributes may look like security problems, they are exposing nothing that is not already
422      * available via reflection from a Request instance.
423      * </p>
424      * @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
425      */
426     @Override
427     public Object getAttribute(String name)
428     {
429         if (name.startsWith("org.eclipse.jetty"))
430         {
431             if ("org.eclipse.jetty.server.Server".equals(name))
432                 return _channel.getServer();
433             if ("org.eclipse.jetty.server.HttpChannel".equals(name))
434                 return _channel;
435             if ("org.eclipse.jetty.server.HttpConnection".equals(name) &&
436                 _channel.getHttpTransport() instanceof HttpConnection)
437                 return _channel.getHttpTransport();
438         }
439         return (_attributes == null)?null:_attributes.getAttribute(name);
440     }
441
442     /* ------------------------------------------------------------ */
443     /*
444      * @see javax.servlet.ServletRequest#getAttributeNames()
445      */
446     @Override
447     public Enumeration<String> getAttributeNames()
448     {
449         if (_attributes == null)
450             return Collections.enumeration(Collections.<String>emptyList());
451
452         return AttributesMap.getAttributeNamesCopy(_attributes);
453     }
454
455     /* ------------------------------------------------------------ */
456     /*
457      */
458     public Attributes getAttributes()
459     {
460         if (_attributes == null)
461             _attributes = new AttributesMap();
462         return _attributes;
463     }
464
465     /* ------------------------------------------------------------ */
466     /**
467      * Get the authentication.
468      *
469      * @return the authentication
470      */
471     public Authentication getAuthentication()
472     {
473         return _authentication;
474     }
475
476     /* ------------------------------------------------------------ */
477     /*
478      * @see javax.servlet.http.HttpServletRequest#getAuthType()
479      */
480     @Override
481     public String getAuthType()
482     {
483         if (_authentication instanceof Authentication.Deferred)
484             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
485
486         if (_authentication instanceof Authentication.User)
487             return ((Authentication.User)_authentication).getAuthMethod();
488         return null;
489     }
490
491     /* ------------------------------------------------------------ */
492     /*
493      * @see javax.servlet.ServletRequest#getCharacterEncoding()
494      */
495     @Override
496     public String getCharacterEncoding()
497     {
498         return _characterEncoding;
499     }
500
501     /* ------------------------------------------------------------ */
502     /**
503      * @return Returns the connection.
504      */
505     public HttpChannel<?> getHttpChannel()
506     {
507         return _channel;
508     }
509
510     /* ------------------------------------------------------------ */
511     /*
512      * @see javax.servlet.ServletRequest#getContentLength()
513      */
514     @Override
515     public int getContentLength()
516     {
517         return (int)_fields.getLongField(HttpHeader.CONTENT_LENGTH.toString());
518     }
519
520     /* ------------------------------------------------------------ */
521     /*
522      * @see javax.servlet.ServletRequest.getContentLengthLong()
523      */
524     @Override
525     public long getContentLengthLong()
526     {
527         return _fields.getLongField(HttpHeader.CONTENT_LENGTH.toString());
528     }
529
530     /* ------------------------------------------------------------ */
531     public long getContentRead()
532     {
533         return _input.getContentRead();
534     }
535
536     /* ------------------------------------------------------------ */
537     /*
538      * @see javax.servlet.ServletRequest#getContentType()
539      */
540     @Override
541     public String getContentType()
542     {
543         return _fields.getStringField(HttpHeader.CONTENT_TYPE);
544     }
545
546     /* ------------------------------------------------------------ */
547     /**
548      * @return The current {@link Context context} used for this request, or <code>null</code> if {@link #setContext} has not yet been called.
549      */
550     public Context getContext()
551     {
552         return _context;
553     }
554
555     /* ------------------------------------------------------------ */
556     /*
557      * @see javax.servlet.http.HttpServletRequest#getContextPath()
558      */
559     @Override
560     public String getContextPath()
561     {
562         return _contextPath;
563     }
564
565     /* ------------------------------------------------------------ */
566     /*
567      * @see javax.servlet.http.HttpServletRequest#getCookies()
568      */
569     @Override
570     public Cookie[] getCookies()
571     {
572         if (_cookiesExtracted)
573         {
574             if (_cookies == null || _cookies.getCookies().length == 0)
575                 return null;
576
577             return _cookies.getCookies();
578         }
579
580         _cookiesExtracted = true;
581
582         Enumeration<?> enm = _fields.getValues(HttpHeader.COOKIE.toString());
583
584         // Handle no cookies
585         if (enm != null)
586         {
587             if (_cookies == null)
588                 _cookies = new CookieCutter();
589
590             while (enm.hasMoreElements())
591             {
592                 String c = (String)enm.nextElement();
593                 _cookies.addCookieField(c);
594             }
595         }
596
597         //Javadoc for Request.getCookies() stipulates null for no cookies
598         if (_cookies == null || _cookies.getCookies().length == 0)
599             return null;
600
601         return _cookies.getCookies();
602     }
603
604     /* ------------------------------------------------------------ */
605     /*
606      * @see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String)
607      */
608     @Override
609     public long getDateHeader(String name)
610     {
611         return _fields.getDateField(name);
612     }
613
614     /* ------------------------------------------------------------ */
615     @Override
616     public DispatcherType getDispatcherType()
617     {
618         return _dispatcherType;
619     }
620
621     /* ------------------------------------------------------------ */
622     /*
623      * @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
624      */
625     @Override
626     public String getHeader(String name)
627     {
628         return _fields.getStringField(name);
629     }
630
631     /* ------------------------------------------------------------ */
632     /*
633      * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
634      */
635     @Override
636     public Enumeration<String> getHeaderNames()
637     {
638         return _fields.getFieldNames();
639     }
640
641     /* ------------------------------------------------------------ */
642     /*
643      * @see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String)
644      */
645     @Override
646     public Enumeration<String> getHeaders(String name)
647     {
648         Enumeration<String> e = _fields.getValues(name);
649         if (e == null)
650             return Collections.enumeration(Collections.<String>emptyList());
651         return e;
652     }
653
654     /* ------------------------------------------------------------ */
655     /**
656      * @return Returns the inputState.
657      */
658     public int getInputState()
659     {
660         return _inputState;
661     }
662
663     /* ------------------------------------------------------------ */
664     /*
665      * @see javax.servlet.ServletRequest#getInputStream()
666      */
667     @Override
668     public ServletInputStream getInputStream() throws IOException
669     {
670         if (_inputState != __NONE && _inputState != _STREAM)
671             throw new IllegalStateException("READER");
672         _inputState = _STREAM;
673
674         if (_channel.isExpecting100Continue())
675             _channel.continue100(_input.available());
676
677         return _input;
678     }
679
680     /* ------------------------------------------------------------ */
681     /*
682      * @see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String)
683      */
684     @Override
685     public int getIntHeader(String name)
686     {
687         return (int)_fields.getLongField(name);
688     }
689
690
691     /* ------------------------------------------------------------ */
692     /*
693      * @see javax.servlet.ServletRequest#getLocale()
694      */
695     @Override
696     public Locale getLocale()
697     {
698         Enumeration<String> enm = _fields.getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators);
699
700         // handle no locale
701         if (enm == null || !enm.hasMoreElements())
702             return Locale.getDefault();
703
704         // sort the list in quality order
705         List<?> acceptLanguage = HttpFields.qualityList(enm);
706         if (acceptLanguage.size() == 0)
707             return Locale.getDefault();
708
709         int size = acceptLanguage.size();
710
711         if (size > 0)
712         {
713             String language = (String)acceptLanguage.get(0);
714             language = HttpFields.valueParameters(language,null);
715             String country = "";
716             int dash = language.indexOf('-');
717             if (dash > -1)
718             {
719                 country = language.substring(dash + 1).trim();
720                 language = language.substring(0,dash).trim();
721             }
722             return new Locale(language,country);
723         }
724
725         return Locale.getDefault();
726     }
727
728     /* ------------------------------------------------------------ */
729     /*
730      * @see javax.servlet.ServletRequest#getLocales()
731      */
732     @Override
733     public Enumeration<Locale> getLocales()
734     {
735
736         Enumeration<String> enm = _fields.getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators);
737
738         // handle no locale
739         if (enm == null || !enm.hasMoreElements())
740             return Collections.enumeration(__defaultLocale);
741
742         // sort the list in quality order
743         List<String> acceptLanguage = HttpFields.qualityList(enm);
744
745         if (acceptLanguage.size() == 0)
746             return Collections.enumeration(__defaultLocale);
747
748         List<Locale> langs = new ArrayList<>();
749
750         // convert to locals
751         for (String language : acceptLanguage)
752         {
753             language = HttpFields.valueParameters(language, null);
754             String country = "";
755             int dash = language.indexOf('-');
756             if (dash > -1)
757             {
758                 country = language.substring(dash + 1).trim();
759                 language = language.substring(0, dash).trim();
760             }
761             langs.add(new Locale(language, country));
762         }
763
764         if (langs.size() == 0)
765             return Collections.enumeration(__defaultLocale);
766
767         return Collections.enumeration(langs);
768     }
769
770     /* ------------------------------------------------------------ */
771     /*
772      * @see javax.servlet.ServletRequest#getLocalAddr()
773      */
774     @Override
775     public String getLocalAddr()
776     {
777         InetSocketAddress local=_channel.getLocalAddress();
778         if (local==null)
779             return "";
780         InetAddress address = local.getAddress();
781         if (address==null)
782             return local.getHostString();
783         return address.getHostAddress();
784     }
785
786     /* ------------------------------------------------------------ */
787     /*
788      * @see javax.servlet.ServletRequest#getLocalName()
789      */
790     @Override
791     public String getLocalName()
792     {
793         InetSocketAddress local=_channel.getLocalAddress();
794         return local.getHostString();
795     }
796
797     /* ------------------------------------------------------------ */
798     /*
799      * @see javax.servlet.ServletRequest#getLocalPort()
800      */
801     @Override
802     public int getLocalPort()
803     {
804         InetSocketAddress local=_channel.getLocalAddress();
805         return local.getPort();
806     }
807
808     /* ------------------------------------------------------------ */
809     /*
810      * @see javax.servlet.http.HttpServletRequest#getMethod()
811      */
812     @Override
813     public String getMethod()
814     {
815         return _httpMethodString;
816     }
817
818     /* ------------------------------------------------------------ */
819     /*
820      * @see javax.servlet.ServletRequest#getParameter(java.lang.String)
821      */
822     @Override
823     public String getParameter(String name)
824     {
825         if (!_paramsExtracted)
826             extractParameters();
827         if (_parameters == null)
828             _parameters = restoreParameters();
829         return _parameters.getValue(name,0);
830     }
831
832     /* ------------------------------------------------------------ */
833     /*
834      * @see javax.servlet.ServletRequest#getParameterMap()
835      */
836     @Override
837     public Map<String, String[]> getParameterMap()
838     {
839         if (!_paramsExtracted)
840             extractParameters();
841         if (_parameters == null)
842             _parameters = restoreParameters();
843         return Collections.unmodifiableMap(_parameters.toStringArrayMap());
844     }
845
846     /* ------------------------------------------------------------ */
847     /*
848      * @see javax.servlet.ServletRequest#getParameterNames()
849      */
850     @Override
851     public Enumeration<String> getParameterNames()
852     {
853         if (!_paramsExtracted)
854             extractParameters();
855         if (_parameters == null)
856             _parameters = restoreParameters();
857         return Collections.enumeration(_parameters.keySet());
858     }
859
860     /* ------------------------------------------------------------ */
861     /*
862      * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
863      */
864     @Override
865     public String[] getParameterValues(String name)
866     {
867         if (!_paramsExtracted)
868             extractParameters();
869         if (_parameters == null)
870             _parameters = restoreParameters();
871         List<String> vals = _parameters.getValues(name);
872         if (vals == null)
873             return null;
874         return vals.toArray(new String[vals.size()]);
875     }
876
877     private MultiMap<String> restoreParameters()
878     {
879         MultiMap<String> result = new MultiMap<>();
880         if (_queryParameters == null)
881             _queryParameters = extractQueryParameters();
882         result.addAllValues(_queryParameters);
883         result.addAllValues(_contentParameters);
884         return result;
885     }
886
887     public MultiMap<String> getQueryParameters()
888     {
889         return _queryParameters;
890     }
891
892     public void setQueryParameters(MultiMap<String> queryParameters)
893     {
894         _queryParameters = queryParameters;
895     }
896
897     public void setContentParameters(MultiMap<String> contentParameters)
898     {
899         _contentParameters = contentParameters;
900     }
901
902     public void resetParameters()
903     {
904         _parameters = null;
905     }
906
907     /* ------------------------------------------------------------ */
908     /*
909      * @see javax.servlet.http.HttpServletRequest#getPathInfo()
910      */
911     @Override
912     public String getPathInfo()
913     {
914         return _pathInfo;
915     }
916
917     /* ------------------------------------------------------------ */
918     /*
919      * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
920      */
921     @Override
922     public String getPathTranslated()
923     {
924         if (_pathInfo == null || _context == null)
925             return null;
926         return _context.getRealPath(_pathInfo);
927     }
928
929     /* ------------------------------------------------------------ */
930     /*
931      * @see javax.servlet.ServletRequest#getProtocol()
932      */
933     @Override
934     public String getProtocol()
935     {
936         return _httpVersion.toString();
937     }
938
939     /* ------------------------------------------------------------ */
940     /*
941      * @see javax.servlet.ServletRequest#getProtocol()
942      */
943     public HttpVersion getHttpVersion()
944     {
945         return _httpVersion;
946     }
947
948     /* ------------------------------------------------------------ */
949     public String getQueryEncoding()
950     {
951         return _queryEncoding;
952     }
953
954     /* ------------------------------------------------------------ */
955     /*
956      * @see javax.servlet.http.HttpServletRequest#getQueryString()
957      */
958     @Override
959     public String getQueryString()
960     {
961         if (_queryString == null && _uri != null)
962         {
963             if (_queryEncoding == null)
964                 _queryString = _uri.getQuery();
965             else
966                 _queryString = _uri.getQuery(_queryEncoding);
967         }
968         return _queryString;
969     }
970
971     /* ------------------------------------------------------------ */
972     /*
973      * @see javax.servlet.ServletRequest#getReader()
974      */
975     @Override
976     public BufferedReader getReader() throws IOException
977     {
978         if (_inputState != __NONE && _inputState != __READER)
979             throw new IllegalStateException("STREAMED");
980
981         if (_inputState == __READER)
982             return _reader;
983
984         String encoding = getCharacterEncoding();
985         if (encoding == null)
986             encoding = StringUtil.__ISO_8859_1;
987
988         if (_reader == null || !encoding.equalsIgnoreCase(_readerEncoding))
989         {
990             final ServletInputStream in = getInputStream();
991             _readerEncoding = encoding;
992             _reader = new BufferedReader(new InputStreamReader(in,encoding))
993             {
994                 @Override
995                 public void close() throws IOException
996                 {
997                     in.close();
998                 }
999             };
1000         }
1001         _inputState = __READER;
1002         return _reader;
1003     }
1004
1005     /* ------------------------------------------------------------ */
1006     /*
1007      * @see javax.servlet.ServletRequest#getRealPath(java.lang.String)
1008      */
1009     @Override
1010     public String getRealPath(String path)
1011     {
1012         if (_context == null)
1013             return null;
1014         return _context.getRealPath(path);
1015     }
1016
1017     /* ------------------------------------------------------------ */
1018     /**
1019      * Access the underlying Remote {@link InetSocketAddress} for this request.
1020      *
1021      * @return the remote {@link InetSocketAddress} for this request, or null if the request has no remote (see {@link ServletRequest#getRemoteAddr()} for
1022      *         conditions that result in no remote address)
1023      */
1024     public InetSocketAddress getRemoteInetSocketAddress()
1025     {
1026         InetSocketAddress remote = _remote;
1027         if (remote == null)
1028             remote = _channel.getRemoteAddress();
1029
1030         return remote;
1031     }
1032
1033     /* ------------------------------------------------------------ */
1034     /*
1035      * @see javax.servlet.ServletRequest#getRemoteAddr()
1036      */
1037     @Override
1038     public String getRemoteAddr()
1039     {
1040         InetSocketAddress remote=_remote;
1041         if (remote==null)
1042             remote=_channel.getRemoteAddress();
1043
1044         if (remote==null)
1045             return "";
1046
1047         InetAddress address = remote.getAddress();
1048         if (address==null)
1049             return remote.getHostString();
1050
1051         return address.getHostAddress();
1052     }
1053
1054     /* ------------------------------------------------------------ */
1055     /*
1056      * @see javax.servlet.ServletRequest#getRemoteHost()
1057      */
1058     @Override
1059     public String getRemoteHost()
1060     {
1061         InetSocketAddress remote=_remote;
1062         if (remote==null)
1063             remote=_channel.getRemoteAddress();
1064         return remote==null?"":remote.getHostString();
1065     }
1066
1067     /* ------------------------------------------------------------ */
1068     /*
1069      * @see javax.servlet.ServletRequest#getRemotePort()
1070      */
1071     @Override
1072     public int getRemotePort()
1073     {
1074         InetSocketAddress remote=_remote;
1075         if (remote==null)
1076             remote=_channel.getRemoteAddress();
1077         return remote==null?0:remote.getPort();
1078     }
1079
1080     /* ------------------------------------------------------------ */
1081     /*
1082      * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
1083      */
1084     @Override
1085     public String getRemoteUser()
1086     {
1087         Principal p = getUserPrincipal();
1088         if (p == null)
1089             return null;
1090         return p.getName();
1091     }
1092
1093     /* ------------------------------------------------------------ */
1094     /*
1095      * @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
1096      */
1097     @Override
1098     public RequestDispatcher getRequestDispatcher(String path)
1099     {
1100         if (path == null || _context == null)
1101             return null;
1102
1103         // handle relative path
1104         if (!path.startsWith("/"))
1105         {
1106             String relTo = URIUtil.addPaths(_servletPath,_pathInfo);
1107             int slash = relTo.lastIndexOf("/");
1108             if (slash > 1)
1109                 relTo = relTo.substring(0,slash + 1);
1110             else
1111                 relTo = "/";
1112             path = URIUtil.addPaths(relTo,path);
1113         }
1114
1115         return _context.getRequestDispatcher(path);
1116     }
1117
1118     /* ------------------------------------------------------------ */
1119     /*
1120      * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
1121      */
1122     @Override
1123     public String getRequestedSessionId()
1124     {
1125         return _requestedSessionId;
1126     }
1127
1128     /* ------------------------------------------------------------ */
1129     /*
1130      * @see javax.servlet.http.HttpServletRequest#getRequestURI()
1131      */
1132     @Override
1133     public String getRequestURI()
1134     {
1135         if (_requestURI == null && _uri != null)
1136             _requestURI = _uri.getPathAndParam();
1137         return _requestURI;
1138     }
1139
1140     /* ------------------------------------------------------------ */
1141     /*
1142      * @see javax.servlet.http.HttpServletRequest#getRequestURL()
1143      */
1144     @Override
1145     public StringBuffer getRequestURL()
1146     {
1147         final StringBuffer url = new StringBuffer(128);
1148         URIUtil.appendSchemeHostPort(url,getScheme(),getServerName(),getServerPort());
1149         url.append(getRequestURI());
1150         return url;
1151     }
1152
1153     /* ------------------------------------------------------------ */
1154     public Response getResponse()
1155     {
1156         return _channel.getResponse();
1157     }
1158
1159     /* ------------------------------------------------------------ */
1160     /**
1161      * Reconstructs the URL the client used to make the request. The returned URL contains a protocol, server name, port number, and, but it does not include a
1162      * path.
1163      * <p>
1164      * Because this method returns a <code>StringBuffer</code>, not a string, you can modify the URL easily, for example, to append path and query parameters.
1165      *
1166      * This method is useful for creating redirect messages and for reporting errors.
1167      *
1168      * @return "scheme://host:port"
1169      */
1170     public StringBuilder getRootURL()
1171     {
1172         StringBuilder url = new StringBuilder(128);
1173         URIUtil.appendSchemeHostPort(url,getScheme(),getServerName(),getServerPort());
1174         return url;
1175     }
1176
1177     /* ------------------------------------------------------------ */
1178     /*
1179      * @see javax.servlet.ServletRequest#getScheme()
1180      */
1181     @Override
1182     public String getScheme()
1183     {
1184         return _scheme;
1185     }
1186
1187     /* ------------------------------------------------------------ */
1188     /*
1189      * @see javax.servlet.ServletRequest#getServerName()
1190      */
1191     @Override
1192     public String getServerName()
1193     {
1194         // Return already determined host
1195         if (_serverName != null)
1196             return _serverName;
1197
1198         if (_uri == null)
1199             throw new IllegalStateException("No uri");
1200
1201         // Return host from absolute URI
1202         _serverName = _uri.getHost();
1203         if (_serverName != null)
1204         {
1205             _port = _uri.getPort();
1206             return _serverName;
1207         }
1208
1209         // Return host from header field
1210         String hostPort = _fields.getStringField(HttpHeader.HOST);
1211
1212         _port=0;
1213         if (hostPort != null)
1214         {
1215             int len=hostPort.length();
1216             loop: for (int i = len; i-- > 0;)
1217             {
1218                 char c2 = (char)(0xff & hostPort.charAt(i));
1219                 switch (c2)
1220                 {
1221                     case ']':
1222                         break loop;
1223
1224                     case ':':
1225                         try
1226                         {
1227                             len=i;
1228                             _port = StringUtil.toInt(hostPort.substring(i+1));
1229                         }
1230                         catch (NumberFormatException e)
1231                         {
1232                             LOG.warn(e);
1233                             _serverName=hostPort;
1234                             _port=0;
1235                             return _serverName;
1236                         }
1237                         break loop;
1238                 }
1239             }
1240             if (hostPort.charAt(0)=='[')
1241             {
1242                 if (hostPort.charAt(len-1)!=']')
1243                 {
1244                     LOG.warn("Bad IPv6 "+hostPort);
1245                     _serverName=hostPort;
1246                     _port=0;
1247                     return _serverName;
1248                 }
1249                 _serverName = hostPort.substring(0,len);
1250             }
1251             else if (len==hostPort.length())
1252                 _serverName=hostPort;
1253             else
1254                 _serverName = hostPort.substring(0,len);
1255
1256             return _serverName;
1257         }
1258
1259         // Return host from connection
1260         if (_channel != null)
1261         {
1262             _serverName = getLocalName();
1263             _port = getLocalPort();
1264             if (_serverName != null && !StringUtil.ALL_INTERFACES.equals(_serverName))
1265                 return _serverName;
1266         }
1267
1268         // Return the local host
1269         try
1270         {
1271             _serverName = InetAddress.getLocalHost().getHostAddress();
1272         }
1273         catch (java.net.UnknownHostException e)
1274         {
1275             LOG.ignore(e);
1276         }
1277         return _serverName;
1278     }
1279
1280     /* ------------------------------------------------------------ */
1281     /*
1282      * @see javax.servlet.ServletRequest#getServerPort()
1283      */
1284     @Override
1285     public int getServerPort()
1286     {
1287         if (_port <= 0)
1288         {
1289             if (_serverName == null)
1290                 getServerName();
1291
1292             if (_port <= 0)
1293             {
1294                 if (_serverName != null && _uri != null)
1295                     _port = _uri.getPort();
1296                 else
1297                 {
1298                     InetSocketAddress local = _channel.getLocalAddress();
1299                     _port = local == null?0:local.getPort();
1300                 }
1301             }
1302         }
1303
1304         if (_port <= 0)
1305         {
1306             if (getScheme().equalsIgnoreCase(URIUtil.HTTPS))
1307                 return 443;
1308             return 80;
1309         }
1310         return _port;
1311     }
1312
1313     /* ------------------------------------------------------------ */
1314     @Override
1315     public ServletContext getServletContext()
1316     {
1317         return _context;
1318     }
1319
1320     /* ------------------------------------------------------------ */
1321     /*
1322      */
1323     public String getServletName()
1324     {
1325         if (_scope != null)
1326             return _scope.getName();
1327         return null;
1328     }
1329
1330     /* ------------------------------------------------------------ */
1331     /*
1332      * @see javax.servlet.http.HttpServletRequest#getServletPath()
1333      */
1334     @Override
1335     public String getServletPath()
1336     {
1337         if (_servletPath == null)
1338             _servletPath = "";
1339         return _servletPath;
1340     }
1341
1342     /* ------------------------------------------------------------ */
1343     public ServletResponse getServletResponse()
1344     {
1345         return _channel.getResponse();
1346     }
1347
1348     /* ------------------------------------------------------------ */
1349     /*
1350      * Add @override when 3.1 api is available
1351      */
1352     public String changeSessionId()
1353     {
1354         HttpSession session = getSession(false);
1355         if (session == null)
1356             throw new IllegalStateException("No session");
1357
1358         if (session instanceof AbstractSession)
1359         {
1360             AbstractSession abstractSession =  ((AbstractSession)session);
1361             abstractSession.renewId(this);
1362             if (getRemoteUser() != null)
1363                 abstractSession.setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
1364             if (abstractSession.isIdChanged())
1365                 _channel.getResponse().addCookie(_sessionManager.getSessionCookie(abstractSession, getContextPath(), isSecure()));
1366         }
1367
1368         return session.getId();
1369     }
1370
1371     /* ------------------------------------------------------------ */
1372     /*
1373      * @see javax.servlet.http.HttpServletRequest#getSession()
1374      */
1375     @Override
1376     public HttpSession getSession()
1377     {
1378         return getSession(true);
1379     }
1380
1381     /* ------------------------------------------------------------ */
1382     /*
1383      * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
1384      */
1385     @Override
1386     public HttpSession getSession(boolean create)
1387     {
1388         if (_session != null)
1389         {
1390             if (_sessionManager != null && !_sessionManager.isValid(_session))
1391                 _session = null;
1392             else
1393                 return _session;
1394         }
1395
1396         if (!create)
1397             return null;
1398
1399         if (getResponse().isCommitted())
1400             throw new IllegalStateException("Response is committed");
1401
1402         if (_sessionManager == null)
1403             throw new IllegalStateException("No SessionManager");
1404
1405         _session = _sessionManager.newHttpSession(this);
1406         HttpCookie cookie = _sessionManager.getSessionCookie(_session,getContextPath(),isSecure());
1407         if (cookie != null)
1408             _channel.getResponse().addCookie(cookie);
1409
1410         return _session;
1411     }
1412
1413     /* ------------------------------------------------------------ */
1414     /**
1415      * @return Returns the sessionManager.
1416      */
1417     public SessionManager getSessionManager()
1418     {
1419         return _sessionManager;
1420     }
1421
1422     /* ------------------------------------------------------------ */
1423     /**
1424      * Get Request TimeStamp
1425      *
1426      * @return The time that the request was received.
1427      */
1428     public long getTimeStamp()
1429     {
1430         return _timeStamp;
1431     }
1432
1433     /* ------------------------------------------------------------ */
1434     /**
1435      * @return Returns the uri.
1436      */
1437     public HttpURI getUri()
1438     {
1439         return _uri;
1440     }
1441
1442     /* ------------------------------------------------------------ */
1443     public UserIdentity getUserIdentity()
1444     {
1445         if (_authentication instanceof Authentication.Deferred)
1446             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
1447
1448         if (_authentication instanceof Authentication.User)
1449             return ((Authentication.User)_authentication).getUserIdentity();
1450         return null;
1451     }
1452
1453     /* ------------------------------------------------------------ */
1454     /**
1455      * @return The resolved user Identity, which may be null if the {@link Authentication} is not {@link Authentication.User} (eg.
1456      *         {@link Authentication.Deferred}).
1457      */
1458     public UserIdentity getResolvedUserIdentity()
1459     {
1460         if (_authentication instanceof Authentication.User)
1461             return ((Authentication.User)_authentication).getUserIdentity();
1462         return null;
1463     }
1464
1465     /* ------------------------------------------------------------ */
1466     public UserIdentity.Scope getUserIdentityScope()
1467     {
1468         return _scope;
1469     }
1470
1471     /* ------------------------------------------------------------ */
1472     /*
1473      * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
1474      */
1475     @Override
1476     public Principal getUserPrincipal()
1477     {
1478         if (_authentication instanceof Authentication.Deferred)
1479             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
1480
1481         if (_authentication instanceof Authentication.User)
1482         {
1483             UserIdentity user = ((Authentication.User)_authentication).getUserIdentity();
1484             return user.getUserPrincipal();
1485         }
1486
1487         return null;
1488     }
1489
1490
1491     /* ------------------------------------------------------------ */
1492     public boolean isHandled()
1493     {
1494         return _handled;
1495     }
1496
1497     @Override
1498     public boolean isAsyncStarted()
1499     {
1500        return getHttpChannelState().isAsyncStarted();
1501     }
1502
1503
1504     /* ------------------------------------------------------------ */
1505     @Override
1506     public boolean isAsyncSupported()
1507     {
1508         return _asyncSupported;
1509     }
1510
1511     /* ------------------------------------------------------------ */
1512     /*
1513      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
1514      */
1515     @Override
1516     public boolean isRequestedSessionIdFromCookie()
1517     {
1518         return _requestedSessionId != null && _requestedSessionIdFromCookie;
1519     }
1520
1521     /* ------------------------------------------------------------ */
1522     /*
1523      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
1524      */
1525     @Override
1526     public boolean isRequestedSessionIdFromUrl()
1527     {
1528         return _requestedSessionId != null && !_requestedSessionIdFromCookie;
1529     }
1530
1531     /* ------------------------------------------------------------ */
1532     /*
1533      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
1534      */
1535     @Override
1536     public boolean isRequestedSessionIdFromURL()
1537     {
1538         return _requestedSessionId != null && !_requestedSessionIdFromCookie;
1539     }
1540
1541     /* ------------------------------------------------------------ */
1542     /*
1543      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
1544      */
1545     @Override
1546     public boolean isRequestedSessionIdValid()
1547     {
1548         if (_requestedSessionId == null)
1549             return false;
1550
1551         HttpSession session = getSession(false);
1552         return (session != null && _sessionManager.getSessionIdManager().getClusterId(_requestedSessionId).equals(_sessionManager.getClusterId(session)));
1553     }
1554
1555     /* ------------------------------------------------------------ */
1556     /*
1557      * @see javax.servlet.ServletRequest#isSecure()
1558      */
1559     @Override
1560     public boolean isSecure()
1561     {
1562         return _secure;
1563     }
1564
1565     /* ------------------------------------------------------------ */
1566     public void setSecure(boolean secure)
1567     {
1568         _secure=secure;
1569     }
1570
1571     /* ------------------------------------------------------------ */
1572     /*
1573      * @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
1574      */
1575     @Override
1576     public boolean isUserInRole(String role)
1577     {
1578         if (_authentication instanceof Authentication.Deferred)
1579             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
1580
1581         if (_authentication instanceof Authentication.User)
1582             return ((Authentication.User)_authentication).isUserInRole(_scope,role);
1583         return false;
1584     }
1585
1586     /* ------------------------------------------------------------ */
1587     public HttpSession recoverNewSession(Object key)
1588     {
1589         if (_savedNewSessions == null)
1590             return null;
1591         return _savedNewSessions.get(key);
1592     }
1593
1594     /* ------------------------------------------------------------ */
1595     protected void recycle()
1596     {
1597         if (_context != null)
1598             throw new IllegalStateException("Request in context!");
1599
1600         if (_inputState == __READER)
1601         {
1602             try
1603             {
1604                 int r = _reader.read();
1605                 while (r != -1)
1606                     r = _reader.read();
1607             }
1608             catch (Exception e)
1609             {
1610                 LOG.ignore(e);
1611                 _reader = null;
1612             }
1613         }
1614
1615         _dispatcherType=null;
1616         setAuthentication(Authentication.NOT_CHECKED);
1617         getHttpChannelState().recycle();
1618         if (_async!=null)
1619             _async.reset();
1620         _async=null;
1621         _asyncSupported = true;
1622         _handled = false;
1623         if (_attributes != null)
1624             _attributes.clearAttributes();
1625         _characterEncoding = null;
1626         _contextPath = null;
1627         if (_cookies != null)
1628             _cookies.reset();
1629         _cookiesExtracted = false;
1630         _context = null;
1631         _newContext=false;
1632         _serverName = null;
1633         _httpMethod=null;
1634         _httpMethodString = null;
1635         _pathInfo = null;
1636         _port = 0;
1637         _httpVersion = HttpVersion.HTTP_1_1;
1638         _queryEncoding = null;
1639         _queryString = null;
1640         _requestedSessionId = null;
1641         _requestedSessionIdFromCookie = false;
1642         _secure=false;
1643         _session = null;
1644         _sessionManager = null;
1645         _requestURI = null;
1646         _scope = null;
1647         _scheme = URIUtil.HTTP;
1648         _servletPath = null;
1649         _timeStamp = 0;
1650         _uri = null;
1651         _queryParameters = null;
1652         _contentParameters = null;
1653         _parameters = null;
1654         _paramsExtracted = false;
1655         _inputState = __NONE;
1656
1657         if (_savedNewSessions != null)
1658             _savedNewSessions.clear();
1659         _savedNewSessions=null;
1660         _multiPartInputStream = null;
1661         _remote=null;
1662         _fields.clear();
1663         _input.recycle();
1664     }
1665
1666     /* ------------------------------------------------------------ */
1667     /*
1668      * @see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
1669      */
1670     @Override
1671     public void removeAttribute(String name)
1672     {
1673         Object old_value = _attributes == null?null:_attributes.getAttribute(name);
1674
1675         if (_attributes != null)
1676             _attributes.removeAttribute(name);
1677
1678         if (old_value != null && !_requestAttributeListeners.isEmpty())
1679         {
1680             final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(_context,this,name,old_value);
1681             for (ServletRequestAttributeListener listener : _requestAttributeListeners)
1682                 listener.attributeRemoved(event);
1683         }
1684     }
1685
1686     /* ------------------------------------------------------------ */
1687     public void removeEventListener(final EventListener listener)
1688     {
1689         _requestAttributeListeners.remove(listener);
1690     }
1691
1692     /* ------------------------------------------------------------ */
1693     public void saveNewSession(Object key, HttpSession session)
1694     {
1695         if (_savedNewSessions == null)
1696             _savedNewSessions = new HashMap<>();
1697         _savedNewSessions.put(key,session);
1698     }
1699
1700     /* ------------------------------------------------------------ */
1701     public void setAsyncSupported(boolean supported)
1702     {
1703         _asyncSupported = supported;
1704     }
1705
1706     /* ------------------------------------------------------------ */
1707     /*
1708      * Set a request attribute. if the attribute name is "org.eclipse.jetty.server.server.Request.queryEncoding" then the value is also passed in a call to
1709      * {@link #setQueryEncoding}.
1710      *
1711      * @see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
1712      */
1713     @Override
1714     public void setAttribute(String name, Object value)
1715     {
1716         Object old_value = _attributes == null?null:_attributes.getAttribute(name);
1717
1718         if ("org.eclipse.jetty.server.Request.queryEncoding".equals(name))
1719             setQueryEncoding(value == null?null:value.toString());
1720         else if ("org.eclipse.jetty.server.sendContent".equals(name))
1721             LOG.warn("Deprecated: org.eclipse.jetty.server.sendContent");
1722
1723         if (_attributes == null)
1724             _attributes = new AttributesMap();
1725         _attributes.setAttribute(name,value);
1726
1727         if (!_requestAttributeListeners.isEmpty())
1728         {
1729             final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(_context,this,name,old_value == null?value:old_value);
1730             for (ServletRequestAttributeListener l : _requestAttributeListeners)
1731             {
1732                 if (old_value == null)
1733                     l.attributeAdded(event);
1734                 else if (value == null)
1735                     l.attributeRemoved(event);
1736                 else
1737                     l.attributeReplaced(event);
1738             }
1739         }
1740     }
1741
1742     /* ------------------------------------------------------------ */
1743     /*
1744      */
1745     public void setAttributes(Attributes attributes)
1746     {
1747         _attributes = attributes;
1748     }
1749
1750     /* ------------------------------------------------------------ */
1751
1752     /* ------------------------------------------------------------ */
1753     /**
1754      * Set the authentication.
1755      *
1756      * @param authentication
1757      *            the authentication to set
1758      */
1759     public void setAuthentication(Authentication authentication)
1760     {
1761         _authentication = authentication;
1762     }
1763
1764     /* ------------------------------------------------------------ */
1765     /*
1766      * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
1767      */
1768     @Override
1769     public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException
1770     {
1771         if (_inputState != __NONE)
1772             return;
1773
1774         _characterEncoding = encoding;
1775
1776         // check encoding is supported
1777         if (!StringUtil.isUTF8(encoding))
1778         {
1779             try
1780             {
1781                 Charset.forName(encoding);
1782             }
1783             catch (UnsupportedCharsetException e)
1784             {
1785                 throw new UnsupportedEncodingException(e.getMessage());
1786             }
1787         }
1788     }
1789
1790     /* ------------------------------------------------------------ */
1791     /*
1792      * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
1793      */
1794     public void setCharacterEncodingUnchecked(String encoding)
1795     {
1796         _characterEncoding = encoding;
1797     }
1798
1799     /* ------------------------------------------------------------ */
1800     /*
1801      * @see javax.servlet.ServletRequest#getContentType()
1802      */
1803     public void setContentType(String contentType)
1804     {
1805         _fields.put(HttpHeader.CONTENT_TYPE,contentType);
1806
1807     }
1808
1809     /* ------------------------------------------------------------ */
1810     /**
1811      * Set request context
1812      *
1813      * @param context
1814      *            context object
1815      */
1816     public void setContext(Context context)
1817     {
1818         _newContext = _context != context;
1819         _context = context;
1820     }
1821
1822     /* ------------------------------------------------------------ */
1823     /**
1824      * @return True if this is the first call of {@link #takeNewContext()} since the last
1825      *         {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context)} call.
1826      */
1827     public boolean takeNewContext()
1828     {
1829         boolean nc = _newContext;
1830         _newContext = false;
1831         return nc;
1832     }
1833
1834     /* ------------------------------------------------------------ */
1835     /**
1836      * Sets the "context path" for this request
1837      *
1838      * @see HttpServletRequest#getContextPath()
1839      */
1840     public void setContextPath(String contextPath)
1841     {
1842         _contextPath = contextPath;
1843     }
1844
1845     /* ------------------------------------------------------------ */
1846     /**
1847      * @param cookies
1848      *            The cookies to set.
1849      */
1850     public void setCookies(Cookie[] cookies)
1851     {
1852         if (_cookies == null)
1853             _cookies = new CookieCutter();
1854         _cookies.setCookies(cookies);
1855     }
1856
1857     /* ------------------------------------------------------------ */
1858     public void setDispatcherType(DispatcherType type)
1859     {
1860         _dispatcherType = type;
1861     }
1862
1863     /* ------------------------------------------------------------ */
1864     public void setHandled(boolean h)
1865     {
1866         _handled = h;
1867     }
1868
1869     /* ------------------------------------------------------------ */
1870     /**
1871      * @param method
1872      *            The method to set.
1873      */
1874     public void setMethod(HttpMethod httpMethod, String method)
1875     {
1876         _httpMethod=httpMethod;
1877         _httpMethodString = method;
1878     }
1879
1880     /* ------------------------------------------------------------ */
1881     public boolean isHead()
1882     {
1883         return HttpMethod.HEAD==_httpMethod;
1884     }
1885
1886     /* ------------------------------------------------------------ */
1887     /**
1888      * @param pathInfo
1889      *            The pathInfo to set.
1890      */
1891     public void setPathInfo(String pathInfo)
1892     {
1893         _pathInfo = pathInfo;
1894     }
1895
1896     /* ------------------------------------------------------------ */
1897     /**
1898      * @param version
1899      *            The protocol to set.
1900      */
1901     public void setHttpVersion(HttpVersion version)
1902     {
1903         _httpVersion = version;
1904     }
1905
1906     /* ------------------------------------------------------------ */
1907     /**
1908      * Set the character encoding used for the query string. This call will effect the return of getQueryString and getParamaters. It must be called before any
1909      * getParameter methods.
1910      *
1911      * The request attribute "org.eclipse.jetty.server.server.Request.queryEncoding" may be set as an alternate method of calling setQueryEncoding.
1912      *
1913      * @param queryEncoding
1914      */
1915     public void setQueryEncoding(String queryEncoding)
1916     {
1917         _queryEncoding = queryEncoding;
1918         _queryString = null;
1919     }
1920
1921     /* ------------------------------------------------------------ */
1922     /**
1923      * @param queryString
1924      *            The queryString to set.
1925      */
1926     public void setQueryString(String queryString)
1927     {
1928         _queryString = queryString;
1929         _queryEncoding = null; //assume utf-8
1930     }
1931
1932     /* ------------------------------------------------------------ */
1933     /**
1934      * @param addr
1935      *            The address to set.
1936      */
1937     public void setRemoteAddr(InetSocketAddress addr)
1938     {
1939         _remote = addr;
1940     }
1941
1942     /* ------------------------------------------------------------ */
1943     /**
1944      * @param requestedSessionId
1945      *            The requestedSessionId to set.
1946      */
1947     public void setRequestedSessionId(String requestedSessionId)
1948     {
1949         _requestedSessionId = requestedSessionId;
1950     }
1951
1952     /* ------------------------------------------------------------ */
1953     /**
1954      * @param requestedSessionIdCookie
1955      *            The requestedSessionIdCookie to set.
1956      */
1957     public void setRequestedSessionIdFromCookie(boolean requestedSessionIdCookie)
1958     {
1959         _requestedSessionIdFromCookie = requestedSessionIdCookie;
1960     }
1961
1962     /* ------------------------------------------------------------ */
1963     /**
1964      * @param requestURI
1965      *            The requestURI to set.
1966      */
1967     public void setRequestURI(String requestURI)
1968     {
1969         _requestURI = requestURI;
1970     }
1971
1972     /* ------------------------------------------------------------ */
1973     /**
1974      * @param scheme
1975      *            The scheme to set.
1976      */
1977     public void setScheme(String scheme)
1978     {
1979         _scheme = scheme;
1980     }
1981
1982     /* ------------------------------------------------------------ */
1983     /**
1984      * @param host
1985      *            The host to set.
1986      */
1987     public void setServerName(String host)
1988     {
1989         _serverName = host;
1990     }
1991
1992     /* ------------------------------------------------------------ */
1993     /**
1994      * @param port
1995      *            The port to set.
1996      */
1997     public void setServerPort(int port)
1998     {
1999         _port = port;
2000     }
2001
2002     /* ------------------------------------------------------------ */
2003     /**
2004      * @param servletPath
2005      *            The servletPath to set.
2006      */
2007     public void setServletPath(String servletPath)
2008     {
2009         _servletPath = servletPath;
2010     }
2011
2012     /* ------------------------------------------------------------ */
2013     /**
2014      * @param session
2015      *            The session to set.
2016      */
2017     public void setSession(HttpSession session)
2018     {
2019         _session = session;
2020     }
2021
2022     /* ------------------------------------------------------------ */
2023     /**
2024      * @param sessionManager
2025      *            The sessionManager to set.
2026      */
2027     public void setSessionManager(SessionManager sessionManager)
2028     {
2029         _sessionManager = sessionManager;
2030     }
2031
2032     /* ------------------------------------------------------------ */
2033     public void setTimeStamp(long ts)
2034     {
2035         _timeStamp = ts;
2036     }
2037
2038     /* ------------------------------------------------------------ */
2039     /**
2040      * @param uri
2041      *            The uri to set.
2042      */
2043     public void setUri(HttpURI uri)
2044     {
2045         _uri = uri;
2046     }
2047
2048     /* ------------------------------------------------------------ */
2049     public void setUserIdentityScope(UserIdentity.Scope scope)
2050     {
2051         _scope = scope;
2052     }
2053
2054     /* ------------------------------------------------------------ */
2055     @Override
2056     public AsyncContext startAsync() throws IllegalStateException
2057     {
2058         if (!_asyncSupported)
2059             throw new IllegalStateException("!asyncSupported");
2060         HttpChannelState state = getHttpChannelState();
2061         if (_async==null)
2062             _async=new AsyncContextState(state);
2063         AsyncContextEvent event = new AsyncContextEvent(_context,_async,state,this,this,getResponse());
2064         state.startAsync(event);
2065         return _async;
2066     }
2067
2068     /* ------------------------------------------------------------ */
2069     @Override
2070     public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException
2071     {
2072         if (!_asyncSupported)
2073             throw new IllegalStateException("!asyncSupported");
2074         HttpChannelState state = getHttpChannelState();
2075         if (_async==null)
2076             _async=new AsyncContextState(state);
2077         AsyncContextEvent event = new AsyncContextEvent(_context,_async,state,this,servletRequest,servletResponse);
2078         event.setDispatchContext(getServletContext());
2079         event.setDispatchPath(URIUtil.addPaths(getServletPath(),getPathInfo()));
2080         state.startAsync(event);
2081         return _async;
2082     }
2083
2084     /* ------------------------------------------------------------ */
2085     @Override
2086     public String toString()
2087     {
2088         return String.format("%s%s%s %s%s@%x",
2089                 getClass().getSimpleName(),
2090                 _handled ? "[" : "(",
2091                 getMethod(),
2092                 _uri,
2093                 _handled ? "]" : ")",
2094                 hashCode());
2095     }
2096
2097     /* ------------------------------------------------------------ */
2098     @Override
2099     public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
2100     {
2101         if (_authentication instanceof Authentication.Deferred)
2102         {
2103             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this,response));
2104             return !(_authentication instanceof Authentication.ResponseSent);
2105         }
2106         response.sendError(HttpStatus.UNAUTHORIZED_401);
2107         return false;
2108     }
2109
2110     /* ------------------------------------------------------------ */
2111     @Override
2112     public Part getPart(String name) throws IOException, ServletException
2113     {
2114         getParts();
2115
2116         return _multiPartInputStream.getPart(name);
2117     }
2118
2119     /* ------------------------------------------------------------ */
2120     @Override
2121     public Collection<Part> getParts() throws IOException, ServletException
2122     {
2123         if (getContentType() == null || !getContentType().startsWith("multipart/form-data"))
2124             throw new ServletException("Content-Type != multipart/form-data");
2125         return getParts(null);
2126     }
2127
2128     private Collection<Part> getParts(MultiMap<String> params) throws IOException, ServletException
2129     {
2130         if (_multiPartInputStream == null)
2131             _multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM);
2132
2133         if (_multiPartInputStream == null)
2134         {
2135             MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
2136
2137             if (config == null)
2138                 throw new IllegalStateException("No multipart config for servlet");
2139
2140             _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(),
2141                                                              getContentType(), config,
2142                                                              (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
2143
2144             setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
2145             setAttribute(__MULTIPART_CONTEXT, _context);
2146             Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
2147             ByteArrayOutputStream os = null;
2148             for (Part p:parts)
2149             {
2150                 MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p;
2151                 if (mp.getContentDispositionFilename() == null)
2152                 {
2153                     // Servlet Spec 3.0 pg 23, parts without filename must be put into params.
2154                     String charset = null;
2155                     if (mp.getContentType() != null)
2156                         charset = MimeTypes.getCharsetFromContentType(mp.getContentType());
2157
2158                     try (InputStream is = mp.getInputStream())
2159                     {
2160                         if (os == null)
2161                             os = new ByteArrayOutputStream();
2162                         IO.copy(is, os);
2163                         String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset));
2164                         if (_contentParameters == null)
2165                             _contentParameters = params == null ? new MultiMap<String>() : params;
2166                         _contentParameters.add(mp.getName(), content);
2167                     }
2168                     os.reset();
2169                 }
2170             }
2171         }
2172
2173         return _multiPartInputStream.getParts();
2174     }
2175
2176     /* ------------------------------------------------------------ */
2177     @Override
2178     public void login(String username, String password) throws ServletException
2179     {
2180         if (_authentication instanceof Authentication.Deferred)
2181         {
2182             _authentication=((Authentication.Deferred)_authentication).login(username,password,this);
2183             if (_authentication == null)
2184                 throw new Authentication.Failed("Authentication failed for username '"+username+"'");
2185         }
2186         else
2187         {
2188             throw new Authentication.Failed("Authenticated failed for username '"+username+"'. Already authenticated as "+_authentication);
2189         }
2190     }
2191
2192     /* ------------------------------------------------------------ */
2193     @Override
2194     public void logout() throws ServletException
2195     {
2196         if (_authentication instanceof Authentication.User)
2197             ((Authentication.User)_authentication).logout();
2198         _authentication=Authentication.UNAUTHENTICATED;
2199     }
2200
2201     public void mergeQueryParameters(String newQuery, boolean updateQueryString)
2202     {
2203         MultiMap<String> newQueryParams = new MultiMap<>();
2204         // Have to assume ENCODING because we can't know otherwise.
2205         UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING, -1);
2206
2207         MultiMap<String> oldQueryParams = _queryParameters;
2208         if (oldQueryParams == null && _queryString != null)
2209         {
2210             oldQueryParams = new MultiMap<>();
2211             UrlEncoded.decodeTo(_queryString, oldQueryParams, getQueryEncoding(), -1);
2212         }
2213
2214         MultiMap<String> mergedQueryParams = newQueryParams;
2215         if (oldQueryParams != null)
2216         {
2217             // Parameters values are accumulated.
2218             mergedQueryParams = new MultiMap<>(newQueryParams);
2219             mergedQueryParams.addAllValues(oldQueryParams);
2220         }
2221
2222         setQueryParameters(mergedQueryParams);
2223         resetParameters();
2224
2225         if (updateQueryString)
2226         {
2227             // Build the new merged query string, parameters in the
2228             // new query string hide parameters in the old query string.
2229             StringBuilder mergedQuery = new StringBuilder(newQuery);
2230             for (Map.Entry<String, List<String>> entry : mergedQueryParams.entrySet())
2231             {
2232                 if (newQueryParams.containsKey(entry.getKey()))
2233                     continue;
2234                 for (String value : entry.getValue())
2235                     mergedQuery.append("&").append(entry.getKey()).append("=").append(value);
2236             }
2237
2238             setQueryString(mergedQuery.toString());
2239         }
2240     }
2241
2242     /**
2243      * @see javax.servlet.http.HttpServletRequest#upgrade(java.lang.Class)
2244      */
2245     @Override
2246     public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException
2247     {
2248         if (getContext() == null)
2249             throw new ServletException ("Unable to instantiate "+handlerClass);
2250
2251         try
2252         {
2253             //Instantiate an instance and inject it
2254             T h = getContext().createInstance(handlerClass);
2255
2256             //TODO handle the rest of the upgrade process
2257
2258             return h;
2259         }
2260         catch (Exception e)
2261         {
2262             if (e instanceof ServletException)
2263                 throw (ServletException)e;
2264             throw new ServletException(e);
2265         }
2266     }
2267 }