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