View Javadoc

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