View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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      * @see javax.servlet.ServletRequest#getRemoteAddr()
993      */
994     @Override
995     public String getRemoteAddr()
996     {
997         InetSocketAddress remote=_remote;
998         if (remote==null)
999             remote=_channel.getRemoteAddress();
1000         
1001         if (remote==null)
1002             return "";
1003         
1004         InetAddress address = remote.getAddress();
1005         if (address==null)
1006             return remote.getHostString();
1007         
1008         return address.getHostAddress();
1009     }
1010 
1011     /* ------------------------------------------------------------ */
1012     /*
1013      * @see javax.servlet.ServletRequest#getRemoteHost()
1014      */
1015     @Override
1016     public String getRemoteHost()
1017     {
1018         InetSocketAddress remote=_remote;
1019         if (remote==null)
1020             remote=_channel.getRemoteAddress();
1021         return remote==null?"":remote.getHostString();
1022     }
1023 
1024     /* ------------------------------------------------------------ */
1025     /*
1026      * @see javax.servlet.ServletRequest#getRemotePort()
1027      */
1028     @Override
1029     public int getRemotePort()
1030     {
1031         InetSocketAddress remote=_remote;
1032         if (remote==null)
1033             remote=_channel.getRemoteAddress();
1034         return remote==null?0:remote.getPort();
1035     }
1036 
1037     /* ------------------------------------------------------------ */
1038     /*
1039      * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
1040      */
1041     @Override
1042     public String getRemoteUser()
1043     {
1044         Principal p = getUserPrincipal();
1045         if (p == null)
1046             return null;
1047         return p.getName();
1048     }
1049 
1050     /* ------------------------------------------------------------ */
1051     /*
1052      * @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
1053      */
1054     @Override
1055     public RequestDispatcher getRequestDispatcher(String path)
1056     {
1057         if (path == null || _context == null)
1058             return null;
1059 
1060         // handle relative path
1061         if (!path.startsWith("/"))
1062         {
1063             String relTo = URIUtil.addPaths(_servletPath,_pathInfo);
1064             int slash = relTo.lastIndexOf("/");
1065             if (slash > 1)
1066                 relTo = relTo.substring(0,slash + 1);
1067             else
1068                 relTo = "/";
1069             path = URIUtil.addPaths(relTo,path);
1070         }
1071 
1072         return _context.getRequestDispatcher(path);
1073     }
1074 
1075     /* ------------------------------------------------------------ */
1076     /*
1077      * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
1078      */
1079     @Override
1080     public String getRequestedSessionId()
1081     {
1082         return _requestedSessionId;
1083     }
1084 
1085     /* ------------------------------------------------------------ */
1086     /*
1087      * @see javax.servlet.http.HttpServletRequest#getRequestURI()
1088      */
1089     @Override
1090     public String getRequestURI()
1091     {
1092         if (_requestURI == null && _uri != null)
1093             _requestURI = _uri.getPathAndParam();
1094         return _requestURI;
1095     }
1096 
1097     /* ------------------------------------------------------------ */
1098     /*
1099      * @see javax.servlet.http.HttpServletRequest#getRequestURL()
1100      */
1101     @Override
1102     public StringBuffer getRequestURL()
1103     {
1104         final StringBuffer url = new StringBuffer(128);
1105         URIUtil.appendSchemeHostPort(url,getScheme(),getServerName(),getServerPort());
1106         url.append(getRequestURI());
1107         return url;
1108     }
1109 
1110     /* ------------------------------------------------------------ */
1111     public Response getResponse()
1112     {
1113         return _channel.getResponse();
1114     }
1115 
1116     /* ------------------------------------------------------------ */
1117     /**
1118      * 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
1119      * path.
1120      * <p>
1121      * 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.
1122      *
1123      * This method is useful for creating redirect messages and for reporting errors.
1124      *
1125      * @return "scheme://host:port"
1126      */
1127     public StringBuilder getRootURL()
1128     {
1129         StringBuilder url = new StringBuilder(128);
1130         URIUtil.appendSchemeHostPort(url,getScheme(),getServerName(),getServerPort());
1131         return url;
1132     }
1133 
1134     /* ------------------------------------------------------------ */
1135     /*
1136      * @see javax.servlet.ServletRequest#getScheme()
1137      */
1138     @Override
1139     public String getScheme()
1140     {
1141         return _scheme;
1142     }
1143 
1144     /* ------------------------------------------------------------ */
1145     /*
1146      * @see javax.servlet.ServletRequest#getServerName()
1147      */
1148     @Override
1149     public String getServerName()
1150     {
1151         // Return already determined host
1152         if (_serverName != null)
1153             return _serverName;
1154 
1155         if (_uri == null)
1156             throw new IllegalStateException("No uri");
1157 
1158         // Return host from absolute URI
1159         _serverName = _uri.getHost();
1160         if (_serverName != null)
1161         {
1162             _port = _uri.getPort();
1163             return _serverName;
1164         }
1165 
1166         // Return host from header field
1167         String hostPort = _fields.getStringField(HttpHeader.HOST);
1168         
1169         _port=0;
1170         if (hostPort != null)
1171         {
1172             int len=hostPort.length();
1173             loop: for (int i = len; i-- > 0;)
1174             {
1175                 char c2 = (char)(0xff & hostPort.charAt(i));
1176                 switch (c2)
1177                 {
1178                     case ']':
1179                         break loop;
1180 
1181                     case ':':
1182                         try
1183                         {
1184                             len=i;
1185                             _port = StringUtil.toInt(hostPort.substring(i+1));
1186                         }
1187                         catch (NumberFormatException e)
1188                         {
1189                             LOG.warn(e);
1190                             _serverName=hostPort;
1191                             _port=0;
1192                             return _serverName;
1193                         }
1194                         break loop;
1195                 }
1196             }
1197             if (hostPort.charAt(0)=='[')
1198             {
1199                 if (hostPort.charAt(len-1)!=']') 
1200                 {
1201                     LOG.warn("Bad IPv6 "+hostPort);
1202                     _serverName=hostPort;
1203                     _port=0;
1204                     return _serverName;
1205                 }
1206                 _serverName = hostPort.substring(1,len-1);
1207             }
1208             else if (len==hostPort.length())
1209                 _serverName=hostPort;
1210             else
1211                 _serverName = hostPort.substring(0,len);
1212 
1213             return _serverName;
1214         }
1215 
1216         // Return host from connection
1217         if (_channel != null)
1218         {
1219             _serverName = getLocalName();
1220             _port = getLocalPort();
1221             if (_serverName != null && !StringUtil.ALL_INTERFACES.equals(_serverName))
1222                 return _serverName;
1223         }
1224 
1225         // Return the local host
1226         try
1227         {
1228             _serverName = InetAddress.getLocalHost().getHostAddress();
1229         }
1230         catch (java.net.UnknownHostException e)
1231         {
1232             LOG.ignore(e);
1233         }
1234         return _serverName;
1235     }
1236 
1237     /* ------------------------------------------------------------ */
1238     /*
1239      * @see javax.servlet.ServletRequest#getServerPort()
1240      */
1241     @Override
1242     public int getServerPort()
1243     {
1244         if (_port <= 0)
1245         {
1246             if (_serverName == null)
1247                 getServerName();
1248 
1249             if (_port <= 0)
1250             {
1251                 if (_serverName != null && _uri != null)
1252                     _port = _uri.getPort();
1253                 else
1254                 {
1255                     InetSocketAddress local = _channel.getLocalAddress();
1256                     _port = local == null?0:local.getPort();
1257                 }
1258             }
1259         }
1260 
1261         if (_port <= 0)
1262         {
1263             if (getScheme().equalsIgnoreCase(URIUtil.HTTPS))
1264                 return 443;
1265             return 80;
1266         }
1267         return _port;
1268     }
1269 
1270     /* ------------------------------------------------------------ */
1271     @Override
1272     public ServletContext getServletContext()
1273     {
1274         return _context;
1275     }
1276 
1277     /* ------------------------------------------------------------ */
1278     /*
1279      */
1280     public String getServletName()
1281     {
1282         if (_scope != null)
1283             return _scope.getName();
1284         return null;
1285     }
1286 
1287     /* ------------------------------------------------------------ */
1288     /*
1289      * @see javax.servlet.http.HttpServletRequest#getServletPath()
1290      */
1291     @Override
1292     public String getServletPath()
1293     {
1294         if (_servletPath == null)
1295             _servletPath = "";
1296         return _servletPath;
1297     }
1298 
1299     /* ------------------------------------------------------------ */
1300     public ServletResponse getServletResponse()
1301     {
1302         return _channel.getResponse();
1303     }
1304 
1305     /* ------------------------------------------------------------ */
1306     /*
1307      * Add @override when 3.1 api is available
1308      */
1309     public String changeSessionId()
1310     {
1311         HttpSession session = getSession(false);
1312         if (session == null)
1313             throw new IllegalStateException("No session");
1314 
1315         if (session instanceof AbstractSession)
1316         {
1317             AbstractSession abstractSession =  ((AbstractSession)session);
1318             abstractSession.renewId(this);
1319             if (getRemoteUser() != null)
1320                 abstractSession.setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
1321             if (abstractSession.isIdChanged())
1322                 _channel.getResponse().addCookie(_sessionManager.getSessionCookie(abstractSession, getContextPath(), isSecure()));
1323         }
1324 
1325         return session.getId();
1326     }
1327 
1328     /* ------------------------------------------------------------ */
1329     /*
1330      * @see javax.servlet.http.HttpServletRequest#getSession()
1331      */
1332     @Override
1333     public HttpSession getSession()
1334     {
1335         return getSession(true);
1336     }
1337 
1338     /* ------------------------------------------------------------ */
1339     /*
1340      * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
1341      */
1342     @Override
1343     public HttpSession getSession(boolean create)
1344     {
1345         if (_session != null)
1346         {
1347             if (_sessionManager != null && !_sessionManager.isValid(_session))
1348                 _session = null;
1349             else
1350                 return _session;
1351         }
1352 
1353         if (!create)
1354             return null;
1355 
1356         if (_sessionManager == null)
1357             throw new IllegalStateException("No SessionManager");
1358 
1359         _session = _sessionManager.newHttpSession(this);
1360         HttpCookie cookie = _sessionManager.getSessionCookie(_session,getContextPath(),isSecure());
1361         if (cookie != null)
1362             _channel.getResponse().addCookie(cookie);
1363 
1364         return _session;
1365     }
1366 
1367     /* ------------------------------------------------------------ */
1368     /**
1369      * @return Returns the sessionManager.
1370      */
1371     public SessionManager getSessionManager()
1372     {
1373         return _sessionManager;
1374     }
1375 
1376     /* ------------------------------------------------------------ */
1377     /**
1378      * Get Request TimeStamp
1379      *
1380      * @return The time that the request was received.
1381      */
1382     public long getTimeStamp()
1383     {
1384         return _timeStamp;
1385     }
1386 
1387     /* ------------------------------------------------------------ */
1388     /**
1389      * @return Returns the uri.
1390      */
1391     public HttpURI getUri()
1392     {
1393         return _uri;
1394     }
1395 
1396     /* ------------------------------------------------------------ */
1397     public UserIdentity getUserIdentity()
1398     {
1399         if (_authentication instanceof Authentication.Deferred)
1400             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
1401 
1402         if (_authentication instanceof Authentication.User)
1403             return ((Authentication.User)_authentication).getUserIdentity();
1404         return null;
1405     }
1406 
1407     /* ------------------------------------------------------------ */
1408     /**
1409      * @return The resolved user Identity, which may be null if the {@link Authentication} is not {@link Authentication.User} (eg.
1410      *         {@link Authentication.Deferred}).
1411      */
1412     public UserIdentity getResolvedUserIdentity()
1413     {
1414         if (_authentication instanceof Authentication.User)
1415             return ((Authentication.User)_authentication).getUserIdentity();
1416         return null;
1417     }
1418 
1419     /* ------------------------------------------------------------ */
1420     public UserIdentity.Scope getUserIdentityScope()
1421     {
1422         return _scope;
1423     }
1424 
1425     /* ------------------------------------------------------------ */
1426     /*
1427      * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
1428      */
1429     @Override
1430     public Principal getUserPrincipal()
1431     {
1432         if (_authentication instanceof Authentication.Deferred)
1433             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
1434 
1435         if (_authentication instanceof Authentication.User)
1436         {
1437             UserIdentity user = ((Authentication.User)_authentication).getUserIdentity();
1438             return user.getUserPrincipal();
1439         }
1440         
1441         return null;
1442     }
1443 
1444 
1445     /* ------------------------------------------------------------ */
1446     public boolean isHandled()
1447     {
1448         return _handled;
1449     }
1450 
1451     @Override
1452     public boolean isAsyncStarted()
1453     {
1454        return getHttpChannelState().isAsyncStarted();
1455     }
1456 
1457 
1458     /* ------------------------------------------------------------ */
1459     @Override
1460     public boolean isAsyncSupported()
1461     {
1462         return _asyncSupported;
1463     }
1464 
1465     /* ------------------------------------------------------------ */
1466     /*
1467      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
1468      */
1469     @Override
1470     public boolean isRequestedSessionIdFromCookie()
1471     {
1472         return _requestedSessionId != null && _requestedSessionIdFromCookie;
1473     }
1474 
1475     /* ------------------------------------------------------------ */
1476     /*
1477      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
1478      */
1479     @Override
1480     public boolean isRequestedSessionIdFromUrl()
1481     {
1482         return _requestedSessionId != null && !_requestedSessionIdFromCookie;
1483     }
1484 
1485     /* ------------------------------------------------------------ */
1486     /*
1487      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
1488      */
1489     @Override
1490     public boolean isRequestedSessionIdFromURL()
1491     {
1492         return _requestedSessionId != null && !_requestedSessionIdFromCookie;
1493     }
1494 
1495     /* ------------------------------------------------------------ */
1496     /*
1497      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
1498      */
1499     @Override
1500     public boolean isRequestedSessionIdValid()
1501     {
1502         if (_requestedSessionId == null)
1503             return false;
1504 
1505         HttpSession session = getSession(false);
1506         return (session != null && _sessionManager.getSessionIdManager().getClusterId(_requestedSessionId).equals(_sessionManager.getClusterId(session)));
1507     }
1508 
1509     /* ------------------------------------------------------------ */
1510     /*
1511      * @see javax.servlet.ServletRequest#isSecure()
1512      */
1513     @Override
1514     public boolean isSecure()
1515     {
1516         return _secure;
1517     }
1518 
1519     /* ------------------------------------------------------------ */
1520     public void setSecure(boolean secure)
1521     {
1522         _secure=secure;
1523     }
1524 
1525     /* ------------------------------------------------------------ */
1526     /*
1527      * @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
1528      */
1529     @Override
1530     public boolean isUserInRole(String role)
1531     {
1532         if (_authentication instanceof Authentication.Deferred)
1533             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
1534 
1535         if (_authentication instanceof Authentication.User)
1536             return ((Authentication.User)_authentication).isUserInRole(_scope,role);
1537         return false;
1538     }
1539 
1540     /* ------------------------------------------------------------ */
1541     public HttpSession recoverNewSession(Object key)
1542     {
1543         if (_savedNewSessions == null)
1544             return null;
1545         return _savedNewSessions.get(key);
1546     }
1547 
1548     /* ------------------------------------------------------------ */
1549     protected void recycle()
1550     {
1551         if (_context != null)
1552             throw new IllegalStateException("Request in context!");
1553         
1554         if (_inputState == __READER)
1555         {
1556             try
1557             {
1558                 int r = _reader.read();
1559                 while (r != -1)
1560                     r = _reader.read();
1561             }
1562             catch (Exception e)
1563             {
1564                 LOG.ignore(e);
1565                 _reader = null;
1566             }
1567         }
1568 
1569         _dispatcherType=null;
1570         setAuthentication(Authentication.NOT_CHECKED);
1571         getHttpChannelState().recycle();
1572         if (_async!=null)
1573             _async.reset();
1574         _async=null;
1575         _asyncSupported = true;
1576         _handled = false;
1577         if (_attributes != null)
1578             _attributes.clearAttributes();
1579         _characterEncoding = null;
1580         _contextPath = null;
1581         if (_cookies != null)
1582             _cookies.reset();
1583         _cookiesExtracted = false;
1584         _context = null;
1585         _newContext=false;
1586         _serverName = null;
1587         _httpMethod=null;
1588         _httpMethodString = null;
1589         _pathInfo = null;
1590         _port = 0;
1591         _httpVersion = HttpVersion.HTTP_1_1;
1592         _queryEncoding = null;
1593         _queryString = null;
1594         _requestedSessionId = null;
1595         _requestedSessionIdFromCookie = false;
1596         _secure=false;
1597         _session = null;
1598         _sessionManager = null;
1599         _requestURI = null;
1600         _scope = null;
1601         _scheme = URIUtil.HTTP;
1602         _servletPath = null;
1603         _timeStamp = 0;
1604         _uri = null;
1605         if (_baseParameters != null)
1606             _baseParameters.clear();
1607         _parameters = null;
1608         _paramsExtracted = false;
1609         _inputState = __NONE;
1610 
1611         if (_savedNewSessions != null)
1612             _savedNewSessions.clear();
1613         _savedNewSessions=null;
1614         _multiPartInputStream = null;
1615         _remote=null;
1616         _fields.clear();
1617         _input.recycle();
1618     }
1619 
1620     /* ------------------------------------------------------------ */
1621     /*
1622      * @see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
1623      */
1624     @Override
1625     public void removeAttribute(String name)
1626     {
1627         Object old_value = _attributes == null?null:_attributes.getAttribute(name);
1628 
1629         if (_attributes != null)
1630             _attributes.removeAttribute(name);
1631 
1632         if (old_value != null && !_requestAttributeListeners.isEmpty())
1633         {
1634             final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(_context,this,name,old_value);
1635             for (ServletRequestAttributeListener listener : _requestAttributeListeners)
1636                 listener.attributeRemoved(event);
1637         }
1638     }
1639 
1640     /* ------------------------------------------------------------ */
1641     public void removeEventListener(final EventListener listener)
1642     {
1643         _requestAttributeListeners.remove(listener);
1644     }
1645 
1646     /* ------------------------------------------------------------ */
1647     public void saveNewSession(Object key, HttpSession session)
1648     {
1649         if (_savedNewSessions == null)
1650             _savedNewSessions = new HashMap<>();
1651         _savedNewSessions.put(key,session);
1652     }
1653 
1654     /* ------------------------------------------------------------ */
1655     public void setAsyncSupported(boolean supported)
1656     {
1657         _asyncSupported = supported;
1658     }
1659 
1660     /* ------------------------------------------------------------ */
1661     /*
1662      * 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
1663      * {@link #setQueryEncoding}.
1664      *
1665      * @see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
1666      */
1667     @Override
1668     public void setAttribute(String name, Object value)
1669     {
1670         Object old_value = _attributes == null?null:_attributes.getAttribute(name);
1671 
1672         if ("org.eclipse.jetty.server.Request.queryEncoding".equals(name))
1673             setQueryEncoding(value == null?null:value.toString());
1674         else if ("org.eclipse.jetty.server.sendContent".equals(name))
1675             LOG.warn("Deprecated: org.eclipse.jetty.server.sendContent");
1676         
1677         if (_attributes == null)
1678             _attributes = new AttributesMap();
1679         _attributes.setAttribute(name,value);
1680 
1681         if (!_requestAttributeListeners.isEmpty())
1682         {
1683             final ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(_context,this,name,old_value == null?value:old_value);
1684             for (ServletRequestAttributeListener l : _requestAttributeListeners)
1685             {
1686                 if (old_value == null)
1687                     l.attributeAdded(event);
1688                 else if (value == null)
1689                     l.attributeRemoved(event);
1690                 else
1691                     l.attributeReplaced(event);
1692             }
1693         }
1694     }
1695 
1696     /* ------------------------------------------------------------ */
1697     /*
1698      */
1699     public void setAttributes(Attributes attributes)
1700     {
1701         _attributes = attributes;
1702     }
1703 
1704     /* ------------------------------------------------------------ */
1705 
1706     /* ------------------------------------------------------------ */
1707     /**
1708      * Set the authentication.
1709      *
1710      * @param authentication
1711      *            the authentication to set
1712      */
1713     public void setAuthentication(Authentication authentication)
1714     {
1715         _authentication = authentication;
1716     }
1717 
1718     /* ------------------------------------------------------------ */
1719     /*
1720      * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
1721      */
1722     @Override
1723     public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException
1724     {
1725         if (_inputState != __NONE)
1726             return;
1727 
1728         _characterEncoding = encoding;
1729 
1730         // check encoding is supported
1731         if (!StringUtil.isUTF8(encoding))
1732         {
1733             try
1734             {
1735                 Charset.forName(encoding);
1736             }
1737             catch (UnsupportedCharsetException e)
1738             {
1739                 throw new UnsupportedEncodingException(e.getMessage());
1740             }
1741         }
1742     }
1743 
1744     /* ------------------------------------------------------------ */
1745     /*
1746      * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
1747      */
1748     public void setCharacterEncodingUnchecked(String encoding)
1749     {
1750         _characterEncoding = encoding;
1751     }
1752 
1753     /* ------------------------------------------------------------ */
1754     /*
1755      * @see javax.servlet.ServletRequest#getContentType()
1756      */
1757     public void setContentType(String contentType)
1758     {
1759         _fields.put(HttpHeader.CONTENT_TYPE,contentType);
1760 
1761     }
1762 
1763     /* ------------------------------------------------------------ */
1764     /**
1765      * Set request context
1766      *
1767      * @param context
1768      *            context object
1769      */
1770     public void setContext(Context context)
1771     {
1772         _newContext = _context != context;
1773         _context = context;
1774     }
1775 
1776     /* ------------------------------------------------------------ */
1777     /**
1778      * @return True if this is the first call of {@link #takeNewContext()} since the last
1779      *         {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context)} call.
1780      */
1781     public boolean takeNewContext()
1782     {
1783         boolean nc = _newContext;
1784         _newContext = false;
1785         return nc;
1786     }
1787 
1788     /* ------------------------------------------------------------ */
1789     /**
1790      * Sets the "context path" for this request
1791      *
1792      * @see HttpServletRequest#getContextPath()
1793      */
1794     public void setContextPath(String contextPath)
1795     {
1796         _contextPath = contextPath;
1797     }
1798 
1799     /* ------------------------------------------------------------ */
1800     /**
1801      * @param cookies
1802      *            The cookies to set.
1803      */
1804     public void setCookies(Cookie[] cookies)
1805     {
1806         if (_cookies == null)
1807             _cookies = new CookieCutter();
1808         _cookies.setCookies(cookies);
1809     }
1810 
1811     /* ------------------------------------------------------------ */
1812     public void setDispatcherType(DispatcherType type)
1813     {
1814         _dispatcherType = type;
1815     }
1816 
1817     /* ------------------------------------------------------------ */
1818     public void setHandled(boolean h)
1819     {
1820         _handled = h;
1821         Response r=getResponse();
1822         if (_handled && r.getStatus()==0)
1823             r.setStatus(200);
1824     }
1825 
1826     /* ------------------------------------------------------------ */
1827     /**
1828      * @param method
1829      *            The method to set.
1830      */
1831     public void setMethod(HttpMethod httpMethod, String method)
1832     {
1833         _httpMethod=httpMethod;
1834         _httpMethodString = method;
1835     }
1836 
1837     /* ------------------------------------------------------------ */
1838     public boolean isHead()
1839     {
1840         return HttpMethod.HEAD==_httpMethod;
1841     }
1842 
1843     /* ------------------------------------------------------------ */
1844     /**
1845      * @param parameters
1846      *            The parameters to set.
1847      */
1848     public void setParameters(MultiMap<String> parameters)
1849     {
1850         _parameters = (parameters == null)?_baseParameters:parameters;
1851         if (_paramsExtracted && _parameters == null)
1852             throw new IllegalStateException();
1853     }
1854 
1855     /* ------------------------------------------------------------ */
1856     /**
1857      * @param pathInfo
1858      *            The pathInfo to set.
1859      */
1860     public void setPathInfo(String pathInfo)
1861     {
1862         _pathInfo = pathInfo;
1863     }
1864 
1865     /* ------------------------------------------------------------ */
1866     /**
1867      * @param version
1868      *            The protocol to set.
1869      */
1870     public void setHttpVersion(HttpVersion version)
1871     {
1872         _httpVersion = version;
1873     }
1874 
1875     /* ------------------------------------------------------------ */
1876     /**
1877      * 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
1878      * getParameter methods.
1879      *
1880      * The request attribute "org.eclipse.jetty.server.server.Request.queryEncoding" may be set as an alternate method of calling setQueryEncoding.
1881      *
1882      * @param queryEncoding
1883      */
1884     public void setQueryEncoding(String queryEncoding)
1885     {
1886         _queryEncoding = queryEncoding;
1887         _queryString = null;
1888     }
1889 
1890     /* ------------------------------------------------------------ */
1891     /**
1892      * @param queryString
1893      *            The queryString to set.
1894      */
1895     public void setQueryString(String queryString)
1896     {
1897         _queryString = queryString;
1898         _queryEncoding = null; //assume utf-8
1899     }
1900 
1901     /* ------------------------------------------------------------ */
1902     /**
1903      * @param addr
1904      *            The address to set.
1905      */
1906     public void setRemoteAddr(InetSocketAddress addr)
1907     {
1908         _remote = addr;
1909     }
1910 
1911     /* ------------------------------------------------------------ */
1912     /**
1913      * @param requestedSessionId
1914      *            The requestedSessionId to set.
1915      */
1916     public void setRequestedSessionId(String requestedSessionId)
1917     {
1918         _requestedSessionId = requestedSessionId;
1919     }
1920 
1921     /* ------------------------------------------------------------ */
1922     /**
1923      * @param requestedSessionIdCookie
1924      *            The requestedSessionIdCookie to set.
1925      */
1926     public void setRequestedSessionIdFromCookie(boolean requestedSessionIdCookie)
1927     {
1928         _requestedSessionIdFromCookie = requestedSessionIdCookie;
1929     }
1930 
1931     /* ------------------------------------------------------------ */
1932     /**
1933      * @param requestURI
1934      *            The requestURI to set.
1935      */
1936     public void setRequestURI(String requestURI)
1937     {
1938         _requestURI = requestURI;
1939     }
1940 
1941     /* ------------------------------------------------------------ */
1942     /**
1943      * @param scheme
1944      *            The scheme to set.
1945      */
1946     public void setScheme(String scheme)
1947     {
1948         _scheme = scheme;
1949     }
1950 
1951     /* ------------------------------------------------------------ */
1952     /**
1953      * @param host
1954      *            The host to set.
1955      */
1956     public void setServerName(String host)
1957     {
1958         _serverName = host;
1959     }
1960 
1961     /* ------------------------------------------------------------ */
1962     /**
1963      * @param port
1964      *            The port to set.
1965      */
1966     public void setServerPort(int port)
1967     {
1968         _port = port;
1969     }
1970 
1971     /* ------------------------------------------------------------ */
1972     /**
1973      * @param servletPath
1974      *            The servletPath to set.
1975      */
1976     public void setServletPath(String servletPath)
1977     {
1978         _servletPath = servletPath;
1979     }
1980 
1981     /* ------------------------------------------------------------ */
1982     /**
1983      * @param session
1984      *            The session to set.
1985      */
1986     public void setSession(HttpSession session)
1987     {
1988         _session = session;
1989     }
1990 
1991     /* ------------------------------------------------------------ */
1992     /**
1993      * @param sessionManager
1994      *            The sessionManager to set.
1995      */
1996     public void setSessionManager(SessionManager sessionManager)
1997     {
1998         _sessionManager = sessionManager;
1999     }
2000 
2001     /* ------------------------------------------------------------ */
2002     public void setTimeStamp(long ts)
2003     {
2004         _timeStamp = ts;
2005     }
2006 
2007     /* ------------------------------------------------------------ */
2008     /**
2009      * @param uri
2010      *            The uri to set.
2011      */
2012     public void setUri(HttpURI uri)
2013     {
2014         _uri = uri;
2015     }
2016 
2017     /* ------------------------------------------------------------ */
2018     public void setUserIdentityScope(UserIdentity.Scope scope)
2019     {
2020         _scope = scope;
2021     }
2022 
2023     /* ------------------------------------------------------------ */
2024     @Override
2025     public AsyncContext startAsync() throws IllegalStateException
2026     {
2027         if (!_asyncSupported)
2028             throw new IllegalStateException("!asyncSupported");
2029         HttpChannelState state = getHttpChannelState();
2030         if (_async==null)
2031             _async=new AsyncContextState(state);
2032         AsyncContextEvent event = new AsyncContextEvent(_context,_async,state,this,this,getResponse());
2033         state.startAsync(event);
2034         return _async;
2035     }
2036 
2037     /* ------------------------------------------------------------ */
2038     @Override
2039     public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException
2040     {
2041         if (!_asyncSupported)
2042             throw new IllegalStateException("!asyncSupported");
2043         HttpChannelState state = getHttpChannelState();
2044         if (_async==null)
2045             _async=new AsyncContextState(state);
2046         AsyncContextEvent event = new AsyncContextEvent(_context,_async,state,this,servletRequest,servletResponse);
2047         event.setDispatchTarget(getServletContext(),URIUtil.addPaths(getServletPath(),getPathInfo()));
2048         state.startAsync(event);
2049         return _async;
2050     }
2051 
2052     /* ------------------------------------------------------------ */
2053     @Override
2054     public String toString()
2055     {
2056         return (_handled?"[":"(") + getMethod() + " " + _uri + (_handled?"]@":")@") + hashCode() + " " + super.toString();
2057     }
2058 
2059     /* ------------------------------------------------------------ */
2060     @Override
2061     public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
2062     {
2063         if (_authentication instanceof Authentication.Deferred)
2064         {
2065             setAuthentication(((Authentication.Deferred)_authentication).authenticate(this,response));
2066             return !(_authentication instanceof Authentication.ResponseSent);
2067         }
2068         response.sendError(HttpStatus.UNAUTHORIZED_401);
2069         return false;
2070     }
2071 
2072     /* ------------------------------------------------------------ */
2073     @Override
2074     public Part getPart(String name) throws IOException, ServletException
2075     {
2076         getParts();
2077 
2078         return _multiPartInputStream.getPart(name);
2079     }
2080 
2081     /* ------------------------------------------------------------ */
2082     @Override
2083     public Collection<Part> getParts() throws IOException, ServletException
2084     {
2085         if (getContentType() == null || !getContentType().startsWith("multipart/form-data"))
2086             throw new ServletException("Content-Type != multipart/form-data");
2087 
2088         if (_multiPartInputStream == null)
2089             _multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM);
2090         
2091         if (_multiPartInputStream == null)
2092         {
2093             MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
2094             
2095             if (config == null)
2096                 throw new IllegalStateException("No multipart config for servlet");
2097             
2098             _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(),
2099                                                              getContentType(), config, 
2100                                                              (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
2101             
2102             setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
2103             setAttribute(__MULTIPART_CONTEXT, _context);
2104             Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
2105             ByteArrayOutputStream os = null;
2106             for (Part p:parts)
2107             {
2108                 MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p;
2109                 if (mp.getContentDispositionFilename() == null)
2110                 {
2111                     //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params
2112                     String charset = null;
2113                     if (mp.getContentType() != null)
2114                         charset = MimeTypes.getCharsetFromContentType(mp.getContentType());
2115 
2116                     //get the bytes regardless of being in memory or in temp file
2117                     try (InputStream is = mp.getInputStream())
2118                     {
2119                         if (os == null)
2120                             os = new ByteArrayOutputStream();
2121                         IO.copy(is, os);
2122                         String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset));
2123                         getParameter(""); //cause params to be evaluated
2124                         getParameters().add(mp.getName(), content);
2125                     }
2126                     os.reset();
2127                 }
2128             }
2129         }
2130 
2131         return _multiPartInputStream.getParts();
2132     }
2133 
2134     /* ------------------------------------------------------------ */
2135     @Override
2136     public void login(String username, String password) throws ServletException
2137     {
2138         if (_authentication instanceof Authentication.Deferred)
2139         {
2140             _authentication=((Authentication.Deferred)_authentication).login(username,password,this);
2141             if (_authentication == null)
2142                 throw new Authentication.Failed("Authentication failed for username '"+username+"'");
2143         }
2144         else
2145         {
2146             throw new Authentication.Failed("Authenticated failed for username '"+username+"'. Already authenticated as "+_authentication);
2147         }
2148     }
2149 
2150     /* ------------------------------------------------------------ */
2151     @Override
2152     public void logout() throws ServletException
2153     {
2154         if (_authentication instanceof Authentication.User)
2155             ((Authentication.User)_authentication).logout();
2156         _authentication=Authentication.UNAUTHENTICATED;
2157     }
2158 
2159     /* ------------------------------------------------------------ */
2160     /**
2161      * Merge in a new query string. The query string is merged with the existing parameters and {@link #setParameters(MultiMap)} and
2162      * {@link #setQueryString(String)} are called with the result. The merge is according to the rules of the servlet dispatch forward method.
2163      *
2164      * @param query
2165      *            The query string to merge into the request.
2166      */
2167     public void mergeQueryString(String query)
2168     {
2169         // extract parameters from dispatch query
2170         MultiMap<String> parameters = new MultiMap<>();
2171         UrlEncoded.decodeTo(query,parameters, StandardCharsets.UTF_8,-1); //have to assume UTF-8 because we can't know otherwise
2172 
2173         boolean merge_old_query = false;
2174 
2175         // Have we evaluated parameters
2176         if (!_paramsExtracted)
2177             extractParameters();
2178 
2179         // Are there any existing parameters?
2180         if (_parameters != null && _parameters.size() > 0)
2181         {
2182             // Merge parameters; new parameters of the same name take precedence.
2183             merge_old_query = parameters.addAllValues(_parameters);
2184         }
2185 
2186         if (_queryString != null && _queryString.length() > 0)
2187         {
2188             if (merge_old_query)
2189             {
2190                 StringBuilder overridden_query_string = new StringBuilder();
2191                 MultiMap<String> overridden_old_query = new MultiMap<>();
2192                 UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding(),-1);//decode using any queryencoding set for the request
2193                 
2194                 
2195                 MultiMap<String> overridden_new_query = new MultiMap<>();
2196                 UrlEncoded.decodeTo(query,overridden_new_query,StandardCharsets.UTF_8,-1); //have to assume utf8 as we cannot know otherwise
2197 
2198                 for(String name: overridden_old_query.keySet())
2199                 {
2200                     if (!overridden_new_query.containsKey(name))
2201                     {
2202                         List<String> values = overridden_old_query.get(name);
2203                         for(String v: values)
2204                         {
2205                             overridden_query_string.append("&").append(name).append("=").append(v);
2206                         }
2207                     }
2208                 }
2209 
2210                 query = query + overridden_query_string;
2211             }
2212             else
2213             {
2214                 query = query + "&" + _queryString;
2215             }
2216         }
2217 
2218         setParameters(parameters);
2219         setQueryString(query);
2220     }
2221 
2222 
2223    
2224     /** 
2225      * @see javax.servlet.http.HttpServletRequest#upgrade(java.lang.Class)
2226      */
2227     @Override
2228     public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException
2229     {
2230         if (getContext() == null)
2231             throw new ServletException ("Unable to instantiate "+handlerClass);
2232 
2233         try
2234         {
2235             //Instantiate an instance and inject it
2236             T h = getContext().createInstance(handlerClass);
2237             
2238             //TODO handle the rest of the upgrade process
2239             
2240             return h;
2241         }
2242         catch (Exception e)
2243         {
2244             if (e instanceof ServletException)
2245                 throw (ServletException)e;
2246             throw new ServletException(e);
2247         }
2248     }
2249 }