Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » connector » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   package org.apache.catalina.connector;
   20   
   21   
   22   import java.io.InputStream;
   23   import java.io.IOException;
   24   import java.io.BufferedReader;
   25   import java.io.UnsupportedEncodingException;
   26   import java.security.Principal;
   27   import java.text.SimpleDateFormat;
   28   import java.util.ArrayList;
   29   import java.util.Enumeration;
   30   import java.util.HashMap;
   31   import java.util.Iterator;
   32   import java.util.Locale;
   33   import java.util.Map;
   34   import java.util.TimeZone;
   35   import java.util.TreeMap;
   36   
   37   import javax.security.auth.Subject;
   38   import javax.servlet.FilterChain;
   39   import javax.servlet.RequestDispatcher;
   40   import javax.servlet.ServletContext;
   41   import javax.servlet.ServletInputStream;
   42   import javax.servlet.ServletRequestAttributeEvent;
   43   import javax.servlet.ServletRequestAttributeListener;
   44   import javax.servlet.http.Cookie;
   45   import javax.servlet.http.HttpServletRequest;
   46   import javax.servlet.http.HttpSession;
   47   
   48   import org.apache.tomcat.util.buf.B2CConverter;
   49   import org.apache.tomcat.util.buf.ByteChunk;
   50   import org.apache.tomcat.util.buf.MessageBytes;
   51   import org.apache.tomcat.util.buf.StringCache;
   52   import org.apache.tomcat.util.http.Cookies;
   53   import org.apache.tomcat.util.http.FastHttpDateFormat;
   54   import org.apache.tomcat.util.http.Parameters;
   55   import org.apache.tomcat.util.http.ServerCookie;
   56   import org.apache.tomcat.util.http.mapper.MappingData;
   57   
   58   import org.apache.coyote.ActionCode;
   59   
   60   import org.apache.catalina.Context;
   61   import org.apache.catalina.Globals;
   62   import org.apache.catalina.Host;
   63   import org.apache.catalina.Manager;
   64   import org.apache.catalina.Realm;
   65   import org.apache.catalina.Session;
   66   import org.apache.catalina.Wrapper;
   67   import org.apache.catalina.core.ApplicationFilterFactory;
   68   import org.apache.catalina.realm.GenericPrincipal;
   69   import org.apache.catalina.util.Enumerator;
   70   import org.apache.catalina.util.ParameterMap;
   71   import org.apache.catalina.util.RequestUtil;
   72   import org.apache.catalina.util.StringManager;
   73   import org.apache.catalina.util.StringParser;
   74   
   75   
   76   /**
   77    * Wrapper object for the Coyote request.
   78    *
   79    * @author Remy Maucherat
   80    * @author Craig R. McClanahan
   81    * @version $Revision: 892545 $ $Date: 2009-12-20 02:04:17 +0100 (Sun, 20 Dec 2009) $
   82    */
   83   
   84   public class Request
   85       implements HttpServletRequest {
   86   
   87   
   88       // ----------------------------------------------------------- Constructors
   89   
   90   
   91       static {
   92           // Ensure that classes are loaded for SM
   93           new StringCache.ByteEntry();
   94           new StringCache.CharEntry();
   95       }
   96   
   97       public Request() {
   98   
   99           formats[0].setTimeZone(GMT_ZONE);
  100           formats[1].setTimeZone(GMT_ZONE);
  101           formats[2].setTimeZone(GMT_ZONE);
  102   
  103       }
  104   
  105   
  106       // ------------------------------------------------------------- Properties
  107   
  108   
  109       /**
  110        * Coyote request.
  111        */
  112       protected org.apache.coyote.Request coyoteRequest;
  113   
  114       /**
  115        * Set the Coyote request.
  116        * 
  117        * @param coyoteRequest The Coyote request
  118        */
  119       public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) {
  120           this.coyoteRequest = coyoteRequest;
  121           inputBuffer.setRequest(coyoteRequest);
  122       }
  123   
  124       /**
  125        * Get the Coyote request.
  126        */
  127       public org.apache.coyote.Request getCoyoteRequest() {
  128           return (this.coyoteRequest);
  129       }
  130   
  131   
  132       // ----------------------------------------------------- Variables
  133   
  134   
  135       protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
  136   
  137   
  138       /**
  139        * The string manager for this package.
  140        */
  141       protected static StringManager sm =
  142           StringManager.getManager(Constants.Package);
  143   
  144   
  145       /**
  146        * The set of cookies associated with this Request.
  147        */
  148       protected Cookie[] cookies = null;
  149   
  150   
  151       /**
  152        * The set of SimpleDateFormat formats to use in getDateHeader().
  153        *
  154        * Notice that because SimpleDateFormat is not thread-safe, we can't
  155        * declare formats[] as a static variable.
  156        */
  157       protected SimpleDateFormat formats[] = {
  158           new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
  159           new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
  160           new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
  161       };
  162   
  163   
  164       /**
  165        * The default Locale if none are specified.
  166        */
  167       protected static Locale defaultLocale = Locale.getDefault();
  168   
  169   
  170       /**
  171        * The attributes associated with this Request, keyed by attribute name.
  172        */
  173       protected HashMap attributes = new HashMap();
  174   
  175   
  176       /**
  177        * List of read only attributes for this Request.
  178        */
  179       private HashMap readOnlyAttributes = new HashMap();
  180   
  181   
  182       /**
  183        * The preferred Locales assocaited with this Request.
  184        */
  185       protected ArrayList locales = new ArrayList();
  186   
  187   
  188       /**
  189        * Internal notes associated with this request by Catalina components
  190        * and event listeners.
  191        */
  192       private transient HashMap notes = new HashMap();
  193   
  194   
  195       /**
  196        * Authentication type.
  197        */
  198       protected String authType = null;
  199   
  200       
  201       /**
  202        * Associated event.
  203        */
  204       protected CometEventImpl event = null;
  205       
  206   
  207       /**
  208        * Comet state
  209        */
  210       protected boolean comet = false;
  211       
  212       
  213       /**
  214        * The current dispatcher type.
  215        */
  216       protected Object dispatcherType = null;
  217   
  218   
  219       /**
  220        * The associated input buffer.
  221        */
  222       protected InputBuffer inputBuffer = new InputBuffer();
  223   
  224   
  225       /**
  226        * ServletInputStream.
  227        */
  228       protected CoyoteInputStream inputStream = 
  229           new CoyoteInputStream(inputBuffer);
  230   
  231   
  232       /**
  233        * Reader.
  234        */
  235       protected CoyoteReader reader = new CoyoteReader(inputBuffer);
  236   
  237   
  238       /**
  239        * Using stream flag.
  240        */
  241       protected boolean usingInputStream = false;
  242   
  243   
  244       /**
  245        * Using writer flag.
  246        */
  247       protected boolean usingReader = false;
  248   
  249   
  250       /**
  251        * User principal.
  252        */
  253       protected Principal userPrincipal = null;
  254   
  255   
  256       /**
  257        * Session parsed flag.
  258        */
  259       protected boolean sessionParsed = false;
  260   
  261   
  262       /**
  263        * Request parameters parsed flag.
  264        */
  265       protected boolean parametersParsed = false;
  266   
  267   
  268       /**
  269        * Cookies parsed flag.
  270        */
  271       protected boolean cookiesParsed = false;
  272   
  273   
  274       /**
  275        * Secure flag.
  276        */
  277       protected boolean secure = false;
  278   
  279       
  280       /**
  281        * The Subject associated with the current AccessControllerContext
  282        */
  283       protected transient Subject subject = null;
  284   
  285   
  286       /**
  287        * Post data buffer.
  288        */
  289       protected static int CACHED_POST_LEN = 8192;
  290       protected byte[] postData = null;
  291   
  292   
  293       /**
  294        * Hash map used in the getParametersMap method.
  295        */
  296       protected ParameterMap parameterMap = new ParameterMap();
  297   
  298   
  299       /**
  300        * The currently active session for this request.
  301        */
  302       protected Session session = null;
  303   
  304   
  305       /**
  306        * The current request dispatcher path.
  307        */
  308       protected Object requestDispatcherPath = null;
  309   
  310   
  311       /**
  312        * Was the requested session ID received in a cookie?
  313        */
  314       protected boolean requestedSessionCookie = false;
  315   
  316   
  317       /**
  318        * The requested session ID (if any) for this request.
  319        */
  320       protected String requestedSessionId = null;
  321   
  322   
  323       /**
  324        * Was the requested session ID received in a URL?
  325        */
  326       protected boolean requestedSessionURL = false;
  327   
  328   
  329       /**
  330        * Parse locales.
  331        */
  332       protected boolean localesParsed = false;
  333   
  334   
  335       /**
  336        * The string parser we will use for parsing request lines.
  337        */
  338       private StringParser parser = new StringParser();
  339   
  340   
  341       /**
  342        * Local port
  343        */
  344       protected int localPort = -1;
  345   
  346       /**
  347        * Remote address.
  348        */
  349       protected String remoteAddr = null;
  350   
  351   
  352       /**
  353        * Remote host.
  354        */
  355       protected String remoteHost = null;
  356   
  357       
  358       /**
  359        * Remote port
  360        */
  361       protected int remotePort = -1;
  362       
  363       /**
  364        * Local address
  365        */
  366       protected String localAddr = null;
  367   
  368       
  369       /**
  370        * Local address
  371        */
  372       protected String localName = null;
  373   
  374   
  375       // --------------------------------------------------------- Public Methods
  376   
  377   
  378       /**
  379        * Release all object references, and initialize instance variables, in
  380        * preparation for reuse of this object.
  381        */
  382       public void recycle() {
  383   
  384           context = null;
  385           wrapper = null;
  386   
  387           dispatcherType = null;
  388           requestDispatcherPath = null;
  389   
  390           comet = false;
  391           if (event != null) {
  392               event.clear();
  393               event = null;
  394           }
  395           
  396           authType = null;
  397           inputBuffer.recycle();
  398           usingInputStream = false;
  399           usingReader = false;
  400           userPrincipal = null;
  401           subject = null;
  402           sessionParsed = false;
  403           parametersParsed = false;
  404           cookiesParsed = false;
  405           locales.clear();
  406           localesParsed = false;
  407           secure = false;
  408           remoteAddr = null;
  409           remoteHost = null;
  410           remotePort = -1;
  411           localPort = -1;
  412           localAddr = null;
  413           localName = null;
  414   
  415           attributes.clear();
  416           notes.clear();
  417           cookies = null;
  418   
  419           if (session != null) {
  420               session.endAccess();
  421           }
  422           session = null;
  423           requestedSessionCookie = false;
  424           requestedSessionId = null;
  425           requestedSessionURL = false;
  426   
  427           if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) {
  428               parameterMap = new ParameterMap();
  429           } else {
  430               parameterMap.setLocked(false);
  431               parameterMap.clear();
  432           }
  433   
  434           mappingData.recycle();
  435   
  436           if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) {
  437               if (facade != null) {
  438                   facade.clear();
  439                   facade = null;
  440               }
  441               if (inputStream != null) {
  442                   inputStream.clear();
  443                   inputStream = null;
  444               }
  445               if (reader != null) {
  446                   reader.clear();
  447                   reader = null;
  448               }
  449           }
  450   
  451       }
  452   
  453   
  454       /**
  455        * Clear cached encoders (to save memory for Comet requests).
  456        */
  457       public void clearEncoders() {
  458           inputBuffer.clearEncoders();
  459       }
  460       
  461   
  462       /**
  463        * Clear cached encoders (to save memory for Comet requests).
  464        */
  465       public boolean read()
  466           throws IOException {
  467           return (inputBuffer.realReadBytes(null, 0, 0) > 0);
  468       }
  469       
  470   
  471       // -------------------------------------------------------- Request Methods
  472   
  473   
  474       /**
  475        * Associated Catalina connector.
  476        */
  477       protected Connector connector;
  478   
  479       /**
  480        * Return the Connector through which this Request was received.
  481        */
  482       public Connector getConnector() {
  483           return (this.connector);
  484       }
  485   
  486       /**
  487        * Set the Connector through which this Request was received.
  488        *
  489        * @param connector The new connector
  490        */
  491       public void setConnector(Connector connector) {
  492           this.connector = connector;
  493       }
  494   
  495   
  496       /**
  497        * Associated context.
  498        */
  499       protected Context context = null;
  500   
  501       /**
  502        * Return the Context within which this Request is being processed.
  503        */
  504       public Context getContext() {
  505           return (this.context);
  506       }
  507   
  508   
  509       /**
  510        * Set the Context within which this Request is being processed.  This
  511        * must be called as soon as the appropriate Context is identified, because
  512        * it identifies the value to be returned by <code>getContextPath()</code>,
  513        * and thus enables parsing of the request URI.
  514        *
  515        * @param context The newly associated Context
  516        */
  517       public void setContext(Context context) {
  518           this.context = context;
  519       }
  520   
  521   
  522       /**
  523        * Filter chain associated with the request.
  524        */
  525       protected FilterChain filterChain = null;
  526   
  527       /**
  528        * Get filter chain associated with the request.
  529        */
  530       public FilterChain getFilterChain() {
  531           return (this.filterChain);
  532       }
  533   
  534       /**
  535        * Set filter chain associated with the request.
  536        * 
  537        * @param filterChain new filter chain
  538        */
  539       public void setFilterChain(FilterChain filterChain) {
  540           this.filterChain = filterChain;
  541       }
  542   
  543   
  544       /**
  545        * Return the Host within which this Request is being processed.
  546        */
  547       public Host getHost() {
  548           if (getContext() == null)
  549               return null;
  550           return (Host) getContext().getParent();
  551           //return ((Host) mappingData.host);
  552       }
  553   
  554   
  555       /**
  556        * Set the Host within which this Request is being processed.  This
  557        * must be called as soon as the appropriate Host is identified, and
  558        * before the Request is passed to a context.
  559        *
  560        * @param host The newly associated Host
  561        */
  562       public void setHost(Host host) {
  563           mappingData.host = host;
  564       }
  565   
  566   
  567       /**
  568        * Descriptive information about this Request implementation.
  569        */
  570       protected static final String info =
  571           "org.apache.coyote.catalina.CoyoteRequest/1.0";
  572   
  573       /**
  574        * Return descriptive information about this Request implementation and
  575        * the corresponding version number, in the format
  576        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  577        */
  578       public String getInfo() {
  579           return (info);
  580       }
  581   
  582   
  583       /**
  584        * Mapping data.
  585        */
  586       protected MappingData mappingData = new MappingData();
  587   
  588       /**
  589        * Return mapping data.
  590        */
  591       public MappingData getMappingData() {
  592           return (mappingData);
  593       }
  594   
  595   
  596       /**
  597        * The facade associated with this request.
  598        */
  599       protected RequestFacade facade = null;
  600   
  601       /**
  602        * Return the <code>ServletRequest</code> for which this object
  603        * is the facade.  This method must be implemented by a subclass.
  604        */
  605       public HttpServletRequest getRequest() {
  606           if (facade == null) {
  607               facade = new RequestFacade(this);
  608           } 
  609           return (facade);
  610       }
  611   
  612   
  613       /**
  614        * The response with which this request is associated.
  615        */
  616       protected org.apache.catalina.connector.Response response = null;
  617   
  618       /**
  619        * Return the Response with which this Request is associated.
  620        */
  621       public org.apache.catalina.connector.Response getResponse() {
  622           return (this.response);
  623       }
  624   
  625       /**
  626        * Set the Response with which this Request is associated.
  627        *
  628        * @param response The new associated response
  629        */
  630       public void setResponse(org.apache.catalina.connector.Response response) {
  631           this.response = response;
  632       }
  633   
  634       /**
  635        * Return the input stream associated with this Request.
  636        */
  637       public InputStream getStream() {
  638           if (inputStream == null) {
  639               inputStream = new CoyoteInputStream(inputBuffer);
  640           }
  641           return inputStream;
  642       }
  643   
  644       /**
  645        * Set the input stream associated with this Request.
  646        *
  647        * @param stream The new input stream
  648        */
  649       public void setStream(InputStream stream) {
  650           // Ignore
  651       }
  652   
  653   
  654       /**
  655        * URI byte to char converter (not recycled).
  656        */
  657       protected B2CConverter URIConverter = null;
  658   
  659       /**
  660        * Return the URI converter.
  661        */
  662       protected B2CConverter getURIConverter() {
  663           return URIConverter;
  664       }
  665   
  666       /**
  667        * Set the URI converter.
  668        * 
  669        * @param URIConverter the new URI connverter
  670        */
  671       protected void setURIConverter(B2CConverter URIConverter) {
  672           this.URIConverter = URIConverter;
  673       }
  674   
  675   
  676       /**
  677        * Associated wrapper.
  678        */
  679       protected Wrapper wrapper = null;
  680   
  681       /**
  682        * Return the Wrapper within which this Request is being processed.
  683        */
  684       public Wrapper getWrapper() {
  685           return (this.wrapper);
  686       }
  687   
  688   
  689       /**
  690        * Set the Wrapper within which this Request is being processed.  This
  691        * must be called as soon as the appropriate Wrapper is identified, and
  692        * before the Request is ultimately passed to an application servlet.
  693        * @param wrapper The newly associated Wrapper
  694        */
  695       public void setWrapper(Wrapper wrapper) {
  696           this.wrapper = wrapper;
  697       }
  698   
  699   
  700       // ------------------------------------------------- Request Public Methods
  701   
  702   
  703       /**
  704        * Create and return a ServletInputStream to read the content
  705        * associated with this Request.
  706        *
  707        * @exception IOException if an input/output error occurs
  708        */
  709       public ServletInputStream createInputStream() 
  710           throws IOException {
  711           if (inputStream == null) {
  712               inputStream = new CoyoteInputStream(inputBuffer);
  713           }
  714           return inputStream;
  715       }
  716   
  717   
  718       /**
  719        * Perform whatever actions are required to flush and close the input
  720        * stream or reader, in a single operation.
  721        *
  722        * @exception IOException if an input/output error occurs
  723        */
  724       public void finishRequest() throws IOException {
  725           // The reader and input stream don't need to be closed
  726       }
  727   
  728   
  729       /**
  730        * Return the object bound with the specified name to the internal notes
  731        * for this request, or <code>null</code> if no such binding exists.
  732        *
  733        * @param name Name of the note to be returned
  734        */
  735       public Object getNote(String name) {
  736           return (notes.get(name));
  737       }
  738   
  739   
  740       /**
  741        * Return an Iterator containing the String names of all notes bindings
  742        * that exist for this request.
  743        */
  744       public Iterator getNoteNames() {
  745           return (notes.keySet().iterator());
  746       }
  747   
  748   
  749       /**
  750        * Remove any object bound to the specified name in the internal notes
  751        * for this request.
  752        *
  753        * @param name Name of the note to be removed
  754        */
  755       public void removeNote(String name) {
  756           notes.remove(name);
  757       }
  758   
  759   
  760       /**
  761        * Bind an object to a specified name in the internal notes associated
  762        * with this request, replacing any existing binding for this name.
  763        *
  764        * @param name Name to which the object should be bound
  765        * @param value Object to be bound to the specified name
  766        */
  767       public void setNote(String name, Object value) {
  768           notes.put(name, value);
  769       }
  770   
  771   
  772       /**
  773        * Set the content length associated with this Request.
  774        *
  775        * @param length The new content length
  776        */
  777       public void setContentLength(int length) {
  778           // Not used
  779       }
  780   
  781   
  782       /**
  783        * Set the content type (and optionally the character encoding)
  784        * associated with this Request.  For example,
  785        * <code>text/html; charset=ISO-8859-4</code>.
  786        *
  787        * @param type The new content type
  788        */
  789       public void setContentType(String type) {
  790           // Not used
  791       }
  792   
  793   
  794       /**
  795        * Set the protocol name and version associated with this Request.
  796        *
  797        * @param protocol Protocol name and version
  798        */
  799       public void setProtocol(String protocol) {
  800           // Not used
  801       }
  802   
  803   
  804       /**
  805        * Set the IP address of the remote client associated with this Request.
  806        *
  807        * @param remoteAddr The remote IP address
  808        */
  809       public void setRemoteAddr(String remoteAddr) {
  810           this.remoteAddr = remoteAddr;
  811       }
  812   
  813   
  814       /**
  815        * Set the fully qualified name of the remote client associated with this
  816        * Request.
  817        *
  818        * @param remoteHost The remote host name
  819        */
  820       public void setRemoteHost(String remoteHost) {
  821           this.remoteHost = remoteHost;
  822       }
  823   
  824   
  825       /**
  826        * Set the name of the scheme associated with this request.  Typical values
  827        * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
  828        *
  829        * @param scheme The scheme
  830        */
  831       public void setScheme(String scheme) {
  832           // Not used
  833       }
  834   
  835   
  836       /**
  837        * Set the value to be returned by <code>isSecure()</code>
  838        * for this Request.
  839        *
  840        * @param secure The new isSecure value
  841        */
  842       public void setSecure(boolean secure) {
  843           this.secure = secure;
  844       }
  845   
  846   
  847       /**
  848        * Set the name of the server (virtual host) to process this request.
  849        *
  850        * @param name The server name
  851        */
  852       public void setServerName(String name) {
  853           coyoteRequest.serverName().setString(name);
  854       }
  855   
  856   
  857       /**
  858        * Set the port number of the server to process this request.
  859        *
  860        * @param port The server port
  861        */
  862       public void setServerPort(int port) {
  863           coyoteRequest.setServerPort(port);
  864       }
  865   
  866   
  867       // ------------------------------------------------- ServletRequest Methods
  868   
  869   
  870       /**
  871        * Return the specified request attribute if it exists; otherwise, return
  872        * <code>null</code>.
  873        *
  874        * @param name Name of the request attribute to return
  875        */
  876       public Object getAttribute(String name) {
  877   
  878           if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
  879               return (dispatcherType == null) 
  880                   ? ApplicationFilterFactory.REQUEST_INTEGER
  881                   : dispatcherType;
  882           } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
  883               return (requestDispatcherPath == null) 
  884                   ? getRequestPathMB().toString()
  885                   : requestDispatcherPath.toString();
  886           }
  887   
  888           Object attr=attributes.get(name);
  889   
  890           if(attr!=null)
  891               return(attr);
  892   
  893           attr =  coyoteRequest.getAttribute(name);
  894           if(attr != null)
  895               return attr;
  896           if( isSSLAttribute(name) ) {
  897               coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE, 
  898                                    coyoteRequest);
  899               attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR);
  900               if( attr != null) {
  901                   attributes.put(Globals.CERTIFICATES_ATTR, attr);
  902               }
  903               attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR);
  904               if(attr != null) {
  905                   attributes.put(Globals.CIPHER_SUITE_ATTR, attr);
  906               }
  907               attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR);
  908               if(attr != null) {
  909                   attributes.put(Globals.KEY_SIZE_ATTR, attr);
  910               }
  911               attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR);
  912               if(attr != null) {
  913                   attributes.put(Globals.SSL_SESSION_ID_ATTR, attr);
  914               }
  915               attr = attributes.get(name);
  916           }
  917           return attr;
  918       }
  919   
  920   
  921       /**
  922        * Test if a given name is one of the special Servlet-spec SSL attributes.
  923        */
  924       static boolean isSSLAttribute(String name) {
  925           return Globals.CERTIFICATES_ATTR.equals(name) ||
  926               Globals.CIPHER_SUITE_ATTR.equals(name) ||
  927               Globals.KEY_SIZE_ATTR.equals(name)  ||
  928               Globals.SSL_SESSION_ID_ATTR.equals(name);
  929       }
  930   
  931       /**
  932        * Return the names of all request attributes for this Request, or an
  933        * empty <code>Enumeration</code> if there are none. Note that the attribute
  934        * names return will only be those for the attributes set via
  935        * {@link #setAttribute(String, Object)}. Tomcat internal attributes will
  936        * not be included although they are accessible via
  937        * {@link #getAttribute(String)}. The Tomcat internal attributes include:
  938        * <ul>
  939        * <li>{@link Globals.DISPATCHER_TYPE_ATTR}</li>
  940        * <li>{@link Globals.DISPATCHER_REQUEST_PATH_ATTR}</li>
  941        * <li>{@link Globals.ASYNC_SUPPORTED_ATTR}</li>
  942        * <li>{@link Globals.CERTIFICATES_ATTR} (SSL connections only)</li>
  943        * <li>{@link Globals.CIPHER_SUITE_ATTR} (SSL connections only)</li>
  944        * <li>{@link Globals.KEY_SIZE_ATTR} (SSL connections only)</li>
  945        * <li>{@link Globals.SSL_SESSION_ID_ATTR} (SSL connections only)</li>
  946        * <li>{@link Globals.SSL_SESSION_MGR_ATTR} (SSL connections only)</li>
  947        * </ul>
  948        * The underlying connector may also expose request attributes. These all
  949        * have names starting with "org.apache.tomcat" and include:
  950        * <ul>
  951        * <li>org.apache.tomcat.sendfile.support</li>
  952        * <li>org.apache.tomcat.comet.support</li>
  953        * <li>org.apache.tomcat.comet.timeout.support</li>
  954        * </ul>
  955        * Connector implementations may return some, all or none of these
  956        * attributes and may also support additional attributes.
  957        */
  958       public Enumeration getAttributeNames() {
  959           if (isSecure()) {
  960               getAttribute(Globals.CERTIFICATES_ATTR);
  961           }
  962           return new Enumerator(attributes.keySet(), true);
  963       }
  964   
  965   
  966       /**
  967        * Return the character encoding for this Request.
  968        */
  969       public String getCharacterEncoding() {
  970         return (coyoteRequest.getCharacterEncoding());
  971       }
  972   
  973   
  974       /**
  975        * Return the content length for this Request.
  976        */
  977       public int getContentLength() {
  978           return (coyoteRequest.getContentLength());
  979       }
  980   
  981   
  982       /**
  983        * Return the content type for this Request.
  984        */
  985       public String getContentType() {
  986           return (coyoteRequest.getContentType());
  987       }
  988   
  989   
  990       /**
  991        * Return the servlet input stream for this Request.  The default
  992        * implementation returns a servlet input stream created by
  993        * <code>createInputStream()</code>.
  994        *
  995        * @exception IllegalStateException if <code>getReader()</code> has
  996        *  already been called for this request
  997        * @exception IOException if an input/output error occurs
  998        */
  999       public ServletInputStream getInputStream() throws IOException {
 1000   
 1001           if (usingReader)
 1002               throw new IllegalStateException
 1003                   (sm.getString("coyoteRequest.getInputStream.ise"));
 1004   
 1005           usingInputStream = true;
 1006           if (inputStream == null) {
 1007               inputStream = new CoyoteInputStream(inputBuffer);
 1008           }
 1009           return inputStream;
 1010   
 1011       }
 1012   
 1013   
 1014       /**
 1015        * Return the preferred Locale that the client will accept content in,
 1016        * based on the value for the first <code>Accept-Language</code> header
 1017        * that was encountered.  If the request did not specify a preferred
 1018        * language, the server's default Locale is returned.
 1019        */
 1020       public Locale getLocale() {
 1021   
 1022           if (!localesParsed)
 1023               parseLocales();
 1024   
 1025           if (locales.size() > 0) {
 1026               return ((Locale) locales.get(0));
 1027           } else {
 1028               return (defaultLocale);
 1029           }
 1030   
 1031       }
 1032   
 1033   
 1034       /**
 1035        * Return the set of preferred Locales that the client will accept
 1036        * content in, based on the values for any <code>Accept-Language</code>
 1037        * headers that were encountered.  If the request did not specify a
 1038        * preferred language, the server's default Locale is returned.
 1039        */
 1040       public Enumeration getLocales() {
 1041   
 1042           if (!localesParsed)
 1043               parseLocales();
 1044   
 1045           if (locales.size() > 0)
 1046               return (new Enumerator(locales));
 1047           ArrayList results = new ArrayList();
 1048           results.add(defaultLocale);
 1049           return (new Enumerator(results));
 1050   
 1051       }
 1052   
 1053   
 1054       /**
 1055        * Return the value of the specified request parameter, if any; otherwise,
 1056        * return <code>null</code>.  If there is more than one value defined,
 1057        * return only the first one.
 1058        *
 1059        * @param name Name of the desired request parameter
 1060        */
 1061       public String getParameter(String name) {
 1062   
 1063           if (!parametersParsed)
 1064               parseParameters();
 1065   
 1066           return coyoteRequest.getParameters().getParameter(name);
 1067   
 1068       }
 1069   
 1070   
 1071   
 1072       /**
 1073        * Returns a <code>Map</code> of the parameters of this request.
 1074        * Request parameters are extra information sent with the request.
 1075        * For HTTP servlets, parameters are contained in the query string
 1076        * or posted form data.
 1077        *
 1078        * @return A <code>Map</code> containing parameter names as keys
 1079        *  and parameter values as map values.
 1080        */
 1081       public Map getParameterMap() {
 1082   
 1083           if (parameterMap.isLocked())
 1084               return parameterMap;
 1085   
 1086           Enumeration enumeration = getParameterNames();
 1087           while (enumeration.hasMoreElements()) {
 1088               String name = enumeration.nextElement().toString();
 1089               String[] values = getParameterValues(name);
 1090               parameterMap.put(name, values);
 1091           }
 1092   
 1093           parameterMap.setLocked(true);
 1094   
 1095           return parameterMap;
 1096   
 1097       }
 1098   
 1099   
 1100       /**
 1101        * Return the names of all defined request parameters for this request.
 1102        */
 1103       public Enumeration getParameterNames() {
 1104   
 1105           if (!parametersParsed)
 1106               parseParameters();
 1107   
 1108           return coyoteRequest.getParameters().getParameterNames();
 1109   
 1110       }
 1111   
 1112   
 1113       /**
 1114        * Return the defined values for the specified request parameter, if any;
 1115        * otherwise, return <code>null</code>.
 1116        *
 1117        * @param name Name of the desired request parameter
 1118        */
 1119       public String[] getParameterValues(String name) {
 1120   
 1121           if (!parametersParsed)
 1122               parseParameters();
 1123   
 1124           return coyoteRequest.getParameters().getParameterValues(name);
 1125   
 1126       }
 1127   
 1128   
 1129       /**
 1130        * Return the protocol and version used to make this Request.
 1131        */
 1132       public String getProtocol() {
 1133           return coyoteRequest.protocol().toString();
 1134       }
 1135   
 1136   
 1137       /**
 1138        * Read the Reader wrapping the input stream for this Request.  The
 1139        * default implementation wraps a <code>BufferedReader</code> around the
 1140        * servlet input stream returned by <code>createInputStream()</code>.
 1141        *
 1142        * @exception IllegalStateException if <code>getInputStream()</code>
 1143        *  has already been called for this request
 1144        * @exception IOException if an input/output error occurs
 1145        */
 1146       public BufferedReader getReader() throws IOException {
 1147   
 1148           if (usingInputStream)
 1149               throw new IllegalStateException
 1150                   (sm.getString("coyoteRequest.getReader.ise"));
 1151   
 1152           usingReader = true;
 1153           inputBuffer.checkConverter();
 1154           if (reader == null) {
 1155               reader = new CoyoteReader(inputBuffer);
 1156           }
 1157           return reader;
 1158   
 1159       }
 1160   
 1161   
 1162       /**
 1163        * Return the real path of the specified virtual path.
 1164        *
 1165        * @param path Path to be translated
 1166        *
 1167        * @deprecated As of version 2.1 of the Java Servlet API, use
 1168        *  <code>ServletContext.getRealPath()</code>.
 1169        */
 1170       public String getRealPath(String path) {
 1171   
 1172           if (context == null)
 1173               return (null);
 1174           ServletContext servletContext = context.getServletContext();
 1175           if (servletContext == null)
 1176               return (null);
 1177           else {
 1178               try {
 1179                   return (servletContext.getRealPath(path));
 1180               } catch (IllegalArgumentException e) {
 1181                   return (null);
 1182               }
 1183           }
 1184   
 1185       }
 1186   
 1187   
 1188       /**
 1189        * Return the remote IP address making this Request.
 1190        */
 1191       public String getRemoteAddr() {
 1192           if (remoteAddr == null) {
 1193               coyoteRequest.action
 1194                   (ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest);
 1195               remoteAddr = coyoteRequest.remoteAddr().toString();
 1196           }
 1197           return remoteAddr;
 1198       }
 1199   
 1200   
 1201       /**
 1202        * Return the remote host name making this Request.
 1203        */
 1204       public String getRemoteHost() {
 1205           if (remoteHost == null) {
 1206               if (!connector.getEnableLookups()) {
 1207                   remoteHost = getRemoteAddr();
 1208               } else {
 1209                   coyoteRequest.action
 1210                       (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest);
 1211                   remoteHost = coyoteRequest.remoteHost().toString();
 1212               }
 1213           }
 1214           return remoteHost;
 1215       }
 1216   
 1217       /**
 1218        * Returns the Internet Protocol (IP) source port of the client
 1219        * or last proxy that sent the request.
 1220        */    
 1221       public int getRemotePort(){
 1222           if (remotePort == -1) {
 1223               coyoteRequest.action
 1224                   (ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest);
 1225               remotePort = coyoteRequest.getRemotePort();
 1226           }
 1227           return remotePort;    
 1228       }
 1229   
 1230       /**
 1231        * Returns the host name of the Internet Protocol (IP) interface on
 1232        * which the request was received.
 1233        */
 1234       public String getLocalName(){
 1235           if (localName == null) {
 1236               coyoteRequest.action
 1237                   (ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, coyoteRequest);
 1238               localName = coyoteRequest.localName().toString();
 1239           }
 1240           return localName;
 1241       }
 1242   
 1243       /**
 1244        * Returns the Internet Protocol (IP) address of the interface on
 1245        * which the request  was received.
 1246        */       
 1247       public String getLocalAddr(){
 1248           if (localAddr == null) {
 1249               coyoteRequest.action
 1250                   (ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest);
 1251               localAddr = coyoteRequest.localAddr().toString();
 1252           }
 1253           return localAddr;    
 1254       }
 1255   
 1256   
 1257       /**
 1258        * Returns the Internet Protocol (IP) port number of the interface
 1259        * on which the request was received.
 1260        */
 1261       public int getLocalPort(){
 1262           if (localPort == -1){
 1263               coyoteRequest.action
 1264                   (ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE, coyoteRequest);
 1265               localPort = coyoteRequest.getLocalPort();
 1266           }
 1267           return localPort;
 1268       }
 1269       
 1270       /**
 1271        * Return a RequestDispatcher that wraps the resource at the specified
 1272        * path, which may be interpreted as relative to the current request path.
 1273        *
 1274        * @param path Path of the resource to be wrapped
 1275        */
 1276       public RequestDispatcher getRequestDispatcher(String path) {
 1277   
 1278           if (context == null)
 1279               return (null);
 1280   
 1281           // If the path is already context-relative, just pass it through
 1282           if (path == null)
 1283               return (null);
 1284           else if (path.startsWith("/"))
 1285               return (context.getServletContext().getRequestDispatcher(path));
 1286   
 1287           // Convert a request-relative path to a context-relative one
 1288           String servletPath = (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
 1289           if (servletPath == null)
 1290               servletPath = getServletPath();
 1291   
 1292           // Add the path info, if there is any
 1293           String pathInfo = getPathInfo();
 1294           String requestPath = null;
 1295   
 1296           if (pathInfo == null) {
 1297               requestPath = servletPath;
 1298           } else {
 1299               requestPath = servletPath + pathInfo;
 1300           }
 1301   
 1302           int pos = requestPath.lastIndexOf('/');
 1303           String relative = null;
 1304           if (pos >= 0) {
 1305               relative = requestPath.substring(0, pos + 1) + path;
 1306           } else {
 1307               relative = requestPath + path;
 1308           }
 1309   
 1310           return (context.getServletContext().getRequestDispatcher(relative));
 1311   
 1312       }
 1313   
 1314   
 1315       /**
 1316        * Return the scheme used to make this Request.
 1317        */
 1318       public String getScheme() {
 1319           return (coyoteRequest.scheme().toString());
 1320       }
 1321   
 1322   
 1323       /**
 1324        * Return the server name responding to this Request.
 1325        */
 1326       public String getServerName() {
 1327           return (coyoteRequest.serverName().toString());
 1328       }
 1329   
 1330   
 1331       /**
 1332        * Return the server port responding to this Request.
 1333        */
 1334       public int getServerPort() {
 1335           return (coyoteRequest.getServerPort());
 1336       }
 1337   
 1338   
 1339       /**
 1340        * Was this request received on a secure connection?
 1341        */
 1342       public boolean isSecure() {
 1343           return (secure);
 1344       }
 1345   
 1346   
 1347       /**
 1348        * Remove the specified request attribute if it exists.
 1349        *
 1350        * @param name Name of the request attribute to remove
 1351        */
 1352       public void removeAttribute(String name) {
 1353           Object value = null;
 1354           boolean found = false;
 1355   
 1356           // Remove the specified attribute
 1357           // Check for read only attribute
 1358           // requests are per thread so synchronization unnecessary
 1359           if (readOnlyAttributes.containsKey(name)) {
 1360               return;
 1361           }
 1362   
 1363           // Pass special attributes to the native layer
 1364           if (name.startsWith("org.apache.tomcat.")) {
 1365               coyoteRequest.getAttributes().remove(name);
 1366           }
 1367   
 1368           found = attributes.containsKey(name);
 1369           if (found) {
 1370               value = attributes.get(name);
 1371               attributes.remove(name);
 1372           } else {
 1373               return;
 1374           }
 1375           
 1376           // Notify interested application event listeners
 1377           Object listeners[] = context.getApplicationEventListeners();
 1378           if ((listeners == null) || (listeners.length == 0))
 1379               return;
 1380           ServletRequestAttributeEvent event =
 1381             new ServletRequestAttributeEvent(context.getServletContext(),
 1382                                              getRequest(), name, value);
 1383           for (int i = 0; i < listeners.length; i++) {
 1384               if (!(listeners[i] instanceof ServletRequestAttributeListener))
 1385                   continue;
 1386               ServletRequestAttributeListener listener =
 1387                   (ServletRequestAttributeListener) listeners[i];
 1388               try {
 1389                   listener.attributeRemoved(event);
 1390               } catch (Throwable t) {
 1391                   context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
 1392                   // Error valve will pick this execption up and display it to user
 1393                   attributes.put( Globals.EXCEPTION_ATTR, t );
 1394               }
 1395           }
 1396       }
 1397   
 1398   
 1399       /**
 1400        * Set the specified request attribute to the specified value.
 1401        *
 1402        * @param name Name of the request attribute to set
 1403        * @param value The associated value
 1404        */
 1405       public void setAttribute(String name, Object value) {
 1406   	
 1407           // Name cannot be null
 1408           if (name == null)
 1409               throw new IllegalArgumentException
 1410                   (sm.getString("coyoteRequest.setAttribute.namenull"));
 1411   
 1412           // Null value is the same as removeAttribute()
 1413           if (value == null) {
 1414               removeAttribute(name);
 1415               return;
 1416           }
 1417   
 1418           if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
 1419               dispatcherType = value;
 1420               return;
 1421           } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
 1422               requestDispatcherPath = value;
 1423               return;
 1424           }
 1425   
 1426           Object oldValue = null;
 1427           boolean replaced = false;
 1428   
 1429           // Add or replace the specified attribute
 1430           // Check for read only attribute
 1431           // requests are per thread so synchronization unnecessary
 1432           if (readOnlyAttributes.containsKey(name)) {
 1433               return;
 1434           }
 1435   
 1436           oldValue = attributes.put(name, value);
 1437           if (oldValue != null) {
 1438               replaced = true;
 1439           }
 1440   
 1441           // Pass special attributes to the native layer
 1442           if (name.startsWith("org.apache.tomcat.")) {
 1443               coyoteRequest.setAttribute(name, value);
 1444           }
 1445           
 1446           // Notify interested application event listeners
 1447           Object listeners[] = context.getApplicationEventListeners();
 1448           if ((listeners == null) || (listeners.length == 0))
 1449               return;
 1450           ServletRequestAttributeEvent event = null;
 1451           if (replaced)
 1452               event =
 1453                   new ServletRequestAttributeEvent(context.getServletContext(),
 1454                                                    getRequest(), name, oldValue);
 1455           else
 1456               event =
 1457                   new ServletRequestAttributeEvent(context.getServletContext(),
 1458                                                    getRequest(), name, value);
 1459   
 1460           for (int i = 0; i < listeners.length; i++) {
 1461               if (!(listeners[i] instanceof ServletRequestAttributeListener))
 1462                   continue;
 1463               ServletRequestAttributeListener listener =
 1464                   (ServletRequestAttributeListener) listeners[i];
 1465               try {
 1466                   if (replaced) {
 1467                       listener.attributeReplaced(event);
 1468                   } else {
 1469                       listener.attributeAdded(event);
 1470                   }
 1471               } catch (Throwable t) {
 1472                   context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
 1473                   // Error valve will pick this execption up and display it to user
 1474                   attributes.put( Globals.EXCEPTION_ATTR, t );
 1475               }
 1476           }
 1477       }
 1478   
 1479   
 1480       /**
 1481        * Overrides the name of the character encoding used in the body of
 1482        * this request.  This method must be called prior to reading request
 1483        * parameters or reading input using <code>getReader()</code>.
 1484        *
 1485        * @param enc The character encoding to be used
 1486        *
 1487        * @exception UnsupportedEncodingException if the specified encoding
 1488        *  is not supported
 1489        *
 1490        * @since Servlet 2.3
 1491        */
 1492       public void setCharacterEncoding(String enc)
 1493           throws UnsupportedEncodingException {
 1494   
 1495           if (usingReader)
 1496               return;
 1497           
 1498           // Ensure that the specified encoding is valid
 1499           byte buffer[] = new byte[1];
 1500           buffer[0] = (byte) 'a';
 1501           String dummy = new String(buffer, enc);
 1502   
 1503           // Save the validated encoding
 1504           coyoteRequest.setCharacterEncoding(enc);
 1505   
 1506       }
 1507   
 1508   
 1509       // ---------------------------------------------------- HttpRequest Methods
 1510   
 1511   
 1512       /**
 1513        * Add a Cookie to the set of Cookies associated with this Request.
 1514        *
 1515        * @param cookie The new cookie
 1516        */
 1517       public void addCookie(Cookie cookie) {
 1518   
 1519           if (!cookiesParsed)
 1520               parseCookies();
 1521   
 1522           int size = 0;
 1523           if (cookies != null) {
 1524               size = cookies.length;
 1525           }
 1526   
 1527           Cookie[] newCookies = new Cookie[size + 1];
 1528           for (int i = 0; i < size; i++) {
 1529               newCookies[i] = cookies[i];
 1530           }
 1531           newCookies[size] = cookie;
 1532   
 1533           cookies = newCookies;
 1534   
 1535       }
 1536   
 1537   
 1538       /**
 1539        * Add a Header to the set of Headers associated with this Request.
 1540        *
 1541        * @param name The new header name
 1542        * @param value The new header value
 1543        */
 1544       public void addHeader(String name, String value) {
 1545           // Not used
 1546       }
 1547   
 1548   
 1549       /**
 1550        * Add a Locale to the set of preferred Locales for this Request.  The
 1551        * first added Locale will be the first one returned by getLocales().
 1552        *
 1553        * @param locale The new preferred Locale
 1554        */
 1555       public void addLocale(Locale locale) {
 1556           locales.add(locale);
 1557       }
 1558   
 1559   
 1560       /**
 1561        * Add a parameter name and corresponding set of values to this Request.
 1562        * (This is used when restoring the original request on a form based
 1563        * login).
 1564        *
 1565        * @param name Name of this request parameter
 1566        * @param values Corresponding values for this request parameter
 1567        */
 1568       public void addParameter(String name, String values[]) {
 1569           coyoteRequest.getParameters().addParameterValues(name, values);
 1570       }
 1571   
 1572   
 1573       /**
 1574        * Clear the collection of Cookies associated with this Request.
 1575        */
 1576       public void clearCookies() {
 1577           cookiesParsed = true;
 1578           cookies = null;
 1579       }
 1580   
 1581   
 1582       /**
 1583        * Clear the collection of Headers associated with this Request.
 1584        */
 1585       public void clearHeaders() {
 1586           // Not used
 1587       }
 1588   
 1589   
 1590       /**
 1591        * Clear the collection of Locales associated with this Request.
 1592        */
 1593       public void clearLocales() {
 1594           locales.clear();
 1595       }
 1596   
 1597   
 1598       /**
 1599        * Clear the collection of parameters associated with this Request.
 1600        */
 1601       public void clearParameters() {
 1602           // Not used
 1603       }
 1604   
 1605   
 1606       /**
 1607        * Set the authentication type used for this request, if any; otherwise
 1608        * set the type to <code>null</code>.  Typical values are "BASIC",
 1609        * "DIGEST", or "SSL".
 1610        *
 1611        * @param type The authentication type used
 1612        */
 1613       public void setAuthType(String type) {
 1614           this.authType = type;
 1615       }
 1616   
 1617   
 1618       /**
 1619        * Set the context path for this Request.  This will normally be called
 1620        * when the associated Context is mapping the Request to a particular
 1621        * Wrapper.
 1622        *
 1623        * @param path The context path
 1624        */
 1625       public void setContextPath(String path) {
 1626   
 1627           if (path == null) {
 1628               mappingData.contextPath.setString("");
 1629           } else {
 1630               mappingData.contextPath.setString(path);
 1631           }
 1632   
 1633       }
 1634   
 1635   
 1636       /**
 1637        * Set the HTTP request method used for this Request.
 1638        *
 1639        * @param method The request method
 1640        */
 1641       public void setMethod(String method) {
 1642           // Not used
 1643       }
 1644   
 1645   
 1646       /**
 1647        * Set the query string for this Request.  This will normally be called
 1648        * by the HTTP Connector, when it parses the request headers.
 1649        *
 1650        * @param query The query string
 1651        */
 1652       public void setQueryString(String query) {
 1653           // Not used
 1654       }
 1655   
 1656   
 1657       /**
 1658        * Set the path information for this Request.  This will normally be called
 1659        * when the associated Context is mapping the Request to a particular
 1660        * Wrapper.
 1661        *
 1662        * @param path The path information
 1663        */
 1664       public void setPathInfo(String path) {
 1665           mappingData.pathInfo.setString(path);
 1666       }
 1667   
 1668   
 1669       /**
 1670        * Set a flag indicating whether or not the requested session ID for this
 1671        * request came in through a cookie.  This is normally called by the
 1672        * HTTP Connector, when it parses the request headers.
 1673        *
 1674        * @param flag The new flag
 1675        */
 1676       public void setRequestedSessionCookie(boolean flag) {
 1677   
 1678           this.requestedSessionCookie = flag;
 1679   
 1680       }
 1681   
 1682   
 1683       /**
 1684        * Set the requested session ID for this request.  This is normally called
 1685        * by the HTTP Connector, when it parses the request headers.
 1686        *
 1687        * @param id The new session id
 1688        */
 1689       public void setRequestedSessionId(String id) {
 1690   
 1691           this.requestedSessionId = id;
 1692   
 1693       }
 1694   
 1695   
 1696       /**
 1697        * Set a flag indicating whether or not the requested session ID for this
 1698        * request came in through a URL.  This is normally called by the
 1699        * HTTP Connector, when it parses the request headers.
 1700        *
 1701        * @param flag The new flag
 1702        */
 1703       public void setRequestedSessionURL(boolean flag) {
 1704   
 1705           this.requestedSessionURL = flag;
 1706   
 1707       }
 1708   
 1709   
 1710       /**
 1711        * Set the unparsed request URI for this Request.  This will normally be
 1712        * called by the HTTP Connector, when it parses the request headers.
 1713        *
 1714        * @param uri The request URI
 1715        */
 1716       public void setRequestURI(String uri) {
 1717           // Not used
 1718       }
 1719   
 1720   
 1721       /**
 1722        * Set the decoded request URI.
 1723        * 
 1724        * @param uri The decoded request URI
 1725        */
 1726       public void setDecodedRequestURI(String uri) {
 1727           // Not used
 1728       }
 1729   
 1730   
 1731       /**
 1732        * Get the decoded request URI.
 1733        * 
 1734        * @return the URL decoded request URI
 1735        */
 1736       public String getDecodedRequestURI() {
 1737           return (coyoteRequest.decodedURI().toString());
 1738       }
 1739   
 1740   
 1741       /**
 1742        * Get the decoded request URI.
 1743        * 
 1744        * @return the URL decoded request URI
 1745        */
 1746       public MessageBytes getDecodedRequestURIMB() {
 1747           return (coyoteRequest.decodedURI());
 1748       }
 1749   
 1750   
 1751       /**
 1752        * Set the servlet path for this Request.  This will normally be called
 1753        * when the associated Context is mapping the Request to a particular
 1754        * Wrapper.
 1755        *
 1756        * @param path The servlet path
 1757        */
 1758       public void setServletPath(String path) {
 1759           if (path != null)
 1760               mappingData.wrapperPath.setString(path);
 1761       }
 1762   
 1763   
 1764       /**
 1765        * Set the Principal who has been authenticated for this Request.  This
 1766        * value is also used to calculate the value to be returned by the
 1767        * <code>getRemoteUser()</code> method.
 1768        *
 1769        * @param principal The user Principal
 1770        */
 1771       public void setUserPrincipal(Principal principal) {
 1772   
 1773           if (Globals.IS_SECURITY_ENABLED){
 1774               HttpSession session = getSession(false);
 1775               if ( (subject != null) && 
 1776                    (!subject.getPrincipals().contains(principal)) ){
 1777                   subject.getPrincipals().add(principal);         
 1778               } else if (session != null &&
 1779                           session.getAttribute(Globals.SUBJECT_ATTR) == null) {
 1780                   subject = new Subject();
 1781                   subject.getPrincipals().add(principal);         
 1782               }
 1783               if (session != null){
 1784                   session.setAttribute(Globals.SUBJECT_ATTR, subject);
 1785               }
 1786           } 
 1787   
 1788           this.userPrincipal = principal;
 1789       }
 1790   
 1791   
 1792       // --------------------------------------------- HttpServletRequest Methods
 1793   
 1794   
 1795       /**
 1796        * Return the authentication type used for this Request.
 1797        */
 1798       public String getAuthType() {
 1799           return (authType);
 1800       }
 1801   
 1802   
 1803       /**
 1804        * Return the portion of the request URI used to select the Context
 1805        * of the Request.
 1806        */
 1807       public String getContextPath() {
 1808           return (mappingData.contextPath.toString());
 1809       }
 1810   
 1811   
 1812       /**
 1813        * Get the context path.
 1814        * 
 1815        * @return the context path
 1816        */
 1817       public MessageBytes getContextPathMB() {
 1818           return (mappingData.contextPath);
 1819       }
 1820   
 1821   
 1822       /**
 1823        * Return the set of Cookies received with this Request.
 1824        */
 1825       public Cookie[] getCookies() {
 1826   
 1827           if (!cookiesParsed)
 1828               parseCookies();
 1829   
 1830           return cookies;
 1831   
 1832       }
 1833   
 1834   
 1835       /**
 1836        * Set the set of cookies recieved with this Request.
 1837        */
 1838       public void setCookies(Cookie[] cookies) {
 1839   
 1840           this.cookies = cookies;
 1841   
 1842       }
 1843   
 1844   
 1845       /**
 1846        * Return the value of the specified date header, if any; otherwise
 1847        * return -1.
 1848        *
 1849        * @param name Name of the requested date header
 1850        *
 1851        * @exception IllegalArgumentException if the specified header value
 1852        *  cannot be converted to a date
 1853        */
 1854       public long getDateHeader(String name) {
 1855   
 1856           String value = getHeader(name);
 1857           if (value == null)
 1858               return (-1L);
 1859   
 1860           // Attempt to convert the date header in a variety of formats
 1861           long result = FastHttpDateFormat.parseDate(value, formats);
 1862           if (result != (-1L)) {
 1863               return result;
 1864           }
 1865           throw new IllegalArgumentException(value);
 1866   
 1867       }
 1868   
 1869   
 1870       /**
 1871        * Return the first value of the specified header, if any; otherwise,
 1872        * return <code>null</code>
 1873        *
 1874        * @param name Name of the requested header
 1875        */
 1876       public String getHeader(String name) {
 1877           return coyoteRequest.getHeader(name);
 1878       }
 1879   
 1880   
 1881       /**
 1882        * Return all of the values of the specified header, if any; otherwise,
 1883        * return an empty enumeration.
 1884        *
 1885        * @param name Name of the requested header
 1886        */
 1887       public Enumeration getHeaders(String name) {
 1888           return coyoteRequest.getMimeHeaders().values(name);
 1889       }
 1890   
 1891   
 1892       /**
 1893        * Return the names of all headers received with this request.
 1894        */
 1895       public Enumeration getHeaderNames() {
 1896           return coyoteRequest.getMimeHeaders().names();
 1897       }
 1898   
 1899   
 1900       /**
 1901        * Return the value of the specified header as an integer, or -1 if there
 1902        * is no such header for this request.
 1903        *
 1904        * @param name Name of the requested header
 1905        *
 1906        * @exception IllegalArgumentException if the specified header value
 1907        *  cannot be converted to an integer
 1908        */
 1909       public int getIntHeader(String name) {
 1910   
 1911           String value = getHeader(name);
 1912           if (value == null) {
 1913               return (-1);
 1914           } else {
 1915               return (Integer.parseInt(value));
 1916           }
 1917   
 1918       }
 1919   
 1920   
 1921       /**
 1922        * Return the HTTP request method used in this Request.
 1923        */
 1924       public String getMethod() {
 1925           return coyoteRequest.method().toString();
 1926       }
 1927   
 1928   
 1929       /**
 1930        * Return the path information associated with this Request.
 1931        */
 1932       public String getPathInfo() {
 1933           return (mappingData.pathInfo.toString());
 1934       }
 1935   
 1936   
 1937       /**
 1938        * Get the path info.
 1939        * 
 1940        * @return the path info
 1941        */
 1942       public MessageBytes getPathInfoMB() {
 1943           return (mappingData.pathInfo);
 1944       }
 1945   
 1946   
 1947       /**
 1948        * Return the extra path information for this request, translated
 1949        * to a real path.
 1950        */
 1951       public String getPathTranslated() {
 1952   
 1953           if (context == null)
 1954               return (null);
 1955   
 1956           if (getPathInfo() == null) {
 1957               return (null);
 1958           } else {
 1959               return (context.getServletContext().getRealPath(getPathInfo()));
 1960           }
 1961   
 1962       }
 1963   
 1964   
 1965       /**
 1966        * Return the query string associated with this request.
 1967        */
 1968       public String getQueryString() {
 1969           String queryString = coyoteRequest.queryString().toString();
 1970           if (queryString == null || queryString.equals("")) {
 1971               return (null);
 1972           } else {
 1973               return queryString;
 1974           }
 1975       }
 1976   
 1977   
 1978       /**
 1979        * Return the name of the remote user that has been authenticated
 1980        * for this Request.
 1981        */
 1982       public String getRemoteUser() {
 1983   
 1984           if (userPrincipal != null) {
 1985               return (userPrincipal.getName());
 1986           } else {
 1987               return (null);
 1988           }
 1989   
 1990       }
 1991   
 1992   
 1993       /**
 1994        * Get the request path.
 1995        * 
 1996        * @return the request path
 1997        */
 1998       public MessageBytes getRequestPathMB() {
 1999           return (mappingData.requestPath);
 2000       }
 2001   
 2002   
 2003       /**
 2004        * Return the session identifier included in this request, if any.
 2005        */
 2006       public String getRequestedSessionId() {
 2007           return (requestedSessionId);
 2008       }
 2009   
 2010   
 2011       /**
 2012        * Return the request URI for this request.
 2013        */
 2014       public String getRequestURI() {
 2015           return coyoteRequest.requestURI().toString();
 2016       }
 2017   
 2018   
 2019       /**
 2020        * Reconstructs the URL the client used to make the request.
 2021        * The returned URL contains a protocol, server name, port
 2022        * number, and server path, but it does not include query
 2023        * string parameters.
 2024        * <p>
 2025        * Because this method returns a <code>StringBuffer</code>,
 2026        * not a <code>String</code>, you can modify the URL easily,
 2027        * for example, to append query parameters.
 2028        * <p>
 2029        * This method is useful for creating redirect messages and
 2030        * for reporting errors.
 2031        *
 2032        * @return A <code>StringBuffer</code> object containing the
 2033        *  reconstructed URL
 2034        */
 2035       public StringBuffer getRequestURL() {
 2036   
 2037           StringBuffer url = new StringBuffer();
 2038           String scheme = getScheme();
 2039           int port = getServerPort();
 2040           if (port < 0)
 2041               port = 80; // Work around java.net.URL bug
 2042   
 2043           url.append(scheme);
 2044           url.append("://");
 2045           url.append(getServerName());
 2046           if ((scheme.equals("http") && (port != 80))
 2047               || (scheme.equals("https") && (port != 443))) {
 2048               url.append(':');
 2049               url.append(port);
 2050           }
 2051           url.append(getRequestURI());
 2052   
 2053           return (url);
 2054   
 2055       }
 2056   
 2057   
 2058       /**
 2059        * Return the portion of the request URI used to select the servlet
 2060        * that will process this request.
 2061        */
 2062       public String getServletPath() {
 2063           return (mappingData.wrapperPath.toString());
 2064       }
 2065   
 2066   
 2067       /**
 2068        * Get the servlet path.
 2069        * 
 2070        * @return the servlet path
 2071        */
 2072       public MessageBytes getServletPathMB() {
 2073           return (mappingData.wrapperPath);
 2074       }
 2075   
 2076   
 2077       /**
 2078        * Return the session associated with this Request, creating one
 2079        * if necessary.
 2080        */
 2081       public HttpSession getSession() {
 2082           Session session = doGetSession(true);
 2083           if (session != null) {
 2084               return session.getSession();
 2085           } else {
 2086               return null;
 2087           }
 2088       }
 2089   
 2090   
 2091       /**
 2092        * Return the session associated with this Request, creating one
 2093        * if necessary and requested.
 2094        *
 2095        * @param create Create a new session if one does not exist
 2096        */
 2097       public HttpSession getSession(boolean create) {
 2098           Session session = doGetSession(create);
 2099           if (session != null) {
 2100               return session.getSession();
 2101           } else {
 2102               return null;
 2103           }
 2104       }
 2105   
 2106   
 2107       /**
 2108        * Return <code>true</code> if the session identifier included in this
 2109        * request came from a cookie.
 2110        */
 2111       public boolean isRequestedSessionIdFromCookie() {
 2112   
 2113           if (requestedSessionId != null)
 2114               return (requestedSessionCookie);
 2115           else
 2116               return (false);
 2117   
 2118       }
 2119   
 2120   
 2121       /**
 2122        * Return <code>true</code> if the session identifier included in this
 2123        * request came from the request URI.
 2124        */
 2125       public boolean isRequestedSessionIdFromURL() {
 2126   
 2127           if (requestedSessionId != null)
 2128               return (requestedSessionURL);
 2129           else
 2130               return (false);
 2131   
 2132       }
 2133   
 2134   
 2135       /**
 2136        * Return <code>true</code> if the session identifier included in this
 2137        * request came from the request URI.
 2138        *
 2139        * @deprecated As of Version 2.1 of the Java Servlet API, use
 2140        *  <code>isRequestedSessionIdFromURL()</code> instead.
 2141        */
 2142       public boolean isRequestedSessionIdFromUrl() {
 2143           return (isRequestedSessionIdFromURL());
 2144       }
 2145   
 2146   
 2147       /**
 2148        * Return <code>true</code> if the session identifier included in this
 2149        * request identifies a valid session.
 2150        */
 2151       public boolean isRequestedSessionIdValid() {
 2152   
 2153           if (requestedSessionId == null)
 2154               return (false);
 2155           if (context == null)
 2156               return (false);
 2157           Manager manager = context.getManager();
 2158           if (manager == null)
 2159               return (false);
 2160           Session session = null;
 2161           try {
 2162               session = manager.findSession(requestedSessionId);
 2163           } catch (IOException e) {
 2164               session = null;
 2165           }
 2166           if ((session != null) && session.isValid())
 2167               return (true);
 2168           else
 2169               return (false);
 2170   
 2171       }
 2172   
 2173   
 2174       /**
 2175        * Return <code>true</code> if the authenticated user principal
 2176        * possesses the specified role name.
 2177        *
 2178        * @param role Role name to be validated
 2179        */
 2180       public boolean isUserInRole(String role) {
 2181   
 2182           // Have we got an authenticated principal at all?
 2183           if (userPrincipal == null)
 2184               return (false);
 2185   
 2186           // Identify the Realm we will use for checking role assignmenets
 2187           if (context == null)
 2188               return (false);
 2189           Realm realm = context.getRealm();
 2190           if (realm == null)
 2191               return (false);
 2192   
 2193           // Check for a role alias defined in a <security-role-ref> element
 2194           if (wrapper != null) {
 2195               String realRole = wrapper.findSecurityReference(role);
 2196               if ((realRole != null) &&
 2197                   realm.hasRole(userPrincipal, realRole))
 2198                   return (true);
 2199           }
 2200   
 2201           // Check for a role defined directly as a <security-role>
 2202           return (realm.hasRole(userPrincipal, role));
 2203   
 2204       }
 2205   
 2206   
 2207       /**
 2208        * Return the principal that has been authenticated for this Request.
 2209        */
 2210       public Principal getPrincipal() {
 2211           return (userPrincipal);
 2212       }
 2213   
 2214   
 2215       /**
 2216        * Return the principal that has been authenticated for this Request.
 2217        */
 2218       public Principal getUserPrincipal() {
 2219           if (userPrincipal instanceof GenericPrincipal) {
 2220               return ((GenericPrincipal) userPrincipal).getUserPrincipal();
 2221           } else {
 2222               return (userPrincipal);
 2223           }
 2224       }
 2225   
 2226   
 2227       /**
 2228        * Return the session associated with this Request, creating one
 2229        * if necessary.
 2230        */
 2231       public Session getSessionInternal() {
 2232           return doGetSession(true);
 2233       }
 2234   
 2235   
 2236       /**
 2237        * Change the ID of the session that this request is associated with. There
 2238        * are several things that may trigger an ID change. These include moving
 2239        * between nodes in a cluster and session fixation prevention during the
 2240        * authentication process.
 2241        * 
 2242        * @param session   The session to change the session ID for
 2243        */
 2244       public void changeSessionId(String newSessionId) {
 2245           // This should only ever be called if there was an old session ID but
 2246           // double check to be sure
 2247           if (requestedSessionId != null && requestedSessionId.length() > 0) {
 2248               requestedSessionId = newSessionId;
 2249           }
 2250           
 2251           if (context != null && !context.getCookies())
 2252               return;
 2253           
 2254           if (response != null) {
 2255               Cookie newCookie = new Cookie(Globals.SESSION_COOKIE_NAME,
 2256                       newSessionId);
 2257               newCookie.setMaxAge(-1);
 2258               String contextPath = null;
 2259               if (!response.getConnector().getEmptySessionPath()
 2260                       && (context != null)) {
 2261                   contextPath = context.getEncodedPath();
 2262               }
 2263               if ((contextPath != null) && (contextPath.length() > 0)) {
 2264                   newCookie.setPath(contextPath);
 2265               } else {
 2266                   newCookie.setPath("/");
 2267               }
 2268               if (isSecure()) {
 2269                   newCookie.setSecure(true);
 2270               }
 2271               if (context == null) {
 2272               	response.addCookieInternal(newCookie, false);
 2273               } else {
 2274               	response.addCookieInternal(newCookie, context.getUseHttpOnly());
 2275               }
 2276           }
 2277       }
 2278   
 2279       
 2280       /**
 2281        * Return the session associated with this Request, creating one
 2282        * if necessary and requested.
 2283        *
 2284        * @param create Create a new session if one does not exist
 2285        */
 2286       public Session getSessionInternal(boolean create) {
 2287           return doGetSession(create);
 2288       }
 2289   
 2290   
 2291       /**
 2292        * Get the event associated with the request.
 2293        * @return
 2294        */
 2295       public CometEventImpl getEvent() {
 2296           if (event == null) {
 2297               event = new CometEventImpl(this, response);
 2298           }
 2299           return event;
 2300       }
 2301       
 2302       
 2303       /**
 2304        * Return true if the current request is handling Comet traffic.
 2305        */
 2306       public boolean isComet() {
 2307           return comet;
 2308       }
 2309   
 2310       
 2311       /**
 2312        * Set comet state.
 2313        */
 2314       public void setComet(boolean comet) {
 2315           this.comet = comet;
 2316       }
 2317   
 2318       /**
 2319        * return true if we have parsed parameters
 2320        */
 2321       public boolean isParametersParsed() {
 2322           return parametersParsed;
 2323       }    
 2324       
 2325       /**
 2326        * Return true if bytes are available.
 2327        */
 2328       public boolean getAvailable() {
 2329           return (inputBuffer.available() > 0);
 2330       }
 2331   
 2332       public void cometClose() {
 2333           coyoteRequest.action(ActionCode.ACTION_COMET_CLOSE,getEvent());
 2334       }
 2335       
 2336       public void setCometTimeout(long timeout) {
 2337           coyoteRequest.action(ActionCode.ACTION_COMET_SETTIMEOUT,new Long(timeout));
 2338       }
 2339       
 2340       // ------------------------------------------------------ Protected Methods
 2341   
 2342   
 2343       protected Session doGetSession(boolean create) {
 2344   
 2345           // There cannot be a session if no context has been assigned yet
 2346           if (context == null)
 2347               return (null);
 2348   
 2349           // Return the current session if it exists and is valid
 2350           if ((session != null) && !session.isValid())
 2351               session = null;
 2352           if (session != null)
 2353               return (session);
 2354   
 2355           // Return the requested session if it exists and is valid
 2356           Manager manager = null;
 2357           if (context != null)
 2358               manager = context.getManager();
 2359           if (manager == null)
 2360               return (null);      // Sessions are not supported
 2361           if (requestedSessionId != null) {
 2362               try {
 2363                   session = manager.findSession(requestedSessionId);
 2364               } catch (IOException e) {
 2365                   session = null;
 2366               }
 2367               if ((session != null) && !session.isValid())
 2368                   session = null;
 2369               if (session != null) {
 2370                   session.access();
 2371                   return (session);
 2372               }
 2373           }
 2374   
 2375           // Create a new session if requested and the response is not committed
 2376           if (!create)
 2377               return (null);
 2378           if ((context != null) && (response != null) &&
 2379               context.getCookies() &&
 2380               response.getResponse().isCommitted()) {
 2381               throw new IllegalStateException
 2382                 (sm.getString("coyoteRequest.sessionCreateCommitted"));
 2383           }
 2384   
 2385           // Attempt to reuse session id if one was submitted in a cookie
 2386           // Do not reuse the session id if it is from a URL, to prevent possible
 2387           // phishing attacks
 2388           if (connector.getEmptySessionPath() 
 2389                   && isRequestedSessionIdFromCookie()) {
 2390               session = manager.createSession(getRequestedSessionId());
 2391           } else {
 2392               session = manager.createSession(null);
 2393           }
 2394   
 2395           // Creating a new session cookie based on that session
 2396           if ((session != null) && (getContext() != null)
 2397                  && getContext().getCookies()) {
 2398               Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
 2399                                          session.getIdInternal());
 2400               configureSessionCookie(cookie);
 2401               response.addCookieInternal(cookie, context.getUseHttpOnly());
 2402           }
 2403   
 2404           if (session != null) {
 2405               session.access();
 2406               return (session);
 2407           } else {
 2408               return (null);
 2409           }
 2410   
 2411       }
 2412   
 2413       /**
 2414        * Configures the given JSESSIONID cookie.
 2415        *
 2416        * @param cookie The JSESSIONID cookie to be configured
 2417        */
 2418       protected void configureSessionCookie(Cookie cookie) {
 2419           cookie.setMaxAge(-1);
 2420           String contextPath = null;
 2421           if (!connector.getEmptySessionPath() && (getContext() != null)) {
 2422               contextPath = getContext().getEncodedPath();
 2423           }
 2424           if ((contextPath != null) && (contextPath.length() > 0)) {
 2425               cookie.setPath(contextPath);
 2426           } else {
 2427               cookie.setPath("/");
 2428           }
 2429           if (isSecure()) {
 2430               cookie.setSecure(true);
 2431           }
 2432       }
 2433       
 2434       protected String unescape(String s) {
 2435           if (s==null) return null;
 2436           if (s.indexOf('\\') == -1) return s;
 2437           StringBuffer buf = new StringBuffer();
 2438           for (int i=0; i<s.length(); i++) {
 2439               char c = s.charAt(i);
 2440               if (c!='\\') buf.append(c);
 2441               else {
 2442                   if (++i >= s.length()) throw new IllegalArgumentException();//invalid escape, hence invalid cookie
 2443                   c = s.charAt(i);
 2444                   buf.append(c);
 2445               }
 2446           }
 2447           return buf.toString();
 2448       }
 2449   
 2450       /**
 2451        * Parse cookies.
 2452        */
 2453       protected void parseCookies() {
 2454   
 2455           cookiesParsed = true;
 2456   
 2457           Cookies serverCookies = coyoteRequest.getCookies();
 2458           int count = serverCookies.getCookieCount();
 2459           if (count <= 0)
 2460               return;
 2461   
 2462           cookies = new Cookie[count];
 2463   
 2464           int idx=0;
 2465           for (int i = 0; i < count; i++) {
 2466               ServerCookie scookie = serverCookies.getCookie(i);
 2467               try {
 2468                   /*
 2469                   we must unescape the '\\' escape character
 2470                   */
 2471                   Cookie cookie = new Cookie(scookie.getName().toString(),null);
 2472                   int version = scookie.getVersion();
 2473                   cookie.setVersion(version);
 2474                   cookie.setValue(unescape(scookie.getValue().toString()));
 2475                   cookie.setPath(unescape(scookie.getPath().toString()));
 2476                   String domain = scookie.getDomain().toString();
 2477                   if (domain!=null) cookie.setDomain(unescape(domain));//avoid NPE
 2478                   String comment = scookie.getComment().toString();
 2479                   cookie.setComment(version==1?unescape(comment):null);
 2480                   cookies[idx++] = cookie;
 2481               } catch(IllegalArgumentException e) {
 2482                   // Ignore bad cookie
 2483               }
 2484           }
 2485           if( idx < count ) {
 2486               Cookie [] ncookies = new Cookie[idx];
 2487               System.arraycopy(cookies, 0, ncookies, 0, idx);
 2488               cookies = ncookies;
 2489           }
 2490   
 2491       }
 2492   
 2493       /**
 2494        * Parse request parameters.
 2495        */
 2496       protected void parseParameters() {
 2497   
 2498           parametersParsed = true;
 2499   
 2500           Parameters parameters = coyoteRequest.getParameters();
 2501   
 2502           // getCharacterEncoding() may have been overridden to search for
 2503           // hidden form field containing request encoding
 2504           String enc = getCharacterEncoding();
 2505   
 2506           boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
 2507           if (enc != null) {
 2508               parameters.setEncoding(enc);
 2509               if (useBodyEncodingForURI) {
 2510                   parameters.setQueryStringEncoding(enc);
 2511               }
 2512           } else {
 2513               parameters.setEncoding
 2514                   (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
 2515               if (useBodyEncodingForURI) {
 2516                   parameters.setQueryStringEncoding
 2517                       (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
 2518               }
 2519           }
 2520   
 2521           parameters.handleQueryParameters();
 2522   
 2523           if (usingInputStream || usingReader)
 2524               return;
 2525   
 2526           if (!getMethod().equalsIgnoreCase("POST"))
 2527               return;
 2528   
 2529           String contentType = getContentType();
 2530           if (contentType == null)
 2531               contentType = "";
 2532           int semicolon = contentType.indexOf(';');
 2533           if (semicolon >= 0) {
 2534               contentType = contentType.substring(0, semicolon).trim();
 2535           } else {
 2536               contentType = contentType.trim();
 2537           }
 2538           if (!("application/x-www-form-urlencoded".equals(contentType)))
 2539               return;
 2540   
 2541           int len = getContentLength();
 2542   
 2543           if (len > 0) {
 2544               int maxPostSize = connector.getMaxPostSize();
 2545               if ((maxPostSize > 0) && (len > maxPostSize)) {
 2546                   if (context.getLogger().isDebugEnabled()) {
 2547                       context.getLogger().debug(
 2548                               sm.getString("coyoteRequest.postTooLarge"));
 2549                   }
 2550                   return;
 2551               }
 2552               byte[] formData = null;
 2553               if (len < CACHED_POST_LEN) {
 2554                   if (postData == null)
 2555                       postData = new byte[CACHED_POST_LEN];
 2556                   formData = postData;
 2557               } else {
 2558                   formData = new byte[len];
 2559               }
 2560               try {
 2561                   if (readPostBody(formData, len) != len) {
 2562                       return;
 2563                   }
 2564               } catch (IOException e) {
 2565                   // Client disconnect
 2566                   if (context.getLogger().isDebugEnabled()) {
 2567                       context.getLogger().debug(
 2568                               sm.getString("coyoteRequest.parseParameters"), e);
 2569                   }
 2570                   return;
 2571               }
 2572               parameters.processParameters(formData, 0, len);
 2573           } else if ("chunked".equalsIgnoreCase(
 2574                   coyoteRequest.getHeader("transfer-encoding"))) {
 2575               byte[] formData = null;
 2576               try {
 2577                   formData = readChunkedPostBody();
 2578               } catch (IOException e) {
 2579                   // Client disconnect
 2580                   if (context.getLogger().isDebugEnabled()) {
 2581                       context.getLogger().debug(
 2582                               sm.getString("coyoteRequest.parseParameters"), e);
 2583                   }
 2584                   return;
 2585               }
 2586               parameters.processParameters(formData, 0, formData.length);
 2587           }
 2588   
 2589       }
 2590   
 2591   
 2592       /**
 2593        * Read post body in an array.
 2594        */
 2595       protected int readPostBody(byte body[], int len)
 2596           throws IOException {
 2597   
 2598           int offset = 0;
 2599           do {
 2600               int inputLen = getStream().read(body, offset, len - offset);
 2601               if (inputLen <= 0) {
 2602                   return offset;
 2603               }
 2604               offset += inputLen;
 2605           } while ((len - offset) > 0);
 2606           return len;
 2607   
 2608       }
 2609   
 2610   
 2611       /**
 2612        * Read chunked post body.
 2613        */
 2614       protected byte[] readChunkedPostBody() throws IOException {
 2615           ByteChunk body = new ByteChunk();
 2616           
 2617           byte[] buffer = new byte[CACHED_POST_LEN];
 2618           
 2619           int len = 0;
 2620           while (len > -1) {
 2621               len = getStream().read(buffer, 0, CACHED_POST_LEN);
 2622               if (connector.getMaxPostSize() > 0 &&
 2623                       (body.getLength() + len) > connector.getMaxPostSize()) {
 2624                   // Too much data
 2625                   throw new IllegalArgumentException(
 2626                           sm.getString("coyoteRequest.chunkedPostTooLarge"));
 2627               }
 2628               if (len > 0) {
 2629                   body.append(buffer, 0, len);
 2630               }
 2631           }
 2632           if (body.getLength() < body.getBuffer().length) {
 2633               int length = body.getLength();
 2634               byte[] result = new byte[length];
 2635               System.arraycopy(body.getBuffer(), 0, result, 0, length);
 2636               return result;
 2637           } else {
 2638               return body.getBuffer();
 2639           }
 2640       }
 2641       
 2642       
 2643       /**
 2644        * Parse request locales.
 2645        */
 2646       protected void parseLocales() {
 2647   
 2648           localesParsed = true;
 2649   
 2650           Enumeration values = getHeaders("accept-language");
 2651   
 2652           while (values.hasMoreElements()) {
 2653               String value = values.nextElement().toString();
 2654               parseLocalesHeader(value);
 2655           }
 2656   
 2657       }
 2658   
 2659   
 2660       /**
 2661        * Parse accept-language header value.
 2662        */
 2663       protected void parseLocalesHeader(String value) {
 2664   
 2665           // Store the accumulated languages that have been requested in
 2666           // a local collection, sorted by the quality value (so we can
 2667           // add Locales in descending order).  The values will be ArrayLists
 2668           // containing the corresponding Locales to be added
 2669           TreeMap locales = new TreeMap();
 2670   
 2671           // Preprocess the value to remove all whitespace
 2672           int white = value.indexOf(' ');
 2673           if (white < 0)
 2674               white = value.indexOf('\t');
 2675           if (white >= 0) {
 2676               StringBuffer sb = new StringBuffer();
 2677               int len = value.length();
 2678               for (int i = 0; i < len; i++) {
 2679                   char ch = value.charAt(i);
 2680                   if ((ch != ' ') && (ch != '\t'))
 2681                       sb.append(ch);
 2682               }
 2683               value = sb.toString();
 2684           }
 2685   
 2686           // Process each comma-delimited language specification
 2687           parser.setString(value);        // ASSERT: parser is available to us
 2688           int length = parser.getLength();
 2689           while (true) {
 2690   
 2691               // Extract the next comma-delimited entry
 2692               int start = parser.getIndex();
 2693               if (start >= length)
 2694                   break;
 2695               int end = parser.findChar(',');
 2696               String entry = parser.extract(start, end).trim();
 2697               parser.advance();   // For the following entry
 2698   
 2699               // Extract the quality factor for this entry
 2700               double quality = 1.0;
 2701               int semi = entry.indexOf(";q=");
 2702               if (semi >= 0) {
 2703                   try {
 2704                       quality = Double.parseDouble(entry.substring(semi + 3));
 2705                   } catch (NumberFormatException e) {
 2706                       quality = 0.0;
 2707                   }
 2708                   entry = entry.substring(0, semi);
 2709               }
 2710   
 2711               // Skip entries we are not going to keep track of
 2712               if (quality < 0.00005)
 2713                   continue;       // Zero (or effectively zero) quality factors
 2714               if ("*".equals(entry))
 2715                   continue;       // FIXME - "*" entries are not handled
 2716   
 2717               // Extract the language and country for this entry
 2718               String language = null;
 2719               String country = null;
 2720               String variant = null;
 2721               int dash = entry.indexOf('-');
 2722               if (dash < 0) {
 2723                   language = entry;
 2724                   country = "";
 2725                   variant = "";
 2726               } else {
 2727                   language = entry.substring(0, dash);
 2728                   country = entry.substring(dash + 1);
 2729                   int vDash = country.indexOf('-');
 2730                   if (vDash > 0) {
 2731                       String cTemp = country.substring(0, vDash);
 2732                       variant = country.substring(vDash + 1);
 2733                       country = cTemp;
 2734                   } else {
 2735                       variant = "";
 2736                   }
 2737               }
 2738               if (!isAlpha(language) || !isAlpha(country) || !isAlpha(variant)) {
 2739                   continue;
 2740               }
 2741   
 2742               // Add a new Locale to the list of Locales for this quality level
 2743               Locale locale = new Locale(language, country, variant);
 2744               Double key = new Double(-quality);  // Reverse the order
 2745               ArrayList values = (ArrayList) locales.get(key);
 2746               if (values == null) {
 2747                   values = new ArrayList();
 2748                   locales.put(key, values);
 2749               }
 2750               values.add(locale);
 2751   
 2752           }
 2753   
 2754           // Process the quality values in highest->lowest order (due to
 2755           // negating the Double value when creating the key)
 2756           Iterator keys = locales.keySet().iterator();
 2757           while (keys.hasNext()) {
 2758               Double key = (Double) keys.next();
 2759               ArrayList list = (ArrayList) locales.get(key);
 2760               Iterator values = list.iterator();
 2761               while (values.hasNext()) {
 2762                   Locale locale = (Locale) values.next();
 2763                   addLocale(locale);
 2764               }
 2765           }
 2766   
 2767       }
 2768   
 2769       
 2770       protected static final boolean isAlpha(String value) {
 2771           for (int i = 0; i < value.length(); i++) {
 2772               char c = value.charAt(i);
 2773               if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
 2774                   return false;
 2775               }
 2776           }
 2777           return true;
 2778       }
 2779       
 2780   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » connector » [javadoc | source]