View Javadoc

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