View Javadoc

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