View Javadoc

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