0001: /*
0002: * Copyright 1999,2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.coyote.tomcat5;
0018:
0019: import java.io.InputStream;
0020: import java.io.IOException;
0021: import java.io.BufferedReader;
0022: import java.io.UnsupportedEncodingException;
0023: import java.net.InetAddress;
0024: import java.net.Socket;
0025: import java.security.Principal;
0026: import java.text.SimpleDateFormat;
0027: import java.util.ArrayList;
0028: import java.util.Enumeration;
0029: import java.util.HashMap;
0030: import java.util.Iterator;
0031: import java.util.Locale;
0032: import java.util.Map;
0033: import java.util.TimeZone;
0034: import java.util.TreeMap;
0035:
0036: import javax.security.auth.Subject;
0037: import javax.servlet.FilterChain;
0038: import javax.servlet.RequestDispatcher;
0039: import javax.servlet.ServletContext;
0040: import javax.servlet.ServletInputStream;
0041: import javax.servlet.ServletRequest;
0042: import javax.servlet.ServletRequestAttributeEvent;
0043: import javax.servlet.ServletRequestAttributeListener;
0044: import javax.servlet.http.Cookie;
0045: import javax.servlet.http.HttpServletRequest;
0046: import javax.servlet.http.HttpServletResponse;
0047: import javax.servlet.http.HttpSession;
0048:
0049: import org.apache.tomcat.util.buf.B2CConverter;
0050: import org.apache.tomcat.util.buf.MessageBytes;
0051: import org.apache.tomcat.util.http.Cookies;
0052: import org.apache.tomcat.util.http.FastHttpDateFormat;
0053: import org.apache.tomcat.util.http.Parameters;
0054: import org.apache.tomcat.util.http.ServerCookie;
0055: import org.apache.tomcat.util.http.mapper.MappingData;
0056:
0057: import org.apache.coyote.ActionCode;
0058: import org.apache.coyote.Request;
0059:
0060: import org.apache.catalina.Connector;
0061: import org.apache.catalina.Context;
0062: import org.apache.catalina.Globals;
0063: import org.apache.catalina.Host;
0064: import org.apache.catalina.HttpRequest;
0065: import org.apache.catalina.Logger;
0066: import org.apache.catalina.Manager;
0067: import org.apache.catalina.Realm;
0068: import org.apache.catalina.Session;
0069: import org.apache.catalina.ValveContext;
0070: import org.apache.catalina.Wrapper;
0071:
0072: import org.apache.catalina.core.ApplicationFilterFactory;
0073: import org.apache.catalina.util.Enumerator;
0074: import org.apache.catalina.util.ParameterMap;
0075: import org.apache.catalina.util.RequestUtil;
0076: import org.apache.catalina.util.StringManager;
0077: import org.apache.catalina.util.StringParser;
0078: import org.apache.commons.logging.Log;
0079:
0080: /**
0081: * Wrapper object for the Coyote request.
0082: *
0083: * @author Remy Maucherat
0084: * @author Craig R. McClanahan
0085: * @version $Revision: 1.37 $ $Date: 2004/06/07 16:54:58 $
0086: */
0087:
0088: public class CoyoteRequest implements HttpRequest, HttpServletRequest {
0089:
0090: // ----------------------------------------------------------- Constructors
0091:
0092: public CoyoteRequest() {
0093:
0094: formats[0].setTimeZone(TimeZone.getTimeZone("GMT"));
0095: formats[1].setTimeZone(TimeZone.getTimeZone("GMT"));
0096: formats[2].setTimeZone(TimeZone.getTimeZone("GMT"));
0097:
0098: }
0099:
0100: // ------------------------------------------------------------- Properties
0101:
0102: /**
0103: * Coyote request.
0104: */
0105: protected Request coyoteRequest;
0106:
0107: /**
0108: * Set the Coyote request.
0109: *
0110: * @param coyoteRequest The Coyote request
0111: */
0112: public void setCoyoteRequest(Request coyoteRequest) {
0113: this .coyoteRequest = coyoteRequest;
0114: inputBuffer.setRequest(coyoteRequest);
0115: }
0116:
0117: /**
0118: * Get the Coyote request.
0119: */
0120: public Request getCoyoteRequest() {
0121: return (this .coyoteRequest);
0122: }
0123:
0124: // ----------------------------------------------------- Instance Variables
0125:
0126: /**
0127: * The string manager for this package.
0128: */
0129: protected static StringManager sm = StringManager
0130: .getManager(Constants.Package);
0131:
0132: /**
0133: * The set of cookies associated with this Request.
0134: */
0135: protected Cookie[] cookies = null;
0136:
0137: /**
0138: * The set of SimpleDateFormat formats to use in getDateHeader().
0139: */
0140: protected SimpleDateFormat formats[] = {
0141: new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
0142: Locale.US),
0143: new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
0144: Locale.US),
0145: new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
0146:
0147: /**
0148: * The default Locale if none are specified.
0149: */
0150: protected static Locale defaultLocale = Locale.getDefault();
0151:
0152: /**
0153: * The attributes associated with this Request, keyed by attribute name.
0154: */
0155: protected HashMap attributes = new HashMap();
0156:
0157: /**
0158: * List of read only attributes for this Request.
0159: */
0160: private HashMap readOnlyAttributes = new HashMap();
0161:
0162: /**
0163: * The preferred Locales assocaited with this Request.
0164: */
0165: protected ArrayList locales = new ArrayList();
0166:
0167: /**
0168: * Internal notes associated with this request by Catalina components
0169: * and event listeners.
0170: */
0171: private transient HashMap notes = new HashMap();
0172:
0173: /**
0174: * Authentication type.
0175: */
0176: protected String authType = null;
0177:
0178: /**
0179: * The current dispatcher type.
0180: */
0181: protected Object dispatcherType = null;
0182:
0183: /**
0184: * The associated input buffer.
0185: */
0186: protected InputBuffer inputBuffer = new InputBuffer();
0187:
0188: /**
0189: * ServletInputStream.
0190: */
0191: protected CoyoteInputStream inputStream = new CoyoteInputStream(
0192: inputBuffer);
0193:
0194: /**
0195: * Reader.
0196: */
0197: protected CoyoteReader reader = new CoyoteReader(inputBuffer);
0198:
0199: /**
0200: * Using stream flag.
0201: */
0202: protected boolean usingInputStream = false;
0203:
0204: /**
0205: * Using writer flag.
0206: */
0207: protected boolean usingReader = false;
0208:
0209: /**
0210: * User principal.
0211: */
0212: protected Principal userPrincipal = null;
0213:
0214: /**
0215: * Session parsed flag.
0216: */
0217: protected boolean sessionParsed = false;
0218:
0219: /**
0220: * Request parameters parsed flag.
0221: */
0222: protected boolean requestParametersParsed = false;
0223:
0224: /**
0225: * Cookies parsed flag.
0226: */
0227: protected boolean cookiesParsed = false;
0228:
0229: /**
0230: * Secure flag.
0231: */
0232: protected boolean secure = false;
0233:
0234: /**
0235: * The Subject associated with the current AccessControllerContext
0236: */
0237: protected transient Subject subject = null;
0238:
0239: /**
0240: * Post data buffer.
0241: */
0242: protected static int CACHED_POST_LEN = 8192;
0243: protected byte[] postData = null;
0244:
0245: /**
0246: * Hash map used in the getParametersMap method.
0247: */
0248: protected ParameterMap parameterMap = new ParameterMap();
0249:
0250: /**
0251: * The currently active session for this request.
0252: */
0253: protected Session session = null;
0254:
0255: /**
0256: * The current request dispatcher path.
0257: */
0258: protected Object requestDispatcherPath = null;
0259:
0260: /**
0261: * Was the requested session ID received in a cookie?
0262: */
0263: protected boolean requestedSessionCookie = false;
0264:
0265: /**
0266: * The requested session ID (if any) for this request.
0267: */
0268: protected String requestedSessionId = null;
0269:
0270: /**
0271: * Was the requested session ID received in a URL?
0272: */
0273: protected boolean requestedSessionURL = false;
0274:
0275: /**
0276: * The socket through which this Request was received.
0277: */
0278: protected Socket socket = null;
0279:
0280: /**
0281: * Parse locales.
0282: */
0283: protected boolean localesParsed = false;
0284:
0285: /**
0286: * The string parser we will use for parsing request lines.
0287: */
0288: private StringParser parser = new StringParser();
0289:
0290: /**
0291: * Local port
0292: */
0293: protected int localPort = -1;
0294:
0295: /**
0296: * Remote address.
0297: */
0298: protected String remoteAddr = null;
0299:
0300: /**
0301: * Remote host.
0302: */
0303: protected String remoteHost = null;
0304:
0305: /**
0306: * Remote port
0307: */
0308: protected int remotePort = -1;
0309:
0310: /**
0311: * Local address
0312: */
0313: protected String localAddr = null;
0314:
0315: /**
0316: * Local address
0317: */
0318: protected String localName = null;
0319:
0320: /** After the request is mapped to a ServletContext, we can also
0321: * map it to a logger.
0322: */
0323: protected Log log = null;
0324:
0325: // --------------------------------------------------------- Public Methods
0326:
0327: /**
0328: * Release all object references, and initialize instance variables, in
0329: * preparation for reuse of this object.
0330: */
0331: public void recycle() {
0332:
0333: context = null;
0334: wrapper = null;
0335:
0336: dispatcherType = null;
0337: requestDispatcherPath = null;
0338:
0339: authType = null;
0340: inputBuffer.recycle();
0341: usingInputStream = false;
0342: usingReader = false;
0343: userPrincipal = null;
0344: subject = null;
0345: sessionParsed = false;
0346: requestParametersParsed = false;
0347: cookiesParsed = false;
0348: locales.clear();
0349: localesParsed = false;
0350: secure = false;
0351: remoteAddr = null;
0352: remoteHost = null;
0353: remotePort = -1;
0354: localPort = -1;
0355: localAddr = null;
0356: localName = null;
0357:
0358: attributes.clear();
0359: notes.clear();
0360: cookies = null;
0361:
0362: if (session != null) {
0363: session.endAccess();
0364: }
0365: session = null;
0366: requestedSessionCookie = false;
0367: requestedSessionId = null;
0368: requestedSessionURL = false;
0369: log = null;
0370:
0371: parameterMap.setLocked(false);
0372: parameterMap.clear();
0373:
0374: mappingData.recycle();
0375:
0376: if (Constants.SECURITY) {
0377: if (facade != null) {
0378: facade.clear();
0379: facade = null;
0380: }
0381: if (inputStream != null) {
0382: inputStream.clear();
0383: inputStream = null;
0384: }
0385: if (reader != null) {
0386: reader.clear();
0387: reader = null;
0388: }
0389: }
0390:
0391: }
0392:
0393: // -------------------------------------------------------- Request Methods
0394:
0395: /**
0396: * Return the authorization credentials sent with this request.
0397: */
0398: public String getAuthorization() {
0399: return (coyoteRequest.getHeader(Constants.AUTHORIZATION_HEADER));
0400: }
0401:
0402: /**
0403: * Set the authorization credentials sent with this request.
0404: *
0405: * @param authorization The new authorization credentials
0406: */
0407: public void setAuthorization(String authorization) {
0408: // Not used
0409: }
0410:
0411: /**
0412: * Associated Catalina connector.
0413: */
0414: protected CoyoteConnector connector;
0415:
0416: /**
0417: * Return the Connector through which this Request was received.
0418: */
0419: public Connector getConnector() {
0420: return (this .connector);
0421: }
0422:
0423: /**
0424: * Set the Connector through which this Request was received.
0425: *
0426: * @param connector The new connector
0427: */
0428: public void setConnector(Connector connector) {
0429: this .connector = (CoyoteConnector) connector;
0430: }
0431:
0432: /**
0433: * Associated context.
0434: */
0435: protected Context context = null;
0436:
0437: /**
0438: * Return the Context within which this Request is being processed.
0439: */
0440: public Context getContext() {
0441: return (this .context);
0442: }
0443:
0444: /**
0445: * Set the Context within which this Request is being processed. This
0446: * must be called as soon as the appropriate Context is identified, because
0447: * it identifies the value to be returned by <code>getContextPath()</code>,
0448: * and thus enables parsing of the request URI.
0449: *
0450: * @param context The newly associated Context
0451: */
0452: public void setContext(Context context) {
0453: this .context = context;
0454: }
0455:
0456: /**
0457: * Filter chain associated with the request.
0458: */
0459: protected FilterChain filterChain = null;
0460:
0461: /**
0462: * Get filter chain associated with the request.
0463: */
0464: public FilterChain getFilterChain() {
0465: return (this .filterChain);
0466: }
0467:
0468: /**
0469: * Set filter chain associated with the request.
0470: *
0471: * @param filterChain new filter chain
0472: */
0473: public void setFilterChain(FilterChain filterChain) {
0474: this .filterChain = filterChain;
0475: }
0476:
0477: /**
0478: * Return the Host within which this Request is being processed.
0479: */
0480: public Host getHost() {
0481: if (getContext() == null)
0482: return null;
0483: return (Host) getContext().getParent();
0484: //return ((Host) mappingData.host);
0485: }
0486:
0487: /**
0488: * Set the Host within which this Request is being processed. This
0489: * must be called as soon as the appropriate Host is identified, and
0490: * before the Request is passed to a context.
0491: *
0492: * @param host The newly associated Host
0493: */
0494: public void setHost(Host host) {
0495: mappingData.host = host;
0496: }
0497:
0498: /**
0499: * Descriptive information about this Request implementation.
0500: */
0501: protected static final String info = "org.apache.coyote.catalina.CoyoteRequest/1.0";
0502:
0503: /**
0504: * Return descriptive information about this Request implementation and
0505: * the corresponding version number, in the format
0506: * <code><description>/<version></code>.
0507: */
0508: public String getInfo() {
0509: return (info);
0510: }
0511:
0512: /**
0513: * Mapping data.
0514: */
0515: protected MappingData mappingData = new MappingData();
0516:
0517: /**
0518: * Return mapping data.
0519: */
0520: public MappingData getMappingData() {
0521: return (mappingData);
0522: }
0523:
0524: /**
0525: * The facade associated with this request.
0526: */
0527: protected CoyoteRequestFacade facade = null;
0528:
0529: /**
0530: * Return the <code>ServletRequest</code> for which this object
0531: * is the facade. This method must be implemented by a subclass.
0532: */
0533: public ServletRequest getRequest() {
0534: if (facade == null) {
0535: facade = new CoyoteRequestFacade(this );
0536: }
0537: return (facade);
0538: }
0539:
0540: /**
0541: * The response with which this request is associated.
0542: */
0543: protected org.apache.catalina.Response response = null;
0544:
0545: /**
0546: * Return the Response with which this Request is associated.
0547: */
0548: public org.apache.catalina.Response getResponse() {
0549: return (this .response);
0550: }
0551:
0552: /**
0553: * Set the Response with which this Request is associated.
0554: *
0555: * @param response The new associated response
0556: */
0557: public void setResponse(org.apache.catalina.Response response) {
0558: this .response = response;
0559: }
0560:
0561: /**
0562: * Return the Socket (if any) through which this Request was received.
0563: * This should <strong>only</strong> be used to access underlying state
0564: * information about this Socket, such as the SSLSession associated with
0565: * an SSLSocket.
0566: */
0567: public Socket getSocket() {
0568: return (socket);
0569: }
0570:
0571: /**
0572: * Set the Socket (if any) through which this Request was received.
0573: *
0574: * @param socket The socket through which this request was received
0575: */
0576: public void setSocket(Socket socket) {
0577: this .socket = socket;
0578: remoteHost = null;
0579: remoteAddr = null;
0580: remotePort = -1;
0581: localPort = -1;
0582: localAddr = null;
0583: localName = null;
0584: }
0585:
0586: /**
0587: * Return the input stream associated with this Request.
0588: */
0589: public InputStream getStream() {
0590: if (inputStream == null) {
0591: inputStream = new CoyoteInputStream(inputBuffer);
0592: }
0593: return inputStream;
0594: }
0595:
0596: /**
0597: * Set the input stream associated with this Request.
0598: *
0599: * @param stream The new input stream
0600: */
0601: public void setStream(InputStream stream) {
0602: // Ignore
0603: }
0604:
0605: /**
0606: * URI byte to char converter (not recycled).
0607: */
0608: protected B2CConverter URIConverter = null;
0609:
0610: /**
0611: * Return the URI converter.
0612: */
0613: protected B2CConverter getURIConverter() {
0614: return URIConverter;
0615: }
0616:
0617: /**
0618: * Set the URI converter.
0619: *
0620: * @param URIConverter the new URI connverter
0621: */
0622: protected void setURIConverter(B2CConverter URIConverter) {
0623: this .URIConverter = URIConverter;
0624: }
0625:
0626: /**
0627: * The valve context associated with this request.
0628: */
0629: protected ValveContext valveContext = null;
0630:
0631: /**
0632: * Get valve context.
0633: */
0634: public ValveContext getValveContext() {
0635: return (this .valveContext);
0636: }
0637:
0638: /**
0639: * Set valve context.
0640: *
0641: * @param valveContext New valve context object
0642: */
0643: public void setValveContext(ValveContext valveContext) {
0644: this .valveContext = valveContext;
0645: }
0646:
0647: /**
0648: * Associated wrapper.
0649: */
0650: protected Wrapper wrapper = null;
0651:
0652: /**
0653: * Return the Wrapper within which this Request is being processed.
0654: */
0655: public Wrapper getWrapper() {
0656: return (this .wrapper);
0657: }
0658:
0659: /**
0660: * Set the Wrapper within which this Request is being processed. This
0661: * must be called as soon as the appropriate Wrapper is identified, and
0662: * before the Request is ultimately passed to an application servlet.
0663: * @param wrapper The newly associated Wrapper
0664: */
0665: public void setWrapper(Wrapper wrapper) {
0666: this .wrapper = wrapper;
0667: }
0668:
0669: // ------------------------------------------------- Request Public Methods
0670:
0671: /**
0672: * Create and return a ServletInputStream to read the content
0673: * associated with this Request.
0674: *
0675: * @exception IOException if an input/output error occurs
0676: */
0677: public ServletInputStream createInputStream() throws IOException {
0678: if (inputStream == null) {
0679: inputStream = new CoyoteInputStream(inputBuffer);
0680: }
0681: return inputStream;
0682: }
0683:
0684: /**
0685: * Perform whatever actions are required to flush and close the input
0686: * stream or reader, in a single operation.
0687: *
0688: * @exception IOException if an input/output error occurs
0689: */
0690: public void finishRequest() throws IOException {
0691: // The reader and input stream don't need to be closed
0692: }
0693:
0694: /**
0695: * Return the object bound with the specified name to the internal notes
0696: * for this request, or <code>null</code> if no such binding exists.
0697: *
0698: * @param name Name of the note to be returned
0699: */
0700: public Object getNote(String name) {
0701: return (notes.get(name));
0702: }
0703:
0704: /**
0705: * Return an Iterator containing the String names of all notes bindings
0706: * that exist for this request.
0707: */
0708: public Iterator getNoteNames() {
0709: return (notes.keySet().iterator());
0710: }
0711:
0712: /**
0713: * Remove any object bound to the specified name in the internal notes
0714: * for this request.
0715: *
0716: * @param name Name of the note to be removed
0717: */
0718: public void removeNote(String name) {
0719: notes.remove(name);
0720: }
0721:
0722: /**
0723: * Bind an object to a specified name in the internal notes associated
0724: * with this request, replacing any existing binding for this name.
0725: *
0726: * @param name Name to which the object should be bound
0727: * @param value Object to be bound to the specified name
0728: */
0729: public void setNote(String name, Object value) {
0730: notes.put(name, value);
0731: }
0732:
0733: /**
0734: * Set the content length associated with this Request.
0735: *
0736: * @param length The new content length
0737: */
0738: public void setContentLength(int length) {
0739: // Not used
0740: }
0741:
0742: /**
0743: * Set the content type (and optionally the character encoding)
0744: * associated with this Request. For example,
0745: * <code>text/html; charset=ISO-8859-4</code>.
0746: *
0747: * @param type The new content type
0748: */
0749: public void setContentType(String type) {
0750: // Not used
0751: }
0752:
0753: /**
0754: * Set the protocol name and version associated with this Request.
0755: *
0756: * @param protocol Protocol name and version
0757: */
0758: public void setProtocol(String protocol) {
0759: // Not used
0760: }
0761:
0762: /**
0763: * Set the IP address of the remote client associated with this Request.
0764: *
0765: * @param remoteAddr The remote IP address
0766: */
0767: public void setRemoteAddr(String remoteAddr) {
0768: // Not used
0769: }
0770:
0771: /**
0772: * Set the fully qualified name of the remote client associated with this
0773: * Request.
0774: *
0775: * @param remoteHost The remote host name
0776: */
0777: public void setRemoteHost(String remoteHost) {
0778: // Not used
0779: }
0780:
0781: /**
0782: * Set the name of the scheme associated with this request. Typical values
0783: * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
0784: *
0785: * @param scheme The scheme
0786: */
0787: public void setScheme(String scheme) {
0788: // Not used
0789: }
0790:
0791: /**
0792: * Set the value to be returned by <code>isSecure()</code>
0793: * for this Request.
0794: *
0795: * @param secure The new isSecure value
0796: */
0797: public void setSecure(boolean secure) {
0798: this .secure = secure;
0799: }
0800:
0801: /**
0802: * Set the name of the server (virtual host) to process this request.
0803: *
0804: * @param name The server name
0805: */
0806: public void setServerName(String name) {
0807: coyoteRequest.serverName().setString(name);
0808: }
0809:
0810: /**
0811: * Set the port number of the server to process this request.
0812: *
0813: * @param port The server port
0814: */
0815: public void setServerPort(int port) {
0816: coyoteRequest.setServerPort(port);
0817: }
0818:
0819: // ------------------------------------------------- ServletRequest Methods
0820:
0821: /**
0822: * Return the specified request attribute if it exists; otherwise, return
0823: * <code>null</code>.
0824: *
0825: * @param name Name of the request attribute to return
0826: */
0827: public Object getAttribute(String name) {
0828:
0829: if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
0830: return (dispatcherType == null) ? ApplicationFilterFactory.REQUEST_INTEGER
0831: : dispatcherType;
0832: } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
0833: return (requestDispatcherPath == null) ? getRequestPathMB()
0834: .toString() : requestDispatcherPath.toString();
0835: }
0836:
0837: Object attr = attributes.get(name);
0838:
0839: if (attr != null)
0840: return (attr);
0841:
0842: attr = coyoteRequest.getAttribute(name);
0843: if (attr != null)
0844: return attr;
0845: // XXX Should move to Globals
0846: if (Constants.SSL_CERTIFICATE_ATTR.equals(name)) {
0847: coyoteRequest.action(ActionCode.ACTION_REQ_SSL_CERTIFICATE,
0848: null);
0849: attr = getAttribute(Globals.CERTIFICATES_ATTR);
0850: if (attr != null)
0851: attributes.put(name, attr);
0852: } else if (isSSLAttribute(name)) {
0853: coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
0854: coyoteRequest);
0855: attr = coyoteRequest
0856: .getAttribute(Globals.CERTIFICATES_ATTR);
0857: if (attr != null) {
0858: attributes.put(Globals.CERTIFICATES_ATTR, attr);
0859: }
0860: attr = coyoteRequest
0861: .getAttribute(Globals.CIPHER_SUITE_ATTR);
0862: if (attr != null) {
0863: attributes.put(Globals.CIPHER_SUITE_ATTR, attr);
0864: }
0865: attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR);
0866: if (attr != null) {
0867: attributes.put(Globals.KEY_SIZE_ATTR, attr);
0868: }
0869: attr = attributes.get(name);
0870: }
0871: return attr;
0872: }
0873:
0874: /**
0875: * Test if a given name is one of the special Servlet-spec SSL attributes.
0876: */
0877: static boolean isSSLAttribute(String name) {
0878: return Globals.CERTIFICATES_ATTR.equals(name)
0879: || Globals.CIPHER_SUITE_ATTR.equals(name)
0880: || Globals.KEY_SIZE_ATTR.equals(name);
0881: }
0882:
0883: /**
0884: * Return the names of all request attributes for this Request, or an
0885: * empty <code>Enumeration</code> if there are none.
0886: */
0887: public Enumeration getAttributeNames() {
0888: if (isSecure()) {
0889: getAttribute(Globals.CERTIFICATES_ATTR);
0890: }
0891: return new Enumerator(attributes.keySet(), true);
0892: }
0893:
0894: /**
0895: * Return the character encoding for this Request.
0896: */
0897: public String getCharacterEncoding() {
0898: return (coyoteRequest.getCharacterEncoding());
0899: }
0900:
0901: /**
0902: * Return the content length for this Request.
0903: */
0904: public int getContentLength() {
0905: return (coyoteRequest.getContentLength());
0906: }
0907:
0908: /**
0909: * Return the content type for this Request.
0910: */
0911: public String getContentType() {
0912: return (coyoteRequest.getContentType());
0913: }
0914:
0915: /**
0916: * Return the servlet input stream for this Request. The default
0917: * implementation returns a servlet input stream created by
0918: * <code>createInputStream()</code>.
0919: *
0920: * @exception IllegalStateException if <code>getReader()</code> has
0921: * already been called for this request
0922: * @exception IOException if an input/output error occurs
0923: */
0924: public ServletInputStream getInputStream() throws IOException {
0925:
0926: if (usingReader)
0927: throw new IllegalStateException(sm
0928: .getString("coyoteRequest.getInputStream.ise"));
0929:
0930: usingInputStream = true;
0931: if (inputStream == null) {
0932: inputStream = new CoyoteInputStream(inputBuffer);
0933: }
0934: return inputStream;
0935:
0936: }
0937:
0938: /**
0939: * Return the preferred Locale that the client will accept content in,
0940: * based on the value for the first <code>Accept-Language</code> header
0941: * that was encountered. If the request did not specify a preferred
0942: * language, the server's default Locale is returned.
0943: */
0944: public Locale getLocale() {
0945:
0946: if (!localesParsed)
0947: parseLocales();
0948:
0949: if (locales.size() > 0) {
0950: return ((Locale) locales.get(0));
0951: } else {
0952: return (defaultLocale);
0953: }
0954:
0955: }
0956:
0957: /**
0958: * Return the set of preferred Locales that the client will accept
0959: * content in, based on the values for any <code>Accept-Language</code>
0960: * headers that were encountered. If the request did not specify a
0961: * preferred language, the server's default Locale is returned.
0962: */
0963: public Enumeration getLocales() {
0964:
0965: if (!localesParsed)
0966: parseLocales();
0967:
0968: if (locales.size() > 0)
0969: return (new Enumerator(locales));
0970: ArrayList results = new ArrayList();
0971: results.add(defaultLocale);
0972: return (new Enumerator(results));
0973:
0974: }
0975:
0976: /**
0977: * Return the value of the specified request parameter, if any; otherwise,
0978: * return <code>null</code>. If there is more than one value defined,
0979: * return only the first one.
0980: *
0981: * @param name Name of the desired request parameter
0982: */
0983: public String getParameter(String name) {
0984:
0985: if (!requestParametersParsed)
0986: parseRequestParameters();
0987:
0988: return coyoteRequest.getParameters().getParameter(name);
0989:
0990: }
0991:
0992: /**
0993: * Returns a <code>Map</code> of the parameters of this request.
0994: * Request parameters are extra information sent with the request.
0995: * For HTTP servlets, parameters are contained in the query string
0996: * or posted form data.
0997: *
0998: * @return A <code>Map</code> containing parameter names as keys
0999: * and parameter values as map values.
1000: */
1001: public Map getParameterMap() {
1002:
1003: if (parameterMap.isLocked())
1004: return parameterMap;
1005:
1006: Enumeration enum = getParameterNames();
1007: while (enum.hasMoreElements()) {
1008: String name = enum.nextElement().toString();
1009: String[] values = getParameterValues(name);
1010: parameterMap.put(name, values);
1011: }
1012:
1013: parameterMap.setLocked(true);
1014:
1015: return parameterMap;
1016:
1017: }
1018:
1019: /**
1020: * Return the names of all defined request parameters for this request.
1021: */
1022: public Enumeration getParameterNames() {
1023:
1024: if (!requestParametersParsed)
1025: parseRequestParameters();
1026:
1027: return coyoteRequest.getParameters().getParameterNames();
1028:
1029: }
1030:
1031: /**
1032: * Return the defined values for the specified request parameter, if any;
1033: * otherwise, return <code>null</code>.
1034: *
1035: * @param name Name of the desired request parameter
1036: */
1037: public String[] getParameterValues(String name) {
1038:
1039: if (!requestParametersParsed)
1040: parseRequestParameters();
1041:
1042: return coyoteRequest.getParameters().getParameterValues(name);
1043:
1044: }
1045:
1046: /**
1047: * Return the protocol and version used to make this Request.
1048: */
1049: public String getProtocol() {
1050: return coyoteRequest.protocol().toString();
1051: }
1052:
1053: /**
1054: * Read the Reader wrapping the input stream for this Request. The
1055: * default implementation wraps a <code>BufferedReader</code> around the
1056: * servlet input stream returned by <code>createInputStream()</code>.
1057: *
1058: * @exception IllegalStateException if <code>getInputStream()</code>
1059: * has already been called for this request
1060: * @exception IOException if an input/output error occurs
1061: */
1062: public BufferedReader getReader() throws IOException {
1063:
1064: if (usingInputStream)
1065: throw new IllegalStateException(sm
1066: .getString("coyoteRequest.getReader.ise"));
1067:
1068: usingReader = true;
1069: inputBuffer.checkConverter();
1070: if (reader == null) {
1071: reader = new CoyoteReader(inputBuffer);
1072: }
1073: return reader;
1074:
1075: }
1076:
1077: /**
1078: * Return the real path of the specified virtual path.
1079: *
1080: * @param path Path to be translated
1081: *
1082: * @deprecated As of version 2.1 of the Java Servlet API, use
1083: * <code>ServletContext.getRealPath()</code>.
1084: */
1085: public String getRealPath(String path) {
1086:
1087: if (context == null)
1088: return (null);
1089: ServletContext servletContext = context.getServletContext();
1090: if (servletContext == null)
1091: return (null);
1092: else {
1093: try {
1094: return (servletContext.getRealPath(path));
1095: } catch (IllegalArgumentException e) {
1096: return (null);
1097: }
1098: }
1099:
1100: }
1101:
1102: /**
1103: * Return the remote IP address making this Request.
1104: */
1105: public String getRemoteAddr() {
1106: if (remoteAddr == null) {
1107: if (socket != null) {
1108: InetAddress inet = socket.getInetAddress();
1109: remoteAddr = inet.getHostAddress();
1110: } else {
1111: coyoteRequest.action(
1112: ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE,
1113: coyoteRequest);
1114: remoteAddr = coyoteRequest.remoteAddr().toString();
1115: }
1116: }
1117: return remoteAddr;
1118: }
1119:
1120: /**
1121: * Return the remote host name making this Request.
1122: */
1123: public String getRemoteHost() {
1124: if (remoteHost == null) {
1125: if (!connector.getEnableLookups()) {
1126: remoteHost = getRemoteAddr();
1127: } else if (socket != null) {
1128: InetAddress inet = socket.getInetAddress();
1129: remoteHost = inet.getHostName();
1130: } else {
1131: coyoteRequest.action(
1132: ActionCode.ACTION_REQ_HOST_ATTRIBUTE,
1133: coyoteRequest);
1134: remoteHost = coyoteRequest.remoteHost().toString();
1135: }
1136: }
1137: return remoteHost;
1138: }
1139:
1140: /**
1141: * Returns the Internet Protocol (IP) source port of the client
1142: * or last proxy that sent the request.
1143: */
1144: public int getRemotePort() {
1145: if (remotePort == -1) {
1146: if (socket != null) {
1147: remotePort = socket.getPort();
1148: } else {
1149: coyoteRequest.action(
1150: ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE,
1151: coyoteRequest);
1152: remotePort = coyoteRequest.getRemotePort();
1153: }
1154: }
1155: return remotePort;
1156: }
1157:
1158: /**
1159: * Returns the host name of the Internet Protocol (IP) interface on
1160: * which the request was received.
1161: */
1162: public String getLocalName() {
1163: if (localName == null) {
1164: if (socket != null) {
1165: InetAddress inet = socket.getLocalAddress();
1166: localName = inet.getHostName();
1167: } else {
1168: coyoteRequest.action(
1169: ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE,
1170: coyoteRequest);
1171: localName = coyoteRequest.localName().toString();
1172: }
1173: }
1174: return localName;
1175: }
1176:
1177: /**
1178: * Returns the Internet Protocol (IP) address of the interface on
1179: * which the request was received.
1180: */
1181: public String getLocalAddr() {
1182: if (localAddr == null) {
1183: if (socket != null) {
1184: InetAddress inet = socket.getLocalAddress();
1185: localAddr = inet.getHostAddress();
1186: } else {
1187: coyoteRequest.action(
1188: ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE,
1189: coyoteRequest);
1190: localAddr = coyoteRequest.localAddr().toString();
1191: }
1192: }
1193: return localAddr;
1194: }
1195:
1196: /**
1197: * Returns the Internet Protocol (IP) port number of the interface
1198: * on which the request was received.
1199: */
1200: public int getLocalPort() {
1201: if (localPort == -1) {
1202: if (socket != null) {
1203: localPort = socket.getLocalPort();
1204: } else {
1205: coyoteRequest.action(
1206: ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE,
1207: coyoteRequest);
1208: localPort = coyoteRequest.getLocalPort();
1209: }
1210: }
1211: return localPort;
1212: }
1213:
1214: /**
1215: * Return a RequestDispatcher that wraps the resource at the specified
1216: * path, which may be interpreted as relative to the current request path.
1217: *
1218: * @param path Path of the resource to be wrapped
1219: */
1220: public RequestDispatcher getRequestDispatcher(String path) {
1221:
1222: if (context == null)
1223: return (null);
1224:
1225: // If the path is already context-relative, just pass it through
1226: if (path == null)
1227: return (null);
1228: else if (path.startsWith("/"))
1229: return (context.getServletContext()
1230: .getRequestDispatcher(path));
1231:
1232: // Convert a request-relative path to a context-relative one
1233: String servletPath = (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
1234: if (servletPath == null)
1235: servletPath = getServletPath();
1236:
1237: // Add the path info, if there is any
1238: String pathInfo = getPathInfo();
1239: String requestPath = null;
1240:
1241: if (pathInfo == null) {
1242: requestPath = servletPath;
1243: } else {
1244: requestPath = servletPath + pathInfo;
1245: }
1246:
1247: int pos = requestPath.lastIndexOf('/');
1248: String relative = null;
1249: if (pos >= 0) {
1250: relative = RequestUtil.normalize(requestPath.substring(0,
1251: pos + 1)
1252: + path);
1253: } else {
1254: relative = RequestUtil.normalize(requestPath + path);
1255: }
1256:
1257: return (context.getServletContext()
1258: .getRequestDispatcher(relative));
1259:
1260: }
1261:
1262: /**
1263: * Return the scheme used to make this Request.
1264: */
1265: public String getScheme() {
1266: return (coyoteRequest.scheme().toString());
1267: }
1268:
1269: /**
1270: * Return the server name responding to this Request.
1271: */
1272: public String getServerName() {
1273: return (coyoteRequest.serverName().toString());
1274: }
1275:
1276: /**
1277: * Return the server port responding to this Request.
1278: */
1279: public int getServerPort() {
1280: return (coyoteRequest.getServerPort());
1281: }
1282:
1283: /**
1284: * Was this request received on a secure connection?
1285: */
1286: public boolean isSecure() {
1287: return (secure);
1288: }
1289:
1290: /**
1291: * Remove the specified request attribute if it exists.
1292: *
1293: * @param name Name of the request attribute to remove
1294: */
1295: public void removeAttribute(String name) {
1296: Object value = null;
1297: boolean found = false;
1298:
1299: // Remove the specified attribute
1300: // Check for read only attribute
1301: // requests are per thread so synchronization unnecessary
1302: if (readOnlyAttributes.containsKey(name)) {
1303: return;
1304: }
1305: found = attributes.containsKey(name);
1306: if (found) {
1307: value = attributes.get(name);
1308: attributes.remove(name);
1309: } else {
1310: return;
1311: }
1312:
1313: // Notify interested application event listeners
1314: Object listeners[] = context.getApplicationEventListeners();
1315: if ((listeners == null) || (listeners.length == 0))
1316: return;
1317: ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(
1318: context.getServletContext(), getRequest(), name, value);
1319: for (int i = 0; i < listeners.length; i++) {
1320: if (!(listeners[i] instanceof ServletRequestAttributeListener))
1321: continue;
1322: ServletRequestAttributeListener listener = (ServletRequestAttributeListener) listeners[i];
1323: try {
1324: listener.attributeRemoved(event);
1325: } catch (Throwable t) {
1326: log(sm.getString("coyoteRequest.attributeEvent"), t);
1327: // Error valve will pick this execption up and display it to user
1328: attributes.put(Globals.EXCEPTION_ATTR, t);
1329: }
1330: }
1331: }
1332:
1333: /**
1334: * Set the specified request attribute to the specified value.
1335: *
1336: * @param name Name of the request attribute to set
1337: * @param value The associated value
1338: */
1339: public void setAttribute(String name, Object value) {
1340:
1341: // Name cannot be null
1342: if (name == null)
1343: throw new IllegalArgumentException(sm
1344: .getString("coyoteRequest.setAttribute.namenull"));
1345:
1346: // Null value is the same as removeAttribute()
1347: if (value == null) {
1348: removeAttribute(name);
1349: return;
1350: }
1351:
1352: if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
1353: dispatcherType = value;
1354: return;
1355: } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
1356: requestDispatcherPath = value;
1357: return;
1358: }
1359:
1360: Object oldValue = null;
1361: boolean replaced = false;
1362:
1363: // Add or replace the specified attribute
1364: // Check for read only attribute
1365: // requests are per thread so synchronization unnecessary
1366: if (readOnlyAttributes.containsKey(name)) {
1367: return;
1368: }
1369:
1370: oldValue = attributes.put(name, value);
1371: if (oldValue != null) {
1372: replaced = true;
1373: }
1374:
1375: // Notify interested application event listeners
1376: Object listeners[] = context.getApplicationEventListeners();
1377: if ((listeners == null) || (listeners.length == 0))
1378: return;
1379: ServletRequestAttributeEvent event = null;
1380: if (replaced)
1381: event = new ServletRequestAttributeEvent(context
1382: .getServletContext(), getRequest(), name, oldValue);
1383: else
1384: event = new ServletRequestAttributeEvent(context
1385: .getServletContext(), getRequest(), name, value);
1386:
1387: for (int i = 0; i < listeners.length; i++) {
1388: if (!(listeners[i] instanceof ServletRequestAttributeListener))
1389: continue;
1390: ServletRequestAttributeListener listener = (ServletRequestAttributeListener) listeners[i];
1391: try {
1392: if (replaced) {
1393: listener.attributeReplaced(event);
1394: } else {
1395: listener.attributeAdded(event);
1396: }
1397: } catch (Throwable t) {
1398: log(sm.getString("coyoteRequest.attributeEvent"), t);
1399: // Error valve will pick this execption up and display it to user
1400: attributes.put(Globals.EXCEPTION_ATTR, t);
1401: }
1402: }
1403: }
1404:
1405: /**
1406: * Overrides the name of the character encoding used in the body of
1407: * this request. This method must be called prior to reading request
1408: * parameters or reading input using <code>getReader()</code>.
1409: *
1410: * @param enc The character encoding to be used
1411: *
1412: * @exception UnsupportedEncodingException if the specified encoding
1413: * is not supported
1414: *
1415: * @since Servlet 2.3
1416: */
1417: public void setCharacterEncoding(String enc)
1418: throws UnsupportedEncodingException {
1419:
1420: // Ensure that the specified encoding is valid
1421: byte buffer[] = new byte[1];
1422: buffer[0] = (byte) 'a';
1423: String dummy = new String(buffer, enc);
1424:
1425: // Save the validated encoding
1426: coyoteRequest.setCharacterEncoding(enc);
1427:
1428: }
1429:
1430: // ---------------------------------------------------- HttpRequest Methods
1431:
1432: /**
1433: * Add a Cookie to the set of Cookies associated with this Request.
1434: *
1435: * @param cookie The new cookie
1436: */
1437: public void addCookie(Cookie cookie) {
1438:
1439: if (!cookiesParsed)
1440: parseCookies();
1441:
1442: int size = 0;
1443: if (cookies != null) {
1444: size = cookies.length;
1445: }
1446:
1447: Cookie[] newCookies = new Cookie[size + 1];
1448: for (int i = 0; i < size; i++) {
1449: newCookies[i] = cookies[i];
1450: }
1451: newCookies[size] = cookie;
1452:
1453: cookies = newCookies;
1454:
1455: }
1456:
1457: /**
1458: * Add a Header to the set of Headers associated with this Request.
1459: *
1460: * @param name The new header name
1461: * @param value The new header value
1462: */
1463: public void addHeader(String name, String value) {
1464: // Not used
1465: }
1466:
1467: /**
1468: * Add a Locale to the set of preferred Locales for this Request. The
1469: * first added Locale will be the first one returned by getLocales().
1470: *
1471: * @param locale The new preferred Locale
1472: */
1473: public void addLocale(Locale locale) {
1474: locales.add(locale);
1475: }
1476:
1477: /**
1478: * Add a parameter name and corresponding set of values to this Request.
1479: * (This is used when restoring the original request on a form based
1480: * login).
1481: *
1482: * @param name Name of this request parameter
1483: * @param values Corresponding values for this request parameter
1484: */
1485: public void addParameter(String name, String values[]) {
1486: coyoteRequest.getParameters().addParameterValues(name, values);
1487: }
1488:
1489: /**
1490: * Clear the collection of Cookies associated with this Request.
1491: */
1492: public void clearCookies() {
1493: cookiesParsed = true;
1494: cookies = null;
1495: }
1496:
1497: /**
1498: * Clear the collection of Headers associated with this Request.
1499: */
1500: public void clearHeaders() {
1501: // Not used
1502: }
1503:
1504: /**
1505: * Clear the collection of Locales associated with this Request.
1506: */
1507: public void clearLocales() {
1508: locales.clear();
1509: }
1510:
1511: /**
1512: * Clear the collection of parameters associated with this Request.
1513: */
1514: public void clearParameters() {
1515: // Not used
1516: }
1517:
1518: /**
1519: * Set the authentication type used for this request, if any; otherwise
1520: * set the type to <code>null</code>. Typical values are "BASIC",
1521: * "DIGEST", or "SSL".
1522: *
1523: * @param type The authentication type used
1524: */
1525: public void setAuthType(String type) {
1526: this .authType = type;
1527: }
1528:
1529: /**
1530: * Set the context path for this Request. This will normally be called
1531: * when the associated Context is mapping the Request to a particular
1532: * Wrapper.
1533: *
1534: * @param path The context path
1535: */
1536: public void setContextPath(String path) {
1537:
1538: if (path == null) {
1539: mappingData.contextPath.setString("");
1540: } else {
1541: mappingData.contextPath.setString(path);
1542: }
1543:
1544: }
1545:
1546: /**
1547: * Set the HTTP request method used for this Request.
1548: *
1549: * @param method The request method
1550: */
1551: public void setMethod(String method) {
1552: // Not used
1553: }
1554:
1555: /**
1556: * Set the query string for this Request. This will normally be called
1557: * by the HTTP Connector, when it parses the request headers.
1558: *
1559: * @param query The query string
1560: */
1561: public void setQueryString(String query) {
1562: // Not used
1563: }
1564:
1565: /**
1566: * Set the path information for this Request. This will normally be called
1567: * when the associated Context is mapping the Request to a particular
1568: * Wrapper.
1569: *
1570: * @param path The path information
1571: */
1572: public void setPathInfo(String path) {
1573: mappingData.pathInfo.setString(path);
1574: }
1575:
1576: /**
1577: * Set a flag indicating whether or not the requested session ID for this
1578: * request came in through a cookie. This is normally called by the
1579: * HTTP Connector, when it parses the request headers.
1580: *
1581: * @param flag The new flag
1582: */
1583: public void setRequestedSessionCookie(boolean flag) {
1584:
1585: this .requestedSessionCookie = flag;
1586:
1587: }
1588:
1589: /**
1590: * Set the requested session ID for this request. This is normally called
1591: * by the HTTP Connector, when it parses the request headers.
1592: *
1593: * @param id The new session id
1594: */
1595: public void setRequestedSessionId(String id) {
1596:
1597: this .requestedSessionId = id;
1598:
1599: }
1600:
1601: /**
1602: * Set a flag indicating whether or not the requested session ID for this
1603: * request came in through a URL. This is normally called by the
1604: * HTTP Connector, when it parses the request headers.
1605: *
1606: * @param flag The new flag
1607: */
1608: public void setRequestedSessionURL(boolean flag) {
1609:
1610: this .requestedSessionURL = flag;
1611:
1612: }
1613:
1614: /**
1615: * Set the unparsed request URI for this Request. This will normally be
1616: * called by the HTTP Connector, when it parses the request headers.
1617: *
1618: * @param uri The request URI
1619: */
1620: public void setRequestURI(String uri) {
1621: // Not used
1622: }
1623:
1624: /**
1625: * Set the decoded request URI.
1626: *
1627: * @param uri The decoded request URI
1628: */
1629: public void setDecodedRequestURI(String uri) {
1630: // Not used
1631: }
1632:
1633: /**
1634: * Get the decoded request URI.
1635: *
1636: * @return the URL decoded request URI
1637: */
1638: public String getDecodedRequestURI() {
1639: return (coyoteRequest.decodedURI().toString());
1640: }
1641:
1642: /**
1643: * Get the decoded request URI.
1644: *
1645: * @return the URL decoded request URI
1646: */
1647: public MessageBytes getDecodedRequestURIMB() {
1648: return (coyoteRequest.decodedURI());
1649: }
1650:
1651: /**
1652: * Set the servlet path for this Request. This will normally be called
1653: * when the associated Context is mapping the Request to a particular
1654: * Wrapper.
1655: *
1656: * @param path The servlet path
1657: */
1658: public void setServletPath(String path) {
1659: if (path != null)
1660: mappingData.wrapperPath.setString(path);
1661: }
1662:
1663: /**
1664: * Set the Principal who has been authenticated for this Request. This
1665: * value is also used to calculate the value to be returned by the
1666: * <code>getRemoteUser()</code> method.
1667: *
1668: * @param principal The user Principal
1669: */
1670: public void setUserPrincipal(Principal principal) {
1671:
1672: if (System.getSecurityManager() != null) {
1673: HttpSession session = getSession(false);
1674: if ((subject != null)
1675: && (!subject.getPrincipals().contains(principal))) {
1676: subject.getPrincipals().add(principal);
1677: } else if (session != null
1678: && session.getAttribute(Globals.SUBJECT_ATTR) == null) {
1679: subject = new Subject();
1680: subject.getPrincipals().add(principal);
1681: }
1682: if (session != null) {
1683: session.setAttribute(Globals.SUBJECT_ATTR, subject);
1684: }
1685: }
1686:
1687: this .userPrincipal = principal;
1688: }
1689:
1690: // --------------------------------------------- HttpServletRequest Methods
1691:
1692: /**
1693: * Return the authentication type used for this Request.
1694: */
1695: public String getAuthType() {
1696: return (authType);
1697: }
1698:
1699: /**
1700: * Return the portion of the request URI used to select the Context
1701: * of the Request.
1702: */
1703: public String getContextPath() {
1704: return (mappingData.contextPath.toString());
1705: }
1706:
1707: /**
1708: * Get the context path.
1709: *
1710: * @return the context path
1711: */
1712: public MessageBytes getContextPathMB() {
1713: return (mappingData.contextPath);
1714: }
1715:
1716: /**
1717: * Return the set of Cookies received with this Request.
1718: */
1719: public Cookie[] getCookies() {
1720:
1721: if (!cookiesParsed)
1722: parseCookies();
1723:
1724: return cookies;
1725:
1726: }
1727:
1728: /**
1729: * Set the set of cookies recieved with this Request.
1730: */
1731: public void setCookies(Cookie[] cookies) {
1732:
1733: this .cookies = cookies;
1734:
1735: }
1736:
1737: /**
1738: * Return the value of the specified date header, if any; otherwise
1739: * return -1.
1740: *
1741: * @param name Name of the requested date header
1742: *
1743: * @exception IllegalArgumentException if the specified header value
1744: * cannot be converted to a date
1745: */
1746: public long getDateHeader(String name) {
1747:
1748: String value = getHeader(name);
1749: if (value == null)
1750: return (-1L);
1751:
1752: // Attempt to convert the date header in a variety of formats
1753: long result = FastHttpDateFormat.parseDate(value, formats);
1754: if (result != (-1L)) {
1755: return result;
1756: }
1757: throw new IllegalArgumentException(value);
1758:
1759: }
1760:
1761: /**
1762: * Return the first value of the specified header, if any; otherwise,
1763: * return <code>null</code>
1764: *
1765: * @param name Name of the requested header
1766: */
1767: public String getHeader(String name) {
1768: return coyoteRequest.getHeader(name);
1769: }
1770:
1771: /**
1772: * Return all of the values of the specified header, if any; otherwise,
1773: * return an empty enumeration.
1774: *
1775: * @param name Name of the requested header
1776: */
1777: public Enumeration getHeaders(String name) {
1778: return coyoteRequest.getMimeHeaders().values(name);
1779: }
1780:
1781: /**
1782: * Return the names of all headers received with this request.
1783: */
1784: public Enumeration getHeaderNames() {
1785: return coyoteRequest.getMimeHeaders().names();
1786: }
1787:
1788: /**
1789: * Return the value of the specified header as an integer, or -1 if there
1790: * is no such header for this request.
1791: *
1792: * @param name Name of the requested header
1793: *
1794: * @exception IllegalArgumentException if the specified header value
1795: * cannot be converted to an integer
1796: */
1797: public int getIntHeader(String name) {
1798:
1799: String value = getHeader(name);
1800: if (value == null) {
1801: return (-1);
1802: } else {
1803: return (Integer.parseInt(value));
1804: }
1805:
1806: }
1807:
1808: /**
1809: * Return the HTTP request method used in this Request.
1810: */
1811: public String getMethod() {
1812: return coyoteRequest.method().toString();
1813: }
1814:
1815: /**
1816: * Return the path information associated with this Request.
1817: */
1818: public String getPathInfo() {
1819: return (mappingData.pathInfo.toString());
1820: }
1821:
1822: /**
1823: * Get the path info.
1824: *
1825: * @return the path info
1826: */
1827: public MessageBytes getPathInfoMB() {
1828: return (mappingData.pathInfo);
1829: }
1830:
1831: /**
1832: * Return the extra path information for this request, translated
1833: * to a real path.
1834: */
1835: public String getPathTranslated() {
1836:
1837: if (context == null)
1838: return (null);
1839:
1840: if (getPathInfo() == null) {
1841: return (null);
1842: } else {
1843: return (context.getServletContext()
1844: .getRealPath(getPathInfo()));
1845: }
1846:
1847: }
1848:
1849: /**
1850: * Return the query string associated with this request.
1851: */
1852: public String getQueryString() {
1853: String queryString = coyoteRequest.queryString().toString();
1854: if (queryString.equals("")) {
1855: return (null);
1856: } else {
1857: return queryString;
1858: }
1859: }
1860:
1861: /**
1862: * Return the name of the remote user that has been authenticated
1863: * for this Request.
1864: */
1865: public String getRemoteUser() {
1866:
1867: if (userPrincipal != null) {
1868: return (userPrincipal.getName());
1869: } else {
1870: return (null);
1871: }
1872:
1873: }
1874:
1875: /**
1876: * Get the request path.
1877: *
1878: * @return the request path
1879: */
1880: public MessageBytes getRequestPathMB() {
1881: return (mappingData.requestPath);
1882: }
1883:
1884: /**
1885: * Return the session identifier included in this request, if any.
1886: */
1887: public String getRequestedSessionId() {
1888: return (requestedSessionId);
1889: }
1890:
1891: /**
1892: * Return the request URI for this request.
1893: */
1894: public String getRequestURI() {
1895: return coyoteRequest.requestURI().toString();
1896: }
1897:
1898: /**
1899: * Reconstructs the URL the client used to make the request.
1900: * The returned URL contains a protocol, server name, port
1901: * number, and server path, but it does not include query
1902: * string parameters.
1903: * <p>
1904: * Because this method returns a <code>StringBuffer</code>,
1905: * not a <code>String</code>, you can modify the URL easily,
1906: * for example, to append query parameters.
1907: * <p>
1908: * This method is useful for creating redirect messages and
1909: * for reporting errors.
1910: *
1911: * @return A <code>StringBuffer</code> object containing the
1912: * reconstructed URL
1913: */
1914: public StringBuffer getRequestURL() {
1915:
1916: StringBuffer url = new StringBuffer();
1917: String scheme = getScheme();
1918: int port = getServerPort();
1919: if (port < 0)
1920: port = 80; // Work around java.net.URL bug
1921:
1922: url.append(scheme);
1923: url.append("://");
1924: url.append(getServerName());
1925: if ((scheme.equals("http") && (port != 80))
1926: || (scheme.equals("https") && (port != 443))) {
1927: url.append(':');
1928: url.append(port);
1929: }
1930: url.append(getRequestURI());
1931:
1932: return (url);
1933:
1934: }
1935:
1936: /**
1937: * Return the portion of the request URI used to select the servlet
1938: * that will process this request.
1939: */
1940: public String getServletPath() {
1941: return (mappingData.wrapperPath.toString());
1942: }
1943:
1944: /**
1945: * Get the servlet path.
1946: *
1947: * @return the servlet path
1948: */
1949: public MessageBytes getServletPathMB() {
1950: return (mappingData.wrapperPath);
1951: }
1952:
1953: /**
1954: * Return the session associated with this Request, creating one
1955: * if necessary.
1956: */
1957: public HttpSession getSession() {
1958: return (getSession(true));
1959: }
1960:
1961: /**
1962: * Return the session associated with this Request, creating one
1963: * if necessary and requested.
1964: *
1965: * @param create Create a new session if one does not exist
1966: */
1967: public HttpSession getSession(boolean create) {
1968:
1969: return doGetSession(create);
1970:
1971: }
1972:
1973: /**
1974: * Return <code>true</code> if the session identifier included in this
1975: * request came from a cookie.
1976: */
1977: public boolean isRequestedSessionIdFromCookie() {
1978:
1979: if (requestedSessionId != null)
1980: return (requestedSessionCookie);
1981: else
1982: return (false);
1983:
1984: }
1985:
1986: /**
1987: * Return <code>true</code> if the session identifier included in this
1988: * request came from the request URI.
1989: */
1990: public boolean isRequestedSessionIdFromURL() {
1991:
1992: if (requestedSessionId != null)
1993: return (requestedSessionURL);
1994: else
1995: return (false);
1996:
1997: }
1998:
1999: /**
2000: * Return <code>true</code> if the session identifier included in this
2001: * request came from the request URI.
2002: *
2003: * @deprecated As of Version 2.1 of the Java Servlet API, use
2004: * <code>isRequestedSessionIdFromURL()</code> instead.
2005: */
2006: public boolean isRequestedSessionIdFromUrl() {
2007: return (isRequestedSessionIdFromURL());
2008: }
2009:
2010: /**
2011: * Return <code>true</code> if the session identifier included in this
2012: * request identifies a valid session.
2013: */
2014: public boolean isRequestedSessionIdValid() {
2015:
2016: if (requestedSessionId == null)
2017: return (false);
2018: if (context == null)
2019: return (false);
2020: Manager manager = context.getManager();
2021: if (manager == null)
2022: return (false);
2023: Session session = null;
2024: try {
2025: session = manager.findSession(requestedSessionId);
2026: } catch (IOException e) {
2027: session = null;
2028: }
2029: if ((session != null) && session.isValid())
2030: return (true);
2031: else
2032: return (false);
2033:
2034: }
2035:
2036: /**
2037: * Return <code>true</code> if the authenticated user principal
2038: * possesses the specified role name.
2039: *
2040: * @param role Role name to be validated
2041: */
2042: public boolean isUserInRole(String role) {
2043:
2044: // Have we got an authenticated principal at all?
2045: if (userPrincipal == null)
2046: return (false);
2047:
2048: // Identify the Realm we will use for checking role assignmenets
2049: if (context == null)
2050: return (false);
2051: Realm realm = context.getRealm();
2052: if (realm == null)
2053: return (false);
2054:
2055: // Check for a role alias defined in a <security-role-ref> element
2056: if (wrapper != null) {
2057: String realRole = wrapper.findSecurityReference(role);
2058: if ((realRole != null)
2059: && realm.hasRole(userPrincipal, realRole))
2060: return (true);
2061: }
2062:
2063: // Check for a role defined directly as a <security-role>
2064: return (realm.hasRole(userPrincipal, role));
2065:
2066: }
2067:
2068: /**
2069: * Return the principal that has been authenticated for this Request.
2070: */
2071: public Principal getUserPrincipal() {
2072: return (userPrincipal);
2073: }
2074:
2075: // ------------------------------------------------------ Protected Methods
2076:
2077: protected HttpSession doGetSession(boolean create) {
2078:
2079: // There cannot be a session if no context has been assigned yet
2080: if (context == null)
2081: return (null);
2082:
2083: // Return the current session if it exists and is valid
2084: if ((session != null) && !session.isValid())
2085: session = null;
2086: if (session != null)
2087: return (session.getSession());
2088:
2089: // Return the requested session if it exists and is valid
2090: Manager manager = null;
2091: if (context != null)
2092: manager = context.getManager();
2093: if (manager == null)
2094: return (null); // Sessions are not supported
2095: if (requestedSessionId != null) {
2096: try {
2097: session = manager.findSession(requestedSessionId);
2098: } catch (IOException e) {
2099: session = null;
2100: }
2101: if ((session != null) && !session.isValid())
2102: session = null;
2103: if (session != null) {
2104: session.access();
2105: return (session.getSession());
2106: }
2107: }
2108:
2109: // Create a new session if requested and the response is not committed
2110: if (!create)
2111: return (null);
2112: if ((context != null) && (response != null)
2113: && context.getCookies()
2114: && response.getResponse().isCommitted()) {
2115: throw new IllegalStateException(sm
2116: .getString("coyoteRequest.sessionCreateCommitted"));
2117: }
2118:
2119: session = manager.createSession();
2120:
2121: // Creating a new session cookie based on that session
2122: if ((session != null) && (getContext() != null)
2123: && getContext().getCookies()) {
2124: Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
2125: session.getId());
2126: configureSessionCookie(cookie);
2127: ((HttpServletResponse) response).addCookie(cookie);
2128: }
2129:
2130: if (session != null) {
2131: session.access();
2132: return (session.getSession());
2133: } else {
2134: return (null);
2135: }
2136:
2137: }
2138:
2139: /**
2140: * Configures the given JSESSIONID cookie.
2141: *
2142: * @param cookie The JSESSIONID cookie to be configured
2143: */
2144: protected void configureSessionCookie(Cookie cookie) {
2145: cookie.setMaxAge(-1);
2146: String contextPath = null;
2147: if (getContext() != null) {
2148: contextPath = getContext().getPath();
2149: }
2150: if ((contextPath != null) && (contextPath.length() > 0)) {
2151: cookie.setPath(contextPath);
2152: } else {
2153: cookie.setPath("/");
2154: }
2155: if (isSecure()) {
2156: cookie.setSecure(true);
2157: }
2158: }
2159:
2160: /**
2161: * Parse cookies.
2162: */
2163: protected void parseCookies() {
2164:
2165: cookiesParsed = true;
2166:
2167: Cookies serverCookies = coyoteRequest.getCookies();
2168: int count = serverCookies.getCookieCount();
2169: if (count <= 0)
2170: return;
2171:
2172: cookies = new Cookie[count];
2173:
2174: int idx = 0;
2175: for (int i = 0; i < count; i++) {
2176: ServerCookie scookie = serverCookies.getCookie(i);
2177: try {
2178: Cookie cookie = new Cookie(
2179: scookie.getName().toString(), scookie
2180: .getValue().toString());
2181: cookie.setPath(scookie.getPath().toString());
2182: cookie.setVersion(scookie.getVersion());
2183: String domain = scookie.getDomain().toString();
2184: if (domain != null) {
2185: cookie.setDomain(scookie.getDomain().toString());
2186: }
2187: cookies[idx++] = cookie;
2188: } catch (IllegalArgumentException e) {
2189: // Ignore bad cookie
2190: }
2191: }
2192: if (idx < count) {
2193: Cookie[] ncookies = new Cookie[idx];
2194: System.arraycopy(cookies, 0, ncookies, 0, idx);
2195: cookies = ncookies;
2196: }
2197:
2198: }
2199:
2200: /**
2201: * Parse request parameters.
2202: */
2203: protected void parseRequestParameters() {
2204:
2205: requestParametersParsed = true;
2206:
2207: Parameters parameters = coyoteRequest.getParameters();
2208:
2209: String enc = coyoteRequest.getCharacterEncoding();
2210: boolean useBodyEncodingForURI = connector
2211: .getUseBodyEncodingForURI();
2212: if (enc != null) {
2213: parameters.setEncoding(enc);
2214: if (useBodyEncodingForURI) {
2215: parameters.setQueryStringEncoding(enc);
2216: }
2217: } else {
2218: parameters
2219: .setEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
2220: if (useBodyEncodingForURI) {
2221: parameters
2222: .setQueryStringEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
2223: }
2224: }
2225:
2226: parameters.handleQueryParameters();
2227:
2228: if (usingInputStream || usingReader)
2229: return;
2230:
2231: if (!getMethod().equalsIgnoreCase("POST"))
2232: return;
2233:
2234: String contentType = getContentType();
2235: if (contentType == null)
2236: contentType = "";
2237: int semicolon = contentType.indexOf(';');
2238: if (semicolon >= 0) {
2239: contentType = contentType.substring(0, semicolon).trim();
2240: } else {
2241: contentType = contentType.trim();
2242: }
2243: if (!("application/x-www-form-urlencoded".equals(contentType)))
2244: return;
2245:
2246: int len = getContentLength();
2247:
2248: if (len > 0) {
2249: int maxPostSize = connector.getMaxPostSize();
2250: if ((maxPostSize > 0) && (len > maxPostSize)) {
2251: log(sm.getString("coyoteRequest.postTooLarge"));
2252: throw new IllegalStateException("Post too large");
2253: }
2254: try {
2255: byte[] formData = null;
2256: if (len < CACHED_POST_LEN) {
2257: if (postData == null)
2258: postData = new byte[CACHED_POST_LEN];
2259: formData = postData;
2260: } else {
2261: formData = new byte[len];
2262: }
2263: int actualLen = readPostBody(formData, len);
2264: if (actualLen == len) {
2265: parameters.processParameters(formData, 0, len);
2266: }
2267: } catch (Throwable t) {
2268: ; // Ignore
2269: }
2270: }
2271:
2272: }
2273:
2274: /**
2275: * Read post body in an array.
2276: */
2277: protected int readPostBody(byte body[], int len) throws IOException {
2278:
2279: int offset = 0;
2280: do {
2281: int inputLen = getStream().read(body, offset, len - offset);
2282: if (inputLen <= 0) {
2283: return offset;
2284: }
2285: offset += inputLen;
2286: } while ((len - offset) > 0);
2287: return len;
2288:
2289: }
2290:
2291: /**
2292: * Parse request locales.
2293: */
2294: protected void parseLocales() {
2295:
2296: localesParsed = true;
2297:
2298: Enumeration values = getHeaders("accept-language");
2299:
2300: while (values.hasMoreElements()) {
2301: String value = values.nextElement().toString();
2302: parseLocalesHeader(value);
2303: }
2304:
2305: }
2306:
2307: /**
2308: * Parse accept-language header value.
2309: */
2310: protected void parseLocalesHeader(String value) {
2311:
2312: // Store the accumulated languages that have been requested in
2313: // a local collection, sorted by the quality value (so we can
2314: // add Locales in descending order). The values will be ArrayLists
2315: // containing the corresponding Locales to be added
2316: TreeMap locales = new TreeMap();
2317:
2318: // Preprocess the value to remove all whitespace
2319: int white = value.indexOf(' ');
2320: if (white < 0)
2321: white = value.indexOf('\t');
2322: if (white >= 0) {
2323: StringBuffer sb = new StringBuffer();
2324: int len = value.length();
2325: for (int i = 0; i < len; i++) {
2326: char ch = value.charAt(i);
2327: if ((ch != ' ') && (ch != '\t'))
2328: sb.append(ch);
2329: }
2330: value = sb.toString();
2331: }
2332:
2333: // Process each comma-delimited language specification
2334: parser.setString(value); // ASSERT: parser is available to us
2335: int length = parser.getLength();
2336: while (true) {
2337:
2338: // Extract the next comma-delimited entry
2339: int start = parser.getIndex();
2340: if (start >= length)
2341: break;
2342: int end = parser.findChar(',');
2343: String entry = parser.extract(start, end).trim();
2344: parser.advance(); // For the following entry
2345:
2346: // Extract the quality factor for this entry
2347: double quality = 1.0;
2348: int semi = entry.indexOf(";q=");
2349: if (semi >= 0) {
2350: try {
2351: quality = Double.parseDouble(entry
2352: .substring(semi + 3));
2353: } catch (NumberFormatException e) {
2354: quality = 0.0;
2355: }
2356: entry = entry.substring(0, semi);
2357: }
2358:
2359: // Skip entries we are not going to keep track of
2360: if (quality < 0.00005)
2361: continue; // Zero (or effectively zero) quality factors
2362: if ("*".equals(entry))
2363: continue; // FIXME - "*" entries are not handled
2364:
2365: // Extract the language and country for this entry
2366: String language = null;
2367: String country = null;
2368: String variant = null;
2369: int dash = entry.indexOf('-');
2370: if (dash < 0) {
2371: language = entry;
2372: country = "";
2373: variant = "";
2374: } else {
2375: language = entry.substring(0, dash);
2376: country = entry.substring(dash + 1);
2377: int vDash = country.indexOf('-');
2378: if (vDash > 0) {
2379: String cTemp = country.substring(0, vDash);
2380: variant = country.substring(vDash + 1);
2381: country = cTemp;
2382: } else {
2383: variant = "";
2384: }
2385: }
2386:
2387: // Add a new Locale to the list of Locales for this quality level
2388: Locale locale = new Locale(language, country, variant);
2389: Double key = new Double(-quality); // Reverse the order
2390: ArrayList values = (ArrayList) locales.get(key);
2391: if (values == null) {
2392: values = new ArrayList();
2393: locales.put(key, values);
2394: }
2395: values.add(locale);
2396:
2397: }
2398:
2399: // Process the quality values in highest->lowest order (due to
2400: // negating the Double value when creating the key)
2401: Iterator keys = locales.keySet().iterator();
2402: while (keys.hasNext()) {
2403: Double key = (Double) keys.next();
2404: ArrayList list = (ArrayList) locales.get(key);
2405: Iterator values = list.iterator();
2406: while (values.hasNext()) {
2407: Locale locale = (Locale) values.next();
2408: addLocale(locale);
2409: }
2410: }
2411:
2412: }
2413:
2414: /**
2415: * Log a message on the Logger associated with our Container (if any).
2416: *
2417: * @param message Message to be logged
2418: */
2419: private void log(String message) {
2420:
2421: Logger logger = connector.getContainer().getLogger();
2422: String localName = "CoyoteRequest";
2423: if (logger != null)
2424: logger.log(localName + " " + message);
2425: else
2426: System.out.println(localName + " " + message);
2427:
2428: }
2429:
2430: /**
2431: * Log a message on the Logger associated with our Container (if any).
2432: *
2433: * @param message Message to be logged
2434: * @param throwable Associated exception
2435: */
2436: private void log(String message, Throwable throwable) {
2437:
2438: Logger logger = connector.getContainer().getLogger();
2439: String localName = "CoyoteRequest";
2440: if (logger != null)
2441: logger.log(localName + " " + message, throwable);
2442: else {
2443: System.out.println(localName + " " + message);
2444: throwable.printStackTrace(System.out);
2445: }
2446:
2447: }
2448:
2449: }
|