View Javadoc

1   //========================================================================
2   //$Id: Request.java,v 1.15 2005/11/16 22:02:40 gregwilkins Exp $
3   //Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
4   //------------------------------------------------------------------------
5   //Licensed under the Apache License, Version 2.0 (the "License");
6   //you may not use this file except in compliance with the License.
7   //You may obtain a copy of the License at 
8   //http://www.apache.org/licenses/LICENSE-2.0
9   //Unless required by applicable law or agreed to in writing, software
10  //distributed under the License is distributed on an "AS IS" BASIS,
11  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  //See the License for the specific language governing permissions and
13  //limitations under the License.
14  //========================================================================
15  
16  package org.mortbay.jetty;
17  
18  import java.io.BufferedReader;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.InputStreamReader;
22  import java.io.UnsupportedEncodingException;
23  import java.net.InetAddress;
24  import java.nio.ByteBuffer;
25  import java.security.Principal;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.Enumeration;
29  import java.util.EventListener;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Map;
35  
36  import javax.servlet.RequestDispatcher;
37  import javax.servlet.ServletContext;
38  import javax.servlet.ServletInputStream;
39  import javax.servlet.ServletRequestAttributeEvent;
40  import javax.servlet.ServletRequestAttributeListener;
41  import javax.servlet.ServletRequestWrapper;
42  import javax.servlet.ServletResponse;
43  import javax.servlet.http.Cookie;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpSession;
46  
47  import org.mortbay.io.Buffer;
48  import org.mortbay.io.BufferUtil;
49  import org.mortbay.io.EndPoint;
50  import org.mortbay.io.Portable;
51  import org.mortbay.io.nio.DirectNIOBuffer;
52  import org.mortbay.io.nio.IndirectNIOBuffer;
53  import org.mortbay.io.nio.NIOBuffer;
54  import org.mortbay.jetty.handler.ContextHandler;
55  import org.mortbay.jetty.handler.ContextHandler.SContext;
56  import org.mortbay.jetty.security.Authenticator;
57  import org.mortbay.jetty.security.SecurityHandler;
58  import org.mortbay.jetty.security.UserRealm;
59  import org.mortbay.log.Log;
60  import org.mortbay.util.Attributes;
61  import org.mortbay.util.AttributesMap;
62  import org.mortbay.util.LazyList;
63  import org.mortbay.util.MultiMap;
64  import org.mortbay.util.StringUtil;
65  import org.mortbay.util.URIUtil;
66  import org.mortbay.util.UrlEncoded;
67  import org.mortbay.util.ajax.Continuation;
68  
69  /* ------------------------------------------------------------ */
70  /** Jetty Request.
71   * <p>
72   * Implements {@link javax.servlet.HttpServletRequest} from the {@link javax.servlet} package.   
73   * </p>
74   * <p>
75   * The standard interface of mostly getters,
76   * is extended with setters so that the request is mutable by the handlers that it is
77   * passed to.  This allows the request object to be as lightweight as possible and not
78   * actually implement any significant behaviour. For example<ul>
79   * 
80   * <li>The {@link getContextPath} method will return null, until the requeset has been 
81   * passed to a {@link ContextHandler} which matches the {@link getPathInfo} with a context
82   * path and calls {@link setContextPath} as a result.</li>
83   * 
84   * <li>the HTTP session methods
85   * will all return null sessions until such time as a request has been passed to
86   * a {@link org.mortbay.jetty.servlet.SessionHandler} which checks for session cookies
87   * and enables the ability to create new sessions.</li>
88   * 
89   * <li>The {@link getServletPath} method will return null until the request has been
90   * passed to a {@link org.mortbay.jetty.servlet.ServletHandler} and the pathInfo matched
91   * against the servlet URL patterns and {@link setServletPath} called as a result.</li>
92   * </ul>
93   * 
94   * A request instance is created for each {@link HttpConnection} accepted by the server 
95   * and recycled for each HTTP request received via that connection. An effort is made
96   * to avoid reparsing headers and cookies that are likely to be the same for 
97   * requests from the same connection.
98   * 
99   * @author gregw
100  *
101  */
102 public class Request implements HttpServletRequest
103 {
104     private static final byte STATE_DELIMITER = 1;
105     private static final byte STATE_NAME = 2;
106     private static final byte STATE_VALUE = 4;
107     private static final byte STATE_QUOTED_VALUE = 8;
108     private static final byte STATE_UNQUOTED_VALUE = 16;
109 
110     private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault());
111     private static final int __NONE=0, _STREAM=1, __READER=2;
112     
113     private boolean _handled =false;
114     private HttpConnection _connection;
115     private EndPoint _endp;
116     private Map _roleMap;
117     
118     private Attributes _attributes;
119     private String _authType;
120     private String _characterEncoding;
121     private String _queryEncoding;
122     private String _serverName;
123     private String _remoteAddr;
124     private String _remoteHost;
125     private String _method;
126     private String _pathInfo;
127     private int _port;
128     private String _protocol=HttpVersions.HTTP_1_1;
129     private String _queryString;
130     private String _requestedSessionId;
131     private boolean _requestedSessionIdFromCookie=false;
132     private String _requestURI;
133     private String _scheme=URIUtil.HTTP;
134     private String _contextPath;
135     private String _servletPath;
136     private String _servletName;
137     private HttpURI _uri;
138     private Principal _userPrincipal;
139     private MultiMap _parameters;
140     private MultiMap _baseParameters;
141     private boolean _paramsExtracted;
142     private int _inputState=__NONE;
143     private BufferedReader _reader;
144     private String _readerEncoding;
145     private boolean _dns=false;
146     private ContextHandler.SContext _context;
147     private HttpSession _session;
148     private SessionManager _sessionManager;
149     private boolean _cookiesExtracted=false;
150     private Cookie[] _cookies;
151     private String[] _lastCookies;
152     private long _timeStamp;
153     private Buffer _timeStampBuffer;
154     private Continuation _continuation;
155     private Object _requestAttributeListeners;
156     private Map _savedNewSessions;
157     private UserRealm _userRealm;
158     
159     /* ------------------------------------------------------------ */
160     /**
161      * 
162      */
163     public Request()
164     {
165     }
166 
167     /* ------------------------------------------------------------ */
168     /**
169      * 
170      */
171     public Request(HttpConnection connection)
172     {
173         _connection=connection;
174         _endp=connection.getEndPoint();
175         _dns=_connection.getResolveNames();
176     }
177 
178     /* ------------------------------------------------------------ */
179     protected void setConnection(HttpConnection connection)
180     {
181         _connection=connection;
182         _endp=connection.getEndPoint();
183         _dns=connection.getResolveNames();
184     }
185     
186     /* ------------------------------------------------------------ */
187     protected void recycle()
188     {
189         _handled=false;
190         if (_context!=null)
191             throw new IllegalStateException("Request in context!");
192         if(_attributes!=null)
193             _attributes.clearAttributes();
194         _authType=null;
195         _characterEncoding=null;
196         _queryEncoding=null;
197         _context=null;
198         _serverName=null;
199         _method=null;
200         _pathInfo=null;
201         _port=0;
202         _protocol=HttpVersions.HTTP_1_1;
203         _queryString=null;
204         _requestedSessionId=null;
205         _requestedSessionIdFromCookie=false;
206         _session=null;
207         _requestURI=null;
208         _scheme=URIUtil.HTTP;
209         _servletPath=null;
210         _timeStamp=0;
211         _timeStampBuffer=null;
212         _uri=null;
213         _userPrincipal=null;
214         if (_baseParameters!=null)
215             _baseParameters.clear();
216         _parameters=null;
217         _paramsExtracted=false;
218         _inputState=__NONE;
219         
220         _cookiesExtracted=false;
221         if (_savedNewSessions!=null)
222             _savedNewSessions.clear();
223         _savedNewSessions=null;
224         if (_continuation!=null && _continuation.isPending())
225             _continuation.reset();
226     }
227 
228     /* ------------------------------------------------------------ */
229     /**
230      * Get Request TimeStamp
231      * 
232      * @return The time that the request was received.
233      */
234     public Buffer getTimeStampBuffer()
235     {
236         if (_timeStampBuffer == null && _timeStamp > 0)
237                 _timeStampBuffer = HttpFields.__dateCache.formatBuffer(_timeStamp);
238         return _timeStampBuffer;
239     }
240 
241     /* ------------------------------------------------------------ */
242     /**
243      * Get Request TimeStamp
244      * 
245      * @return The time that the request was received.
246      */
247     public long getTimeStamp()
248     {
249         return _timeStamp;
250     }
251 
252     /* ------------------------------------------------------------ */
253     public void setTimeStamp(long ts)
254     {
255         _timeStamp = ts;
256     }
257 
258     /* ------------------------------------------------------------ */
259     public boolean isHandled()
260     {
261         return _handled;
262     }
263 
264     /* ------------------------------------------------------------ */
265     public void setHandled(boolean h)
266     {
267         _handled=h;
268     }
269     
270     
271     /* ------------------------------------------------------------ */
272     /* 
273      * @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
274      */
275     public Object getAttribute(String name)
276     {
277         if ("org.mortbay.jetty.ajax.Continuation".equals(name))
278             return getContinuation(true);
279             
280         if (_attributes==null)
281             return null;
282         return _attributes.getAttribute(name);
283     }
284 
285     /* ------------------------------------------------------------ */
286     /* 
287      * @see javax.servlet.ServletRequest#getAttributeNames()
288      */
289     public Enumeration getAttributeNames()
290     {
291         if (_attributes==null)
292             return Collections.enumeration(Collections.EMPTY_LIST);
293         return AttributesMap.getAttributeNamesCopy(_attributes);
294     }
295 
296     /* ------------------------------------------------------------ */
297     /* 
298      * @see javax.servlet.http.HttpServletRequest#getAuthType()
299      */
300     public String getAuthType()
301     {
302         return _authType;
303     }
304 
305     /* ------------------------------------------------------------ */
306     /* 
307      * @see javax.servlet.ServletRequest#getCharacterEncoding()
308      */
309     public String getCharacterEncoding()
310     {
311         return _characterEncoding;
312     }
313     
314 
315     /* ------------------------------------------------------------ */
316     /* 
317      * @see javax.servlet.ServletRequest#getContentLength()
318      */
319     public int getContentLength()
320     {
321         return (int)_connection.getRequestFields().getLongField(HttpHeaders.CONTENT_LENGTH_BUFFER);
322     }
323 
324     /* ------------------------------------------------------------ */
325     /* 
326      * @see javax.servlet.ServletRequest#getContentType()
327      */
328     public String getContentType()
329     {
330         return _connection.getRequestFields().getStringField(HttpHeaders.CONTENT_TYPE_BUFFER);
331     }
332 
333     /* ------------------------------------------------------------ */
334     /* 
335      * @see javax.servlet.ServletRequest#getContentType()
336      */
337     public void setContentType(String contentType)
338     {
339         _connection.getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,contentType);
340         
341     }
342 
343     /* ------------------------------------------------------------ */
344     /* 
345      * @see javax.servlet.http.HttpServletRequest#getContextPath()
346      */
347     public String getContextPath()
348     {
349         return _contextPath;
350     }
351 
352     /* ------------------------------------------------------------ */
353     /* 
354      * @see javax.servlet.http.HttpServletRequest#getCookies()
355      */
356     public Cookie[] getCookies()
357     {
358         if (_cookiesExtracted) return _cookies;
359 
360         try
361         {
362             // Handle no cookies
363             if (!_connection.getRequestFields().containsKey(HttpHeaders.COOKIE_BUFFER))
364             {
365                 _cookies = null;
366                 _cookiesExtracted = true;
367                 _lastCookies = null;
368                 return _cookies;
369             }
370 
371             // Check if cookie headers match last cookies
372             if (_lastCookies != null)
373             {
374                 int last = 0;
375                 Enumeration enm = _connection.getRequestFields().getValues(HttpHeaders.COOKIE_BUFFER);
376                 while (enm.hasMoreElements())
377                 {
378                     String c = (String)enm.nextElement();
379                     if (last >= _lastCookies.length || !c.equals(_lastCookies[last]))
380                     {
381                         _lastCookies = null;
382                         break;
383                     }
384                     last++;
385                 }
386                 if (_lastCookies != null && _lastCookies.length==last)
387                 {
388                     _cookiesExtracted = true;
389                     return _cookies;
390                 }
391             }
392 
393             // Get ready to parse cookies (Expensive!!!)
394             Object cookies = null;
395             Object lastCookies = null;
396 
397             int version = 0;
398 
399             // For each cookie header
400             Enumeration enm = _connection.getRequestFields().getValues(HttpHeaders.COOKIE_BUFFER);
401             while (enm.hasMoreElements())
402             {
403                 // Save a copy of the unparsed header as cache.
404                 String hdr = (String)enm.nextElement();
405                 lastCookies = LazyList.add(lastCookies, hdr);
406 
407                 // Parse the header
408                 String name = null;
409                 String value = null;
410 
411                 Cookie cookie = null;
412 
413                 byte state = STATE_NAME;
414                 for (int i = 0, tokenstart = 0, length = hdr.length(); i < length; i++)
415                 {
416                     char c = hdr.charAt(i);
417                     switch (c)
418                     {
419                         case ',':
420                         case ';':
421                             switch (state)
422                             {
423                                 case STATE_DELIMITER:
424                                     state = STATE_NAME;
425                                     tokenstart = i + 1;
426                                     break;
427                                 case STATE_UNQUOTED_VALUE:
428                                     state = STATE_NAME;
429                                     value = hdr.substring(tokenstart, i).trim();
430                                     if(isRequestedSessionIdFromURL())
431                                         value = URIUtil.decodePath(value);
432                                     tokenstart = i + 1;
433                                     break;
434                                 case STATE_NAME:
435                                     name = hdr.substring(tokenstart, i);
436                                     value = "";
437                                     tokenstart = i + 1;
438                                     break;
439                                 case STATE_VALUE:
440                                     state = STATE_NAME;
441                                     value = "";
442                                     tokenstart = i + 1;
443                                     break;
444                             }
445                             break;
446                         case '=':
447                             switch (state)
448                             {
449                                 case STATE_NAME:
450                                     state = STATE_VALUE;
451                                     name = hdr.substring(tokenstart, i);
452                                     tokenstart = i + 1;
453                                     break;
454                                 case STATE_VALUE:
455                                     state = STATE_UNQUOTED_VALUE;
456                                     tokenstart = i;
457                                     break;
458                             }
459                             break;
460                         case '"':
461                             switch (state)
462                             {
463                                 case STATE_VALUE:
464                                     state = STATE_QUOTED_VALUE;
465                                     tokenstart = i + 1;
466                                     break;
467                                 case STATE_QUOTED_VALUE:
468                                     state = STATE_DELIMITER;
469                                     value = hdr.substring(tokenstart, i);
470                                     break;
471                             }
472                             break;
473                         case ' ':
474                         case '\t':
475                             break;
476                         default:
477                             switch (state)
478                             {
479                                 case STATE_VALUE:
480                                     state = STATE_UNQUOTED_VALUE;
481                                     tokenstart = i;
482                                     break;
483                                 case STATE_DELIMITER:
484                                     state = STATE_NAME;
485                                     tokenstart = i;
486                                     break;
487                             }
488                     }
489 
490                     if (i + 1 == length)
491                     {
492                         switch (state)
493                         {
494                             case STATE_UNQUOTED_VALUE:
495                                 value = hdr.substring(tokenstart).trim();
496                                 if(isRequestedSessionIdFromURL())
497                                     value = URIUtil.decodePath(value);
498                                 break;
499                             case STATE_NAME:
500                                 name = hdr.substring(tokenstart);
501                                 value = "";
502                                 break;
503                             case STATE_VALUE:
504                                 value = "";
505                                 break;
506                         }
507                     }
508 
509                     if (name != null && value != null)
510                     {
511                         name = name.trim();
512 
513                         try
514                         {
515                             if (name.startsWith("$"))
516                             {
517                                 String lowercaseName = name.toLowerCase();
518                                 if ("$path".equals(lowercaseName))
519                                 {
520                                     cookie.setPath(value);
521                                 }
522                                 else if ("$domain".equals(lowercaseName))
523                                 {
524                                     cookie.setDomain(value);
525                                 }
526                                 else if ("$version".equals(lowercaseName))
527                                 {
528                                     version = Integer.parseInt(value);
529                                 }
530                             }
531                             else
532                             {
533                                 cookie = new Cookie(name, value);
534 
535                                 if (version > 0)
536                                 {
537                                     cookie.setVersion(version);
538                                 }
539 
540                                 cookies = LazyList.add(cookies, cookie);
541                             }
542                         }
543                         catch (Exception e)
544                         {
545                             Log.ignore(e);
546                         }
547 
548                         name = null;
549                         value = null;
550                     }
551                 }
552             }
553 
554             int l = LazyList.size(cookies);
555             _cookiesExtracted = true;
556             if (l>0)
557             {
558                 if (_cookies == null || _cookies.length != l) _cookies = new Cookie[l];
559                 for (int i = 0; i < l; i++)
560                     _cookies[i] = (Cookie) LazyList.get(cookies, i);
561 
562                 l = LazyList.size(lastCookies);
563                 _lastCookies = new String[l];
564                 for (int i = 0; i < l; i++)
565                     _lastCookies[i] = (String) LazyList.get(lastCookies, i);
566             }
567         }
568         catch (Exception e)
569         {
570             Log.warn(e);
571         }
572 
573         if (_cookies==null || _cookies.length==0)
574             return null;
575         return _cookies;
576     }
577 
578     /* ------------------------------------------------------------ */
579     /* 
580      * @see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String)
581      */
582     public long getDateHeader(String name)
583     {
584         return _connection.getRequestFields().getDateField(name);
585     }
586 
587     /* ------------------------------------------------------------ */
588     /* 
589      * @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
590      */
591     public String getHeader(String name)
592     {
593         return _connection.getRequestFields().getStringField(name);
594     }
595 
596     /* ------------------------------------------------------------ */
597     /* 
598      * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
599      */
600     public Enumeration getHeaderNames()
601     {
602         return _connection.getRequestFields().getFieldNames();
603     }
604 
605     /* ------------------------------------------------------------ */
606     /* 
607      * @see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String)
608      */
609     public Enumeration getHeaders(String name)
610     {
611         Enumeration e = _connection.getRequestFields().getValues(name);
612         if (e==null)
613             return Collections.enumeration(Collections.EMPTY_LIST);
614         return e;
615     }
616 
617     /* ------------------------------------------------------------ */
618     /* 
619      * @see javax.servlet.ServletRequest#getInputStream()
620      */
621     public ServletInputStream getInputStream() throws IOException
622     {
623         if (_inputState!=__NONE && _inputState!=_STREAM)
624             throw new IllegalStateException("READER");
625         _inputState=_STREAM;
626         return _connection.getInputStream();
627     }
628 
629     /* ------------------------------------------------------------ */
630     /* 
631      * @see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String)
632      */
633     public int getIntHeader(String name)
634     {
635         return (int)_connection.getRequestFields().getLongField(name);
636     }
637 
638     /* ------------------------------------------------------------ */
639     /* 
640      * @see javax.servlet.ServletRequest#getLocalAddr()
641      */
642     public String getLocalAddr()
643     {
644         return _endp==null?null:_endp.getLocalAddr();
645     }
646 
647     /* ------------------------------------------------------------ */
648     /* 
649      * @see javax.servlet.ServletRequest#getLocale()
650      */
651     public Locale getLocale()
652     {
653         Enumeration enm = _connection.getRequestFields().getValues(HttpHeaders.ACCEPT_LANGUAGE, HttpFields.__separators);
654         
655         // handle no locale
656         if (enm == null || !enm.hasMoreElements())
657             return Locale.getDefault();
658         
659         // sort the list in quality order
660         List acceptLanguage = HttpFields.qualityList(enm);
661         if (acceptLanguage.size()==0)
662             return  Locale.getDefault();
663         
664         int size=acceptLanguage.size();
665         
666         // convert to locals
667         for (int i=0; i<size; i++)
668         {
669             String language = (String)acceptLanguage.get(i);
670             language=HttpFields.valueParameters(language,null);
671             String country = "";
672             int dash = language.indexOf('-');
673             if (dash > -1)
674             {
675                 country = language.substring(dash + 1).trim();
676                 language = language.substring(0,dash).trim();
677             }
678             return new Locale(language,country);
679         }
680         
681         return  Locale.getDefault();
682     }
683 
684     /* ------------------------------------------------------------ */
685     /* 
686      * @see javax.servlet.ServletRequest#getLocales()
687      */
688     public Enumeration getLocales()
689     {
690 
691         Enumeration enm = _connection.getRequestFields().getValues(HttpHeaders.ACCEPT_LANGUAGE, HttpFields.__separators);
692         
693         // handle no locale
694         if (enm == null || !enm.hasMoreElements())
695             return Collections.enumeration(__defaultLocale);
696         
697         // sort the list in quality order
698         List acceptLanguage = HttpFields.qualityList(enm);
699         
700         if (acceptLanguage.size()==0)
701             return
702             Collections.enumeration(__defaultLocale);
703         
704         Object langs = null;
705         int size=acceptLanguage.size();
706         
707         // convert to locals
708         for (int i=0; i<size; i++)
709         {
710             String language = (String)acceptLanguage.get(i);
711             language=HttpFields.valueParameters(language,null);
712             String country = "";
713             int dash = language.indexOf('-');
714             if (dash > -1)
715             {
716                 country = language.substring(dash + 1).trim();
717                 language = language.substring(0,dash).trim();
718             }
719             langs=LazyList.ensureSize(langs,size);
720             langs=LazyList.add(langs,new Locale(language,country));
721         }
722         
723         if (LazyList.size(langs)==0)
724             return Collections.enumeration(__defaultLocale);
725         
726         return Collections.enumeration(LazyList.getList(langs));
727     }
728 
729     /* ------------------------------------------------------------ */
730     /* 
731      * @see javax.servlet.ServletRequest#getLocalName()
732      */
733     public String getLocalName()
734     {
735         if (_dns)
736             return _endp==null?null:_endp.getLocalHost();
737         return _endp==null?null:_endp.getLocalAddr();
738     }
739 
740     /* ------------------------------------------------------------ */
741     /* 
742      * @see javax.servlet.ServletRequest#getLocalPort()
743      */
744     public int getLocalPort()
745     {
746         return _endp==null?0:_endp.getLocalPort();
747     }
748 
749     /* ------------------------------------------------------------ */
750     /* 
751      * @see javax.servlet.http.HttpServletRequest#getMethod()
752      */
753     public String getMethod()
754     {
755         return _method;
756     }
757 
758     /* ------------------------------------------------------------ */
759     /* 
760      * @see javax.servlet.ServletRequest#getParameter(java.lang.String)
761      */
762     public String getParameter(String name)
763     {
764         if (!_paramsExtracted) 
765             extractParameters();
766         return (String) _parameters.getValue(name, 0);
767     }
768 
769     /* ------------------------------------------------------------ */
770     /* 
771      * @see javax.servlet.ServletRequest#getParameterMap()
772      */
773     public Map getParameterMap()
774     {
775         if (!_paramsExtracted) 
776             extractParameters();
777         
778         return Collections.unmodifiableMap(_parameters.toStringArrayMap());
779     }
780 
781     /* ------------------------------------------------------------ */
782     /* 
783      * @see javax.servlet.ServletRequest#getParameterNames()
784      */
785     public Enumeration getParameterNames()
786     {
787         if (!_paramsExtracted) 
788             extractParameters();
789         return Collections.enumeration(_parameters.keySet());
790     }
791 
792     /* ------------------------------------------------------------ */
793     /* 
794      * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
795      */
796     public String[] getParameterValues(String name)
797     {
798         if (!_paramsExtracted) 
799             extractParameters();
800         List vals = _parameters.getValues(name);
801         if (vals==null)
802             return null;
803         return (String[])vals.toArray(new String[vals.size()]);
804     }
805 
806     /* ------------------------------------------------------------ */
807     /* 
808      * @see javax.servlet.http.HttpServletRequest#getPathInfo()
809      */
810     public String getPathInfo()
811     {
812         return _pathInfo;
813     }
814 
815     /* ------------------------------------------------------------ */
816     /* 
817      * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
818      */
819     public String getPathTranslated()
820     {
821         if (_pathInfo==null || _context==null)
822             return null;
823         return _context.getRealPath(_pathInfo);
824     }
825 
826     /* ------------------------------------------------------------ */
827     /* 
828      * @see javax.servlet.ServletRequest#getProtocol()
829      */
830     public String getProtocol()
831     {
832         return _protocol;
833     }
834 
835     /* ------------------------------------------------------------ */
836     /* 
837      * @see javax.servlet.ServletRequest#getReader()
838      */
839     public BufferedReader getReader() throws IOException
840     {
841         if (_inputState!=__NONE && _inputState!=__READER)
842             throw new IllegalStateException("STREAMED");
843 
844         if (_inputState==__READER)
845             return _reader;
846         
847         String encoding=getCharacterEncoding();
848         if (encoding==null)
849             encoding=StringUtil.__ISO_8859_1;
850         
851         if (_reader==null || !encoding.equalsIgnoreCase(_readerEncoding))
852         {
853             final ServletInputStream in = getInputStream();
854             _readerEncoding=encoding;
855             _reader=new BufferedReader(new InputStreamReader(in,encoding))
856             {
857                 public void close() throws IOException
858                 {
859                     in.close();
860                 }   
861             };
862         }
863         _inputState=__READER;
864         return _reader;
865     }
866 
867     /* ------------------------------------------------------------ */
868     /* 
869      * @see javax.servlet.ServletRequest#getRealPath(java.lang.String)
870      */
871     public String getRealPath(String path)
872     {
873         if (_context==null)
874             return null;
875         return _context.getRealPath(path);
876     }
877 
878     /* ------------------------------------------------------------ */
879     /* 
880      * @see javax.servlet.ServletRequest#getRemoteAddr()
881      */
882     public String getRemoteAddr()
883     {
884         if (_remoteAddr != null)
885             return _remoteAddr;	
886         return _endp==null?null:_endp.getRemoteAddr();
887     }
888 
889     /* ------------------------------------------------------------ */
890     /* 
891      * @see javax.servlet.ServletRequest#getRemoteHost()
892      */
893     public String getRemoteHost()
894     {
895         if (_dns)
896         {
897             if (_remoteHost != null)
898             {
899                 return _remoteHost;
900             }
901             return _endp==null?null:_endp.getRemoteHost();
902         }
903         return getRemoteAddr();
904     }
905 
906     /* ------------------------------------------------------------ */
907     /* 
908      * @see javax.servlet.ServletRequest#getRemotePort()
909      */
910     public int getRemotePort()
911     {
912         return _endp==null?0:_endp.getRemotePort();
913     }
914 
915     /* ------------------------------------------------------------ */
916     /* 
917      * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
918      */
919     public String getRemoteUser()
920     {
921         Principal p = getUserPrincipal();
922         if (p==null)
923             return null;
924         return p.getName();
925     }
926 
927     /* ------------------------------------------------------------ */
928     /* 
929      * @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
930      */
931     public RequestDispatcher getRequestDispatcher(String path)
932     {
933         if (path == null || _context==null)
934             return null;
935 
936         // handle relative path
937         if (!path.startsWith("/"))
938         {
939             String relTo=URIUtil.addPaths(_servletPath,_pathInfo);
940             int slash=relTo.lastIndexOf("/");
941             if (slash>1)
942                 relTo=relTo.substring(0,slash+1);
943             else
944                 relTo="/";
945             path=URIUtil.addPaths(relTo,path);
946         }
947     
948         return _context.getRequestDispatcher(path);
949     }
950 
951     /* ------------------------------------------------------------ */
952     /* 
953      * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
954      */
955     public String getRequestedSessionId()
956     {
957         return _requestedSessionId;
958     }
959 
960     /* ------------------------------------------------------------ */
961     /* 
962      * @see javax.servlet.http.HttpServletRequest#getRequestURI()
963      */
964     public String getRequestURI()
965     {
966         if (_requestURI==null && _uri!=null)
967             _requestURI=_uri.getPathAndParam();
968         return _requestURI;
969     }
970 
971     /* ------------------------------------------------------------ */
972     /* 
973      * @see javax.servlet.http.HttpServletRequest#getRequestURL()
974      */
975     public StringBuffer getRequestURL()
976     {
977         StringBuffer url = new StringBuffer(48);
978         synchronized (url)
979         {
980             String scheme = getScheme();
981             int port = getServerPort();
982 
983             url.append(scheme);
984             url.append("://");
985             url.append(getServerName());
986             if (_port>0 && 
987                 ((scheme.equalsIgnoreCase(URIUtil.HTTP) && port != 80) || 
988                  (scheme.equalsIgnoreCase(URIUtil.HTTPS) && port != 443)))
989             {
990                 url.append(':');
991                 url.append(_port);
992             }
993             
994             url.append(getRequestURI());
995             return url;
996         }
997     }
998 
999     /* ------------------------------------------------------------ */
1000     /* 
1001      * @see javax.servlet.ServletRequest#getScheme()
1002      */
1003     public String getScheme()
1004     {
1005         return _scheme;
1006     }
1007 
1008     /* ------------------------------------------------------------ */
1009     /* 
1010      * @see javax.servlet.ServletRequest#getServerName()
1011      */
1012     public String getServerName()
1013     {       
1014         // Return already determined host
1015         if (_serverName != null) 
1016             return _serverName;
1017 
1018         // Return host from absolute URI
1019         _serverName = _uri.getHost();
1020         _port = _uri.getPort();
1021         if (_serverName != null) 
1022             return _serverName;
1023 
1024         // Return host from header field
1025         Buffer hostPort = _connection.getRequestFields().get(HttpHeaders.HOST_BUFFER);
1026         if (hostPort!=null)
1027         {
1028             for (int i=hostPort.length();i-->0;)   
1029             {
1030                 if (hostPort.peek(hostPort.getIndex()+i)==':')
1031                 {
1032                     _serverName=BufferUtil.to8859_1_String(hostPort.peek(hostPort.getIndex(), i));
1033                     _port=BufferUtil.toInt(hostPort.peek(hostPort.getIndex()+i+1, hostPort.length()-i-1));
1034                     return _serverName;
1035                 }
1036             }
1037             if (_serverName==null || _port<0)
1038             {
1039                 _serverName=BufferUtil.to8859_1_String(hostPort);
1040                 _port = 0;
1041             }
1042             
1043             return _serverName;
1044         }
1045 
1046         // Return host from connection
1047         if (_connection != null)
1048         {
1049             _serverName = getLocalName();
1050             _port = getLocalPort();
1051             if (_serverName != null && !Portable.ALL_INTERFACES.equals(_serverName)) 
1052                 return _serverName;
1053         }
1054 
1055         // Return the local host
1056         try
1057         {
1058             _serverName = InetAddress.getLocalHost().getHostAddress();
1059         }
1060         catch (java.net.UnknownHostException e)
1061         {
1062             Log.ignore(e);
1063         }
1064         return _serverName;
1065     }
1066 
1067     /* ------------------------------------------------------------ */
1068     /* 
1069      * @see javax.servlet.ServletRequest#getServerPort()
1070      */
1071     public int getServerPort()
1072     {
1073         if (_port<=0)
1074         {
1075             if (_serverName==null)
1076                 getServerName();
1077         
1078             if (_port<=0)
1079             {
1080                 if (_serverName!=null && _uri!=null)
1081                     _port = _uri.getPort();
1082                 else
1083                     _port = _endp==null?0:_endp.getLocalPort();
1084             }
1085         }
1086         
1087         if (_port<=0)
1088         {
1089             if (getScheme().equalsIgnoreCase(URIUtil.HTTPS))
1090                 return 443;
1091             return 80;
1092         }
1093         return _port;
1094     }
1095 
1096     /* ------------------------------------------------------------ */
1097     /* 
1098      * @see javax.servlet.http.HttpServletRequest#getServletPath()
1099      */
1100     public String getServletPath()
1101     {
1102         if (_servletPath==null)
1103             _servletPath="";
1104         return _servletPath;
1105     }
1106     
1107     /* ------------------------------------------------------------ */
1108     /* 
1109      */
1110     public String getServletName()
1111     {
1112         return _servletName;
1113     }
1114 
1115     /* ------------------------------------------------------------ */
1116     /* 
1117      * @see javax.servlet.http.HttpServletRequest#getSession()
1118      */
1119     public HttpSession getSession()
1120     {
1121         return getSession(true);
1122     }
1123 
1124     /* ------------------------------------------------------------ */
1125     /* 
1126      * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
1127      */
1128     public HttpSession getSession(boolean create)
1129     {
1130         if (_sessionManager==null && create)
1131             throw new IllegalStateException("No SessionHandler or SessionManager");
1132         
1133         if (_session != null && _sessionManager!=null && _sessionManager.isValid(_session))
1134             return _session;
1135         
1136         _session=null;
1137         
1138         String id=getRequestedSessionId();
1139         
1140         if (id != null && _sessionManager!=null)
1141         {
1142             _session=_sessionManager.getHttpSession(id);
1143             if (_session == null && !create)
1144                 return null;
1145         }
1146         
1147         if (_session == null && _sessionManager!=null && create )
1148         {
1149             _session=_sessionManager.newHttpSession(this);
1150             Cookie cookie=_sessionManager.getSessionCookie(_session,getContextPath(),isSecure());
1151             if (cookie!=null)
1152                 _connection.getResponse().addCookie(cookie);
1153         }
1154         
1155         return _session;
1156     }
1157 
1158     /* ------------------------------------------------------------ */
1159     /* 
1160      * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
1161      */
1162     public Principal getUserPrincipal()
1163     {
1164         if (_userPrincipal != null && _userPrincipal instanceof SecurityHandler.NotChecked)
1165         {
1166             SecurityHandler.NotChecked not_checked=(SecurityHandler.NotChecked)_userPrincipal;
1167             _userPrincipal = SecurityHandler.__NO_USER;
1168             
1169             Authenticator auth=not_checked.getSecurityHandler().getAuthenticator();
1170             UserRealm realm=not_checked.getSecurityHandler().getUserRealm();
1171             String pathInContext=getPathInfo()==null?getServletPath():(getServletPath()+getPathInfo());
1172             
1173             if (realm != null && auth != null)
1174             {
1175                 try
1176                 {
1177                     auth.authenticate(realm, pathInContext, this, null);
1178                 }
1179                 catch (Exception e)
1180                 {
1181                     Log.ignore(e);
1182                 }
1183             }
1184         }
1185         
1186         if (_userPrincipal == SecurityHandler.__NO_USER) 
1187             return null;
1188         return _userPrincipal;
1189     }
1190 
1191     /* ------------------------------------------------------------ */
1192     /* 
1193      * @see javax.servlet.http.HttpServletRequest#getQueryString()
1194      */
1195     public String getQueryString()
1196     {
1197         if (_queryString==null && _uri!=null)
1198         {
1199             if (_queryEncoding==null)
1200                 _queryString=_uri.getQuery();
1201             else
1202                 _queryString=_uri.getQuery(_queryEncoding);
1203         }
1204         return _queryString;
1205     }
1206     
1207     /* ------------------------------------------------------------ */
1208     /* 
1209      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
1210      */
1211     public boolean isRequestedSessionIdFromCookie()
1212     {
1213         return _requestedSessionId!=null && _requestedSessionIdFromCookie;
1214     }
1215 
1216     /* ------------------------------------------------------------ */
1217     /* 
1218      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
1219      */
1220     public boolean isRequestedSessionIdFromUrl()
1221     {
1222         return _requestedSessionId!=null && !_requestedSessionIdFromCookie;
1223     }
1224 
1225     /* ------------------------------------------------------------ */
1226     /* 
1227      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
1228      */
1229     public boolean isRequestedSessionIdFromURL()
1230     {
1231         return _requestedSessionId!=null && !_requestedSessionIdFromCookie;
1232     }
1233 
1234     /* ------------------------------------------------------------ */
1235     /* 
1236      * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
1237      */
1238     public boolean isRequestedSessionIdValid()
1239     {	
1240         if (_requestedSessionId==null)
1241             return false;
1242         
1243         HttpSession session=getSession(false);
1244         return (session==null?false:_sessionManager.getIdManager().getClusterId(_requestedSessionId).equals(_sessionManager.getClusterId(session)));
1245     }
1246 
1247     /* ------------------------------------------------------------ */
1248     /* 
1249      * @see javax.servlet.ServletRequest#isSecure()
1250      */
1251     public boolean isSecure()
1252     {
1253         return _connection.isConfidential(this);
1254     }
1255 
1256     /* ------------------------------------------------------------ */
1257     /* 
1258      * @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
1259      */
1260     public boolean isUserInRole(String role)
1261     {
1262         if (_roleMap!=null)
1263         {
1264             String r=(String)_roleMap.get(role);
1265             if (r!=null)
1266                 role=r;
1267         }
1268 
1269         Principal principal = getUserPrincipal();
1270         
1271         if (_userRealm!=null && principal!=null)
1272             return _userRealm.isUserInRole(principal, role);
1273         
1274         return false;
1275     }
1276 
1277     /* ------------------------------------------------------------ */
1278     /* 
1279      * @see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
1280      */
1281     public void removeAttribute(String name)
1282     {
1283         Object old_value=_attributes==null?null:_attributes.getAttribute(name);
1284         
1285         if (_attributes!=null)
1286             _attributes.removeAttribute(name);
1287         
1288         if (old_value!=null)
1289         {
1290             if (_requestAttributeListeners!=null)
1291             {
1292                 ServletRequestAttributeEvent event =
1293                     new ServletRequestAttributeEvent(_context,this,name, old_value);
1294 
1295                 for(int i=0;i<LazyList.size(_requestAttributeListeners);i++)
1296                     ((ServletRequestAttributeListener)LazyList.get(_requestAttributeListeners,i)).attributeRemoved(event);
1297             }
1298         }
1299     }
1300 
1301     /* ------------------------------------------------------------ */
1302     /* 
1303      * Set a request attribute.
1304      * if the attribute name is "org.mortbay.jetty.Request.queryEncoding" then
1305      * the value is also passed in a call to {@link #setQueryEncoding}.
1306      *
1307      * if the attribute name is "org.mortbay.jetty.ResponseBuffer", then
1308      * the response buffer is flushed with @{link #flushResponseBuffer}  
1309      * 
1310      * @see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
1311      */
1312     public void setAttribute(String name, Object value)
1313     {
1314         Object old_value=_attributes==null?null:_attributes.getAttribute(name);
1315         
1316         if ("org.mortbay.jetty.Request.queryEncoding".equals(name))
1317             setQueryEncoding(value==null?null:value.toString());
1318         else if("org.mortbay.jetty.ResponseBuffer".equals(name))
1319         {
1320             try 
1321             {
1322                 ByteBuffer byteBuffer=(ByteBuffer)value;
1323                 synchronized (byteBuffer)
1324                 {
1325                     NIOBuffer buffer = byteBuffer.isDirect()
1326                         ?(NIOBuffer)new DirectNIOBuffer(byteBuffer,true)
1327                         :(NIOBuffer)new IndirectNIOBuffer(byteBuffer,true);
1328                     ((HttpConnection.Output)getServletResponse().getOutputStream()).sendResponse(buffer);