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