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.tomcat4;
0018:
0019: import java.io.BufferedReader;
0020: import java.io.IOException;
0021: import java.io.InputStream;
0022: import java.io.InputStreamReader;
0023: import java.io.UnsupportedEncodingException;
0024: import java.net.InetAddress;
0025: import java.net.Socket;
0026: import java.security.AccessController;
0027: import java.security.Principal;
0028: import java.security.PrivilegedAction;
0029: import java.text.ParseException;
0030: import java.text.SimpleDateFormat;
0031: import java.util.ArrayList;
0032: import java.util.Date;
0033: import java.util.Enumeration;
0034: import java.util.HashMap;
0035: import java.util.Iterator;
0036: import java.util.Locale;
0037: import java.util.Map;
0038: import java.util.TreeMap;
0039:
0040: import javax.servlet.RequestDispatcher;
0041: import javax.servlet.ServletContext;
0042: import javax.servlet.ServletInputStream;
0043: import javax.servlet.ServletRequest;
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.catalina.Connector;
0050: import org.apache.catalina.Context;
0051: import org.apache.catalina.Globals;
0052: import org.apache.catalina.HttpRequest;
0053: import org.apache.catalina.Manager;
0054: import org.apache.catalina.Realm;
0055: import org.apache.catalina.Session;
0056: import org.apache.catalina.Wrapper;
0057: import org.apache.catalina.util.Enumerator;
0058: import org.apache.catalina.util.ParameterMap;
0059: import org.apache.catalina.util.RequestUtil;
0060: import org.apache.catalina.util.StringManager;
0061: import org.apache.catalina.util.StringParser;
0062: import org.apache.coyote.ActionCode;
0063: import org.apache.coyote.Request;
0064: import org.apache.tomcat.util.buf.B2CConverter;
0065: import org.apache.tomcat.util.http.Parameters;
0066:
0067: /**
0068: * Wrapper object for the Coyote request.
0069: *
0070: * @author Remy Maucherat
0071: * @author Craig R. McClanahan
0072: * @version $Revision: 1.37 $ $Date: 2004/02/24 08:54:29 $
0073: */
0074:
0075: public class CoyoteRequest implements HttpRequest, HttpServletRequest {
0076:
0077: // --------------------------------------- PrivilegedGetSession Inner Class
0078:
0079: protected class PrivilegedGetSession implements PrivilegedAction {
0080:
0081: private boolean create;
0082:
0083: PrivilegedGetSession(boolean create) {
0084: this .create = create;
0085: }
0086:
0087: public Object run() {
0088: return doGetSession(create);
0089: }
0090:
0091: }
0092:
0093: // ------------------------------------------------------------- Properties
0094:
0095: /**
0096: * Coyote request.
0097: */
0098: protected Request coyoteRequest;
0099:
0100: /**
0101: * Set the Coyote request.
0102: *
0103: * @param coyoteRequest The Coyote request
0104: */
0105: public void setCoyoteRequest(Request coyoteRequest) {
0106: this .coyoteRequest = coyoteRequest;
0107: inputStream.setRequest(coyoteRequest);
0108: }
0109:
0110: /**
0111: * Get the Coyote request.
0112: */
0113: public Request getCoyoteRequest() {
0114: return (this .coyoteRequest);
0115: }
0116:
0117: // ----------------------------------------------------- Instance Variables
0118:
0119: /**
0120: * The string manager for this package.
0121: */
0122: protected static StringManager sm = StringManager
0123: .getManager(Constants.Package);
0124:
0125: /**
0126: * The set of cookies associated with this Request.
0127: */
0128: protected Cookie[] cookies = null;
0129:
0130: /**
0131: * The set of SimpleDateFormat formats to use in getDateHeader().
0132: */
0133: protected SimpleDateFormat formats[] = {
0134: new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
0135: Locale.US),
0136: new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
0137: Locale.US),
0138: new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
0139:
0140: /**
0141: * The default Locale if none are specified.
0142: */
0143: protected static Locale defaultLocale = Locale.getDefault();
0144:
0145: /**
0146: * The attributes associated with this Request, keyed by attribute name.
0147: */
0148: protected HashMap attributes = new HashMap();
0149:
0150: /**
0151: * The preferred Locales assocaited with this Request.
0152: */
0153: protected ArrayList locales = new ArrayList();
0154:
0155: /**
0156: * Internal notes associated with this request by Catalina components
0157: * and event listeners.
0158: */
0159: private transient HashMap notes = new HashMap();
0160:
0161: /**
0162: * Authentication type.
0163: */
0164: protected String authType = null;
0165:
0166: /**
0167: * Reader.
0168: * Note: At the moment, no attempt is being made at recycling the reader,
0169: * but this could be implemented in the future, using a design like the one
0170: * used for the output buffer.
0171: */
0172: protected BufferedReader reader = null;
0173:
0174: /**
0175: * ServletInputStream.
0176: */
0177: protected CoyoteInputStream inputStream = new CoyoteInputStream();
0178:
0179: /**
0180: * Using stream flag.
0181: */
0182: protected boolean usingInputStream = false;
0183:
0184: /**
0185: * Using writer flag.
0186: */
0187: protected boolean usingReader = false;
0188:
0189: /**
0190: * Context path.
0191: */
0192: protected String contextPath = "";
0193:
0194: /**
0195: * Path info.
0196: */
0197: protected String pathInfo = null;
0198:
0199: /**
0200: * Servlet path.
0201: */
0202: protected String servletPath = null;
0203:
0204: /**
0205: * User principal.
0206: */
0207: protected Principal userPrincipal = null;
0208:
0209: /**
0210: * Session parsed flag.
0211: */
0212: protected boolean sessionParsed = false;
0213:
0214: /**
0215: * Request parameters parsed flag.
0216: */
0217: protected boolean requestParametersParsed = false;
0218:
0219: /**
0220: * Secure flag.
0221: */
0222: protected boolean secure = false;
0223:
0224: /**
0225: * Post data buffer.
0226: */
0227: protected static int CACHED_POST_LEN = 8192;
0228: protected byte[] postData = null;
0229:
0230: /**
0231: * Hash map used in the getParametersMap method.
0232: */
0233: protected ParameterMap parameterMap = new ParameterMap();
0234:
0235: /**
0236: * The currently active session for this request.
0237: */
0238: protected Session session = null;
0239:
0240: /**
0241: * Was the requested session ID received in a cookie?
0242: */
0243: protected boolean requestedSessionCookie = false;
0244:
0245: /**
0246: * The requested session ID (if any) for this request.
0247: */
0248: protected String requestedSessionId = null;
0249:
0250: /**
0251: * Was the requested session ID received in a URL?
0252: */
0253: protected boolean requestedSessionURL = false;
0254:
0255: /**
0256: * The socket through which this Request was received.
0257: */
0258: protected Socket socket = null;
0259:
0260: /**
0261: * Parse locales.
0262: */
0263: protected boolean localesParsed = false;
0264:
0265: /**
0266: * The string parser we will use for parsing request lines.
0267: */
0268: private StringParser parser = new StringParser();
0269:
0270: /**
0271: * Remote address.
0272: */
0273: protected String remoteAddr = null;
0274:
0275: /**
0276: * Remote host.
0277: */
0278: protected String remoteHost = null;
0279:
0280: // --------------------------------------------------------- Public Methods
0281:
0282: /**
0283: * Release all object references, and initialize instance variables, in
0284: * preparation for reuse of this object.
0285: */
0286: public void recycle() {
0287:
0288: context = null;
0289: wrapper = null;
0290:
0291: authorization = null;
0292: authType = null;
0293: usingInputStream = false;
0294: usingReader = false;
0295: contextPath = "";
0296: pathInfo = null;
0297: servletPath = null;
0298: reader = null;
0299: inputStream.recycle();
0300: userPrincipal = null;
0301: sessionParsed = false;
0302: authorization = null;
0303: requestParametersParsed = false;
0304: locales.clear();
0305: localesParsed = false;
0306: secure = false;
0307: remoteAddr = null;
0308: remoteHost = null;
0309:
0310: attributes.clear();
0311: notes.clear();
0312: cookies = null;
0313:
0314: session = null;
0315: requestedSessionCookie = false;
0316: requestedSessionId = null;
0317: requestedSessionURL = false;
0318:
0319: parameterMap.setLocked(false);
0320: parameterMap.clear();
0321:
0322: if (facade != null) {
0323: facade.clear();
0324: facade = null;
0325: }
0326:
0327: }
0328:
0329: // -------------------------------------------------------- Request Methods
0330:
0331: /**
0332: * The authorization credentials sent with this Request.
0333: */
0334: protected String authorization = null;
0335:
0336: /**
0337: * Return the authorization credentials sent with this request.
0338: */
0339: public String getAuthorization() {
0340:
0341: return (this .authorization);
0342:
0343: }
0344:
0345: /**
0346: * Set the authorization credentials sent with this request.
0347: *
0348: * @param authorization The new authorization credentials
0349: */
0350: public void setAuthorization(String authorization) {
0351: this .authorization = authorization;
0352: }
0353:
0354: /**
0355: * Associated Catalina connector.
0356: */
0357: protected CoyoteConnector connector;
0358:
0359: /**
0360: * Return the Connector through which this Request was received.
0361: */
0362: public Connector getConnector() {
0363: return (this .connector);
0364: }
0365:
0366: /**
0367: * Set the Connector through which this Request was received.
0368: *
0369: * @param connector The new connector
0370: */
0371: public void setConnector(Connector connector) {
0372: this .connector = (CoyoteConnector) connector;
0373: }
0374:
0375: /**
0376: * The Context within which this Request is being processed.
0377: */
0378: protected Context context = null;
0379:
0380: /**
0381: * Return the Context within which this Request is being processed.
0382: */
0383: public Context getContext() {
0384: return (this .context);
0385: }
0386:
0387: /**
0388: * Set the Context within which this Request is being processed. This
0389: * must be called as soon as the appropriate Context is identified, because
0390: * it identifies the value to be returned by <code>getContextPath()</code>,
0391: * and thus enables parsing of the request URI.
0392: *
0393: * @param context The newly associated Context
0394: */
0395: public void setContext(Context context) {
0396: this .context = context;
0397: }
0398:
0399: /**
0400: * Descriptive information about this Request implementation.
0401: */
0402: protected static final String info = "org.apache.coyote.catalina.CoyoteRequest/1.0";
0403:
0404: /**
0405: * Return descriptive information about this Request implementation and
0406: * the corresponding version number, in the format
0407: * <code><description>/<version></code>.
0408: */
0409: public String getInfo() {
0410: return (info);
0411: }
0412:
0413: /**
0414: * The facade associated with this request.
0415: */
0416: protected CoyoteRequestFacade facade = null;
0417:
0418: /**
0419: * Return the <code>ServletRequest</code> for which this object
0420: * is the facade. This method must be implemented by a subclass.
0421: */
0422: public ServletRequest getRequest() {
0423: if (facade == null) {
0424: facade = new CoyoteRequestFacade(this );
0425: }
0426: return (facade);
0427: }
0428:
0429: /**
0430: * The response with which this request is associated.
0431: */
0432: protected org.apache.catalina.Response response = null;
0433:
0434: /**
0435: * Return the Response with which this Request is associated.
0436: */
0437: public org.apache.catalina.Response getResponse() {
0438: return (this .response);
0439: }
0440:
0441: /**
0442: * Set the Response with which this Request is associated.
0443: *
0444: * @param response The new associated response
0445: */
0446: public void setResponse(org.apache.catalina.Response response) {
0447: this .response = response;
0448: }
0449:
0450: /**
0451: * Return the Socket (if any) through which this Request was received.
0452: * This should <strong>only</strong> be used to access underlying state
0453: * information about this Socket, such as the SSLSession associated with
0454: * an SSLSocket.
0455: */
0456: public Socket getSocket() {
0457: return (socket);
0458: }
0459:
0460: /**
0461: * Set the Socket (if any) through which this Request was received.
0462: *
0463: * @param socket The socket through which this request was received
0464: */
0465: public void setSocket(Socket socket) {
0466: this .socket = socket;
0467: remoteHost = null;
0468: remoteAddr = null;
0469: }
0470:
0471: /**
0472: * Return the input stream associated with this Request.
0473: */
0474: public InputStream getStream() {
0475: return inputStream;
0476: }
0477:
0478: /**
0479: * Set the input stream associated with this Request.
0480: *
0481: * @param stream The new input stream
0482: */
0483: public void setStream(InputStream stream) {
0484: // Ignore
0485: }
0486:
0487: /**
0488: * URI byte to char converter (not recycled).
0489: */
0490: protected B2CConverter URIConverter = null;
0491:
0492: /**
0493: * Return the URI converter.
0494: */
0495: protected B2CConverter getURIConverter() {
0496: return URIConverter;
0497: }
0498:
0499: /**
0500: * Set the URI converter.
0501: *
0502: * @param URIConverter the new URI connverter
0503: */
0504: protected void setURIConverter(B2CConverter URIConverter) {
0505: this .URIConverter = URIConverter;
0506: }
0507:
0508: /**
0509: * The Wrapper within which this Request is being processed.
0510: */
0511: protected Wrapper wrapper = null;
0512:
0513: /**
0514: * Return the Wrapper within which this Request is being processed.
0515: */
0516: public Wrapper getWrapper() {
0517: return (this .wrapper);
0518: }
0519:
0520: /**
0521: * Set the Wrapper within which this Request is being processed. This
0522: * must be called as soon as the appropriate Wrapper is identified, and
0523: * before the Request is ultimately passed to an application servlet.
0524: *
0525: * @param wrapper The newly associated Wrapper
0526: */
0527: public void setWrapper(Wrapper wrapper) {
0528: this .wrapper = wrapper;
0529: }
0530:
0531: // ------------------------------------------------- Request Public Methods
0532:
0533: /**
0534: * Create and return a ServletInputStream to read the content
0535: * associated with this Request.
0536: *
0537: * @exception IOException if an input/output error occurs
0538: */
0539: public ServletInputStream createInputStream() throws IOException {
0540: return inputStream;
0541: }
0542:
0543: /**
0544: * Perform whatever actions are required to flush and close the input
0545: * stream or reader, in a single operation.
0546: *
0547: * @exception IOException if an input/output error occurs
0548: */
0549: public void finishRequest() throws IOException {
0550: // The reader and input stream don't need to be closed
0551: }
0552:
0553: /**
0554: * Return the object bound with the specified name to the internal notes
0555: * for this request, or <code>null</code> if no such binding exists.
0556: *
0557: * @param name Name of the note to be returned
0558: */
0559: public Object getNote(String name) {
0560: return (notes.get(name));
0561: }
0562:
0563: /**
0564: * Return an Iterator containing the String names of all notes bindings
0565: * that exist for this request.
0566: */
0567: public Iterator getNoteNames() {
0568: return (notes.keySet().iterator());
0569: }
0570:
0571: /**
0572: * Remove any object bound to the specified name in the internal notes
0573: * for this request.
0574: *
0575: * @param name Name of the note to be removed
0576: */
0577: public void removeNote(String name) {
0578: notes.remove(name);
0579: }
0580:
0581: /**
0582: * Bind an object to a specified name in the internal notes associated
0583: * with this request, replacing any existing binding for this name.
0584: *
0585: * @param name Name to which the object should be bound
0586: * @param value Object to be bound to the specified name
0587: */
0588: public void setNote(String name, Object value) {
0589: notes.put(name, value);
0590: }
0591:
0592: /**
0593: * Set the content length associated with this Request.
0594: *
0595: * @param length The new content length
0596: */
0597: public void setContentLength(int length) {
0598: // Not used
0599: }
0600:
0601: /**
0602: * Set the content type (and optionally the character encoding)
0603: * associated with this Request. For example,
0604: * <code>text/html; charset=ISO-8859-4</code>.
0605: *
0606: * @param type The new content type
0607: */
0608: public void setContentType(String type) {
0609: // Not used
0610: }
0611:
0612: /**
0613: * Set the protocol name and version associated with this Request.
0614: *
0615: * @param protocol Protocol name and version
0616: */
0617: public void setProtocol(String protocol) {
0618: // Not used
0619: }
0620:
0621: /**
0622: * Set the IP address of the remote client associated with this Request.
0623: *
0624: * @param remoteAddr The remote IP address
0625: */
0626: public void setRemoteAddr(String remoteAddr) {
0627: // Not used
0628: }
0629:
0630: /**
0631: * Set the fully qualified name of the remote client associated with this
0632: * Request.
0633: *
0634: * @param remoteHost The remote host name
0635: */
0636: public void setRemoteHost(String remoteHost) {
0637: // Not used
0638: }
0639:
0640: /**
0641: * Set the name of the scheme associated with this request. Typical values
0642: * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
0643: *
0644: * @param scheme The scheme
0645: */
0646: public void setScheme(String scheme) {
0647: // Not used
0648: }
0649:
0650: /**
0651: * Set the value to be returned by <code>isSecure()</code>
0652: * for this Request.
0653: *
0654: * @param secure The new isSecure value
0655: */
0656: public void setSecure(boolean secure) {
0657: this .secure = secure;
0658: }
0659:
0660: /**
0661: * Set the name of the server (virtual host) to process this request.
0662: *
0663: * @param name The server name
0664: */
0665: public void setServerName(String name) {
0666: coyoteRequest.serverName().setString(name);
0667: }
0668:
0669: /**
0670: * Set the port number of the server to process this request.
0671: *
0672: * @param port The server port
0673: */
0674: public void setServerPort(int port) {
0675: coyoteRequest.setServerPort(port);
0676: }
0677:
0678: // ------------------------------------------------- ServletRequest Methods
0679:
0680: /**
0681: * Return the specified request attribute if it exists; otherwise, return
0682: * <code>null</code>.
0683: *
0684: * @param name Name of the request attribute to return
0685: */
0686: public Object getAttribute(String name) {
0687: Object attr = attributes.get(name);
0688:
0689: if (attr != null)
0690: return (attr);
0691:
0692: attr = coyoteRequest.getAttribute(name);
0693: if (attr != null) {
0694: attributes.put(name, attr);
0695: return attr;
0696: }
0697: // XXX Should move to Globals
0698: if (Constants.SSL_CERTIFICATE_ATTR.equals(name)) {
0699: coyoteRequest.action(ActionCode.ACTION_REQ_SSL_CERTIFICATE,
0700: null);
0701: attr = getAttribute(Globals.CERTIFICATES_ATTR);
0702: if (attr != null)
0703: attributes.put(name, attr);
0704: }
0705: return attr;
0706: }
0707:
0708: /**
0709: * Return the names of all request attributes for this Request, or an
0710: * empty <code>Enumeration</code> if there are none.
0711: */
0712: public Enumeration getAttributeNames() {
0713: return (new Enumerator(attributes.keySet()));
0714: }
0715:
0716: /**
0717: * Return the character encoding for this Request.
0718: */
0719: public String getCharacterEncoding() {
0720: return (coyoteRequest.getCharacterEncoding());
0721: }
0722:
0723: /**
0724: * Return the content length for this Request.
0725: */
0726: public int getContentLength() {
0727: return (coyoteRequest.getContentLength());
0728: }
0729:
0730: /**
0731: * Return the content type for this Request.
0732: */
0733: public String getContentType() {
0734: return (coyoteRequest.getContentType());
0735: }
0736:
0737: /**
0738: * Return the servlet input stream for this Request. The default
0739: * implementation returns a servlet input stream created by
0740: * <code>createInputStream()</code>.
0741: *
0742: * @exception IllegalStateException if <code>getReader()</code> has
0743: * already been called for this request
0744: * @exception IOException if an input/output error occurs
0745: */
0746: public ServletInputStream getInputStream() throws IOException {
0747:
0748: if (usingReader)
0749: throw new IllegalStateException(sm
0750: .getString("coyoteRequest.getInputStream.ise"));
0751:
0752: usingInputStream = true;
0753: return inputStream;
0754:
0755: }
0756:
0757: /**
0758: * Return the preferred Locale that the client will accept content in,
0759: * based on the value for the first <code>Accept-Language</code> header
0760: * that was encountered. If the request did not specify a preferred
0761: * language, the server's default Locale is returned.
0762: */
0763: public Locale getLocale() {
0764:
0765: if (!localesParsed)
0766: parseLocales();
0767:
0768: if (locales.size() > 0) {
0769: return ((Locale) locales.get(0));
0770: } else {
0771: return (defaultLocale);
0772: }
0773:
0774: }
0775:
0776: /**
0777: * Return the set of preferred Locales that the client will accept
0778: * content in, based on the values for any <code>Accept-Language</code>
0779: * headers that were encountered. If the request did not specify a
0780: * preferred language, the server's default Locale is returned.
0781: */
0782: public Enumeration getLocales() {
0783:
0784: if (!localesParsed)
0785: parseLocales();
0786:
0787: if (locales.size() > 0)
0788: return (new Enumerator(locales));
0789: ArrayList results = new ArrayList();
0790: results.add(defaultLocale);
0791: return (new Enumerator(results));
0792:
0793: }
0794:
0795: /**
0796: * Return the value of the specified request parameter, if any; otherwise,
0797: * return <code>null</code>. If there is more than one value defined,
0798: * return only the first one.
0799: *
0800: * @param name Name of the desired request parameter
0801: */
0802: public String getParameter(String name) {
0803:
0804: if (!requestParametersParsed)
0805: parseRequestParameters();
0806:
0807: return coyoteRequest.getParameters().getParameter(name);
0808:
0809: }
0810:
0811: /**
0812: * Returns a <code>Map</code> of the parameters of this request.
0813: * Request parameters are extra information sent with the request.
0814: * For HTTP servlets, parameters are contained in the query string
0815: * or posted form data.
0816: *
0817: * @return A <code>Map</code> containing parameter names as keys
0818: * and parameter values as map values.
0819: */
0820: public Map getParameterMap() {
0821:
0822: if (parameterMap.isLocked())
0823: return parameterMap;
0824:
0825: Enumeration enum = getParameterNames();
0826: while (enum.hasMoreElements()) {
0827: String name = enum.nextElement().toString();
0828: String[] values = getParameterValues(name);
0829: parameterMap.put(name, values);
0830: }
0831:
0832: parameterMap.setLocked(true);
0833:
0834: return parameterMap;
0835:
0836: }
0837:
0838: /**
0839: * Return the names of all defined request parameters for this request.
0840: */
0841: public Enumeration getParameterNames() {
0842:
0843: if (!requestParametersParsed)
0844: parseRequestParameters();
0845:
0846: return coyoteRequest.getParameters().getParameterNames();
0847:
0848: }
0849:
0850: /**
0851: * Return the defined values for the specified request parameter, if any;
0852: * otherwise, return <code>null</code>.
0853: *
0854: * @param name Name of the desired request parameter
0855: */
0856: public String[] getParameterValues(String name) {
0857:
0858: if (!requestParametersParsed)
0859: parseRequestParameters();
0860:
0861: return coyoteRequest.getParameters().getParameterValues(name);
0862:
0863: }
0864:
0865: /**
0866: * Return the protocol and version used to make this Request.
0867: */
0868: public String getProtocol() {
0869: return coyoteRequest.protocol().toString();
0870: }
0871:
0872: /**
0873: * Read the Reader wrapping the input stream for this Request. The
0874: * default implementation wraps a <code>BufferedReader</code> around the
0875: * servlet input stream returned by <code>createInputStream()</code>.
0876: *
0877: * @exception IllegalStateException if <code>getInputStream()</code>
0878: * has already been called for this request
0879: * @exception IOException if an input/output error occurs
0880: */
0881: public BufferedReader getReader() throws IOException {
0882:
0883: if (usingInputStream)
0884: throw new IllegalStateException(sm
0885: .getString("coyoteRequest.getReader.ise"));
0886:
0887: usingReader = true;
0888: if (reader == null) {
0889: String encoding = getCharacterEncoding();
0890: if (encoding == null) {
0891: encoding = org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
0892: }
0893: InputStreamReader r = new InputStreamReader(inputStream,
0894: encoding);
0895: reader = new BufferedReader(r);
0896: }
0897: return (reader);
0898:
0899: }
0900:
0901: /**
0902: * Return the real path of the specified virtual path.
0903: *
0904: * @param path Path to be translated
0905: *
0906: * @deprecated As of version 2.1 of the Java Servlet API, use
0907: * <code>ServletContext.getRealPath()</code>.
0908: */
0909: public String getRealPath(String path) {
0910:
0911: if (context == null)
0912: return (null);
0913: ServletContext servletContext = context.getServletContext();
0914: if (servletContext == null)
0915: return (null);
0916: else {
0917: try {
0918: return (servletContext.getRealPath(path));
0919: } catch (IllegalArgumentException e) {
0920: return (null);
0921: }
0922: }
0923:
0924: }
0925:
0926: /**
0927: * Return the remote IP address making this Request.
0928: */
0929: public String getRemoteAddr() {
0930: if (remoteAddr == null) {
0931: if (socket != null) {
0932: InetAddress inet = socket.getInetAddress();
0933: remoteAddr = inet.getHostAddress();
0934: } else {
0935: coyoteRequest.action(
0936: ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE,
0937: coyoteRequest);
0938: remoteAddr = coyoteRequest.remoteAddr().toString();
0939: }
0940: }
0941: return remoteAddr;
0942: }
0943:
0944: /**
0945: * Return the remote host name making this Request.
0946: */
0947: public String getRemoteHost() {
0948: if (remoteHost == null) {
0949: if (!connector.getEnableLookups()) {
0950: remoteHost = getRemoteAddr();
0951: } else if (socket != null) {
0952: InetAddress inet = socket.getInetAddress();
0953: remoteHost = inet.getHostName();
0954: } else {
0955: coyoteRequest.action(
0956: ActionCode.ACTION_REQ_HOST_ATTRIBUTE,
0957: coyoteRequest);
0958: remoteHost = coyoteRequest.remoteHost().toString();
0959: }
0960: }
0961: return remoteHost;
0962: }
0963:
0964: /**
0965: * Return a RequestDispatcher that wraps the resource at the specified
0966: * path, which may be interpreted as relative to the current request path.
0967: *
0968: * @param path Path of the resource to be wrapped
0969: */
0970: public RequestDispatcher getRequestDispatcher(String path) {
0971:
0972: if (context == null)
0973: return (null);
0974:
0975: // If the path is already context-relative, just pass it through
0976: if (path == null)
0977: return (null);
0978: else if (path.startsWith("/"))
0979: return (context.getServletContext()
0980: .getRequestDispatcher(path));
0981:
0982: // Convert a request-relative path to a context-relative one
0983: String servletPath = (String) getAttribute(Globals.SERVLET_PATH_ATTR);
0984: if (servletPath == null)
0985: servletPath = getServletPath();
0986:
0987: // Add the path info, if there is any
0988: String pathInfo = getPathInfo();
0989: String requestPath = null;
0990:
0991: if (pathInfo == null) {
0992: requestPath = servletPath;
0993: } else {
0994: requestPath = servletPath + pathInfo;
0995: }
0996:
0997: int pos = requestPath.lastIndexOf('/');
0998: String relative = null;
0999: if (pos >= 0) {
1000: relative = RequestUtil.normalize(requestPath.substring(0,
1001: pos + 1)
1002: + path);
1003: } else {
1004: relative = RequestUtil.normalize(requestPath + path);
1005: }
1006:
1007: return (context.getServletContext()
1008: .getRequestDispatcher(relative));
1009:
1010: }
1011:
1012: /**
1013: * Return the scheme used to make this Request.
1014: */
1015: public String getScheme() {
1016: return (coyoteRequest.scheme().toString());
1017: }
1018:
1019: /**
1020: * Return the server name responding to this Request.
1021: */
1022: public String getServerName() {
1023: return (coyoteRequest.serverName().toString());
1024: }
1025:
1026: /**
1027: * Return the server port responding to this Request.
1028: */
1029: public int getServerPort() {
1030: return (coyoteRequest.getServerPort());
1031: }
1032:
1033: /**
1034: * Was this request received on a secure connection?
1035: */
1036: public boolean isSecure() {
1037: return (secure);
1038: }
1039:
1040: /**
1041: * Remove the specified request attribute if it exists.
1042: *
1043: * @param name Name of the request attribute to remove
1044: */
1045: public void removeAttribute(String name) {
1046: attributes.remove(name);
1047: }
1048:
1049: /**
1050: * Set the specified request attribute to the specified value.
1051: *
1052: * @param name Name of the request attribute to set
1053: * @param value The associated value
1054: */
1055: public void setAttribute(String name, Object value) {
1056:
1057: // Name cannot be null
1058: if (name == null)
1059: throw new IllegalArgumentException(sm
1060: .getString("coyoteRequest.setAttribute.namenull"));
1061:
1062: // Null value is the same as removeAttribute()
1063: if (value == null) {
1064: removeAttribute(name);
1065: return;
1066: }
1067:
1068: attributes.put(name, value);
1069:
1070: }
1071:
1072: /**
1073: * Overrides the name of the character encoding used in the body of
1074: * this request. This method must be called prior to reading request
1075: * parameters or reading input using <code>getReader()</code>.
1076: *
1077: * @param enc The character encoding to be used
1078: *
1079: * @exception UnsupportedEncodingException if the specified encoding
1080: * is not supported
1081: *
1082: * @since Servlet 2.3
1083: */
1084: public void setCharacterEncoding(String enc)
1085: throws UnsupportedEncodingException {
1086:
1087: // Ensure that the specified encoding is valid
1088: byte buffer[] = new byte[1];
1089: buffer[0] = (byte) 'a';
1090: String dummy = new String(buffer, enc);
1091:
1092: // Save the validated encoding
1093: coyoteRequest.setCharacterEncoding(enc);
1094:
1095: }
1096:
1097: // ---------------------------------------------------- HttpRequest Methods
1098:
1099: /**
1100: * Add a Cookie to the set of Cookies associated with this Request.
1101: *
1102: * @param cookie The new cookie
1103: */
1104: public void addCookie(Cookie cookie) {
1105:
1106: // For compatibility only
1107:
1108: int size = 0;
1109: if (cookies != null) {
1110: size = cookies.length;
1111: }
1112:
1113: Cookie[] newCookies = new Cookie[size + 1];
1114: for (int i = 0; i < size; i++) {
1115: newCookies[i] = cookies[i];
1116: }
1117: newCookies[size] = cookie;
1118:
1119: cookies = newCookies;
1120:
1121: }
1122:
1123: /**
1124: * Add a Header to the set of Headers associated with this Request.
1125: *
1126: * @param name The new header name
1127: * @param value The new header value
1128: */
1129: public void addHeader(String name, String value) {
1130: // Not used
1131: }
1132:
1133: /**
1134: * Add a Locale to the set of preferred Locales for this Request. The
1135: * first added Locale will be the first one returned by getLocales().
1136: *
1137: * @param locale The new preferred Locale
1138: */
1139: public void addLocale(Locale locale) {
1140: locales.add(locale);
1141: }
1142:
1143: /**
1144: * Add a parameter name and corresponding set of values to this Request.
1145: * (This is used when restoring the original request on a form based
1146: * login).
1147: *
1148: * @param name Name of this request parameter
1149: * @param values Corresponding values for this request parameter
1150: */
1151: public void addParameter(String name, String values[]) {
1152: coyoteRequest.getParameters().addParameterValues(name, values);
1153: }
1154:
1155: /**
1156: * Clear the collection of Cookies associated with this Request.
1157: */
1158: public void clearCookies() {
1159: cookies = null;
1160: }
1161:
1162: /**
1163: * Clear the collection of Headers associated with this Request.
1164: */
1165: public void clearHeaders() {
1166: // Not used
1167: }
1168:
1169: /**
1170: * Clear the collection of Locales associated with this Request.
1171: */
1172: public void clearLocales() {
1173: locales.clear();
1174: }
1175:
1176: /**
1177: * Clear the collection of parameters associated with this Request.
1178: */
1179: public void clearParameters() {
1180: // Not used
1181: }
1182:
1183: /**
1184: * Set the authentication type used for this request, if any; otherwise
1185: * set the type to <code>null</code>. Typical values are "BASIC",
1186: * "DIGEST", or "SSL".
1187: *
1188: * @param type The authentication type used
1189: */
1190: public void setAuthType(String type) {
1191: this .authType = type;
1192: }
1193:
1194: /**
1195: * Set the context path for this Request. This will normally be called
1196: * when the associated Context is mapping the Request to a particular
1197: * Wrapper.
1198: *
1199: * @param path The context path
1200: */
1201: public void setContextPath(String path) {
1202:
1203: if (path == null) {
1204: this .contextPath = "";
1205: } else {
1206: this .contextPath = path;
1207: }
1208:
1209: }
1210:
1211: /**
1212: * Set the HTTP request method used for this Request.
1213: *
1214: * @param method The request method
1215: */
1216: public void setMethod(String method) {
1217: // Not used
1218: }
1219:
1220: /**
1221: * Set the query string for this Request. This will normally be called
1222: * by the HTTP Connector, when it parses the request headers.
1223: *
1224: * @param query The query string
1225: */
1226: public void setQueryString(String query) {
1227: // Not used
1228: }
1229:
1230: /**
1231: * Set the path information for this Request. This will normally be called
1232: * when the associated Context is mapping the Request to a particular
1233: * Wrapper.
1234: *
1235: * @param path The path information
1236: */
1237: public void setPathInfo(String path) {
1238: this .pathInfo = path;
1239: }
1240:
1241: /**
1242: * Set a flag indicating whether or not the requested session ID for this
1243: * request came in through a cookie. This is normally called by the
1244: * HTTP Connector, when it parses the request headers.
1245: *
1246: * @param flag The new flag
1247: */
1248: public void setRequestedSessionCookie(boolean flag) {
1249:
1250: this .requestedSessionCookie = flag;
1251:
1252: }
1253:
1254: /**
1255: * Set the requested session ID for this request. This is normally called
1256: * by the HTTP Connector, when it parses the request headers.
1257: *
1258: * @param id The new session id
1259: */
1260: public void setRequestedSessionId(String id) {
1261:
1262: this .requestedSessionId = id;
1263:
1264: }
1265:
1266: /**
1267: * Set a flag indicating whether or not the requested session ID for this
1268: * request came in through a URL. This is normally called by the
1269: * HTTP Connector, when it parses the request headers.
1270: *
1271: * @param flag The new flag
1272: */
1273: public void setRequestedSessionURL(boolean flag) {
1274:
1275: this .requestedSessionURL = flag;
1276:
1277: }
1278:
1279: /**
1280: * Set the unparsed request URI for this Request. This will normally be
1281: * called by the HTTP Connector, when it parses the request headers.
1282: *
1283: * @param uri The request URI
1284: */
1285: public void setRequestURI(String uri) {
1286: // Not used
1287: }
1288:
1289: /**
1290: * Set the decoded request URI.
1291: *
1292: * @param uri The decoded request URI
1293: */
1294: public void setDecodedRequestURI(String uri) {
1295: // Not used
1296: }
1297:
1298: /**
1299: * Get the decoded request URI.
1300: *
1301: * @return the URL decoded request URI
1302: */
1303: public String getDecodedRequestURI() {
1304: return (coyoteRequest.decodedURI().toString());
1305: }
1306:
1307: /**
1308: * Set the servlet path for this Request. This will normally be called
1309: * when the associated Context is mapping the Request to a particular
1310: * Wrapper.
1311: *
1312: * @param path The servlet path
1313: */
1314: public void setServletPath(String path) {
1315: this .servletPath = path;
1316: }
1317:
1318: /**
1319: * Set the Principal who has been authenticated for this Request. This
1320: * value is also used to calculate the value to be returned by the
1321: * <code>getRemoteUser()</code> method.
1322: *
1323: * @param principal The user Principal
1324: */
1325: public void setUserPrincipal(Principal principal) {
1326: this .userPrincipal = principal;
1327: }
1328:
1329: // --------------------------------------------- HttpServletRequest Methods
1330:
1331: /**
1332: * Return the authentication type used for this Request.
1333: */
1334: public String getAuthType() {
1335: return (authType);
1336: }
1337:
1338: /**
1339: * Return the portion of the request URI used to select the Context
1340: * of the Request.
1341: */
1342: public String getContextPath() {
1343: return (contextPath);
1344: }
1345:
1346: /**
1347: * Return the set of Cookies received with this Request.
1348: */
1349: public Cookie[] getCookies() {
1350:
1351: return cookies;
1352:
1353: }
1354:
1355: /**
1356: * Set the set of cookies recieved with this Request.
1357: */
1358: public void setCookies(Cookie[] cookies) {
1359:
1360: this .cookies = cookies;
1361:
1362: }
1363:
1364: /**
1365: * Return the value of the specified date header, if any; otherwise
1366: * return -1.
1367: *
1368: * @param name Name of the requested date header
1369: *
1370: * @exception IllegalArgumentException if the specified header value
1371: * cannot be converted to a date
1372: */
1373: public long getDateHeader(String name) {
1374:
1375: String value = getHeader(name);
1376: if (value == null)
1377: return (-1L);
1378:
1379: // Work around a bug in SimpleDateFormat in pre-JDK1.2b4
1380: // (Bug Parade bug #4106807)
1381: value += " ";
1382:
1383: // Attempt to convert the date header in a variety of formats
1384: for (int i = 0; i < formats.length; i++) {
1385: try {
1386: Date date = formats[i].parse(value);
1387: return (date.getTime());
1388: } catch (ParseException e) {
1389: ;
1390: }
1391: }
1392: throw new IllegalArgumentException(value);
1393:
1394: }
1395:
1396: /**
1397: * Return the first value of the specified header, if any; otherwise,
1398: * return <code>null</code>
1399: *
1400: * @param name Name of the requested header
1401: */
1402: public String getHeader(String name) {
1403: return coyoteRequest.getHeader(name);
1404: }
1405:
1406: /**
1407: * Return all of the values of the specified header, if any; otherwise,
1408: * return an empty enumeration.
1409: *
1410: * @param name Name of the requested header
1411: */
1412: public Enumeration getHeaders(String name) {
1413: return coyoteRequest.getMimeHeaders().values(name);
1414: }
1415:
1416: /**
1417: * Return the names of all headers received with this request.
1418: */
1419: public Enumeration getHeaderNames() {
1420: return coyoteRequest.getMimeHeaders().names();
1421: }
1422:
1423: /**
1424: * Return the value of the specified header as an integer, or -1 if there
1425: * is no such header for this request.
1426: *
1427: * @param name Name of the requested header
1428: *
1429: * @exception IllegalArgumentException if the specified header value
1430: * cannot be converted to an integer
1431: */
1432: public int getIntHeader(String name) {
1433:
1434: String value = getHeader(name);
1435: if (value == null) {
1436: return (-1);
1437: } else {
1438: return (Integer.parseInt(value));
1439: }
1440:
1441: }
1442:
1443: /**
1444: * Return the HTTP request method used in this Request.
1445: */
1446: public String getMethod() {
1447: return coyoteRequest.method().toString();
1448: }
1449:
1450: /**
1451: * Return the path information associated with this Request.
1452: */
1453: public String getPathInfo() {
1454: return (pathInfo);
1455: }
1456:
1457: /**
1458: * Return the extra path information for this request, translated
1459: * to a real path.
1460: */
1461: public String getPathTranslated() {
1462:
1463: if (context == null)
1464: return (null);
1465:
1466: if (pathInfo == null) {
1467: return (null);
1468: } else {
1469: return (context.getServletContext().getRealPath(pathInfo));
1470: }
1471:
1472: }
1473:
1474: /**
1475: * Return the query string associated with this request.
1476: */
1477: public String getQueryString() {
1478: String queryString = coyoteRequest.queryString().toString();
1479: if (queryString.equals("")) {
1480: return (null);
1481: } else {
1482: return queryString;
1483: }
1484: }
1485:
1486: /**
1487: * Return the name of the remote user that has been authenticated
1488: * for this Request.
1489: */
1490: public String getRemoteUser() {
1491:
1492: if (userPrincipal != null) {
1493: return (userPrincipal.getName());
1494: } else {
1495: return (null);
1496: }
1497:
1498: }
1499:
1500: /**
1501: * Return the session identifier included in this request, if any.
1502: */
1503: public String getRequestedSessionId() {
1504: return (requestedSessionId);
1505: }
1506:
1507: /**
1508: * Return the request URI for this request.
1509: */
1510: public String getRequestURI() {
1511: return coyoteRequest.requestURI().toString();
1512: }
1513:
1514: /**
1515: * Reconstructs the URL the client used to make the request.
1516: * The returned URL contains a protocol, server name, port
1517: * number, and server path, but it does not include query
1518: * string parameters.
1519: * <p>
1520: * Because this method returns a <code>StringBuffer</code>,
1521: * not a <code>String</code>, you can modify the URL easily,
1522: * for example, to append query parameters.
1523: * <p>
1524: * This method is useful for creating redirect messages and
1525: * for reporting errors.
1526: *
1527: * @return A <code>StringBuffer</code> object containing the
1528: * reconstructed URL
1529: */
1530: public StringBuffer getRequestURL() {
1531:
1532: StringBuffer url = new StringBuffer();
1533: String scheme = getScheme();
1534: int port = getServerPort();
1535: if (port < 0)
1536: port = 80; // Work around java.net.URL bug
1537:
1538: url.append(scheme);
1539: url.append("://");
1540: url.append(getServerName());
1541: if ((scheme.equals("http") && (port != 80))
1542: || (scheme.equals("https") && (port != 443))) {
1543: url.append(':');
1544: url.append(port);
1545: }
1546: url.append(getRequestURI());
1547:
1548: return (url);
1549:
1550: }
1551:
1552: /**
1553: * Return the portion of the request URI used to select the servlet
1554: * that will process this request.
1555: */
1556: public String getServletPath() {
1557: return (servletPath);
1558: }
1559:
1560: /**
1561: * Return the session associated with this Request, creating one
1562: * if necessary.
1563: */
1564: public HttpSession getSession() {
1565: return (getSession(true));
1566: }
1567:
1568: /**
1569: * Return the session associated with this Request, creating one
1570: * if necessary and requested.
1571: *
1572: * @param create Create a new session if one does not exist
1573: */
1574: public HttpSession getSession(boolean create) {
1575:
1576: if (System.getSecurityManager() != null) {
1577: PrivilegedGetSession dp = new PrivilegedGetSession(create);
1578: return (HttpSession) AccessController.doPrivileged(dp);
1579: }
1580: return doGetSession(create);
1581:
1582: }
1583:
1584: /**
1585: * Return <code>true</code> if the session identifier included in this
1586: * request came from a cookie.
1587: */
1588: public boolean isRequestedSessionIdFromCookie() {
1589:
1590: if (requestedSessionId != null)
1591: return (requestedSessionCookie);
1592: else
1593: return (false);
1594:
1595: }
1596:
1597: /**
1598: * Return <code>true</code> if the session identifier included in this
1599: * request came from the request URI.
1600: */
1601: public boolean isRequestedSessionIdFromURL() {
1602:
1603: if (requestedSessionId != null)
1604: return (requestedSessionURL);
1605: else
1606: return (false);
1607:
1608: }
1609:
1610: /**
1611: * Return <code>true</code> if the session identifier included in this
1612: * request came from the request URI.
1613: *
1614: * @deprecated As of Version 2.1 of the Java Servlet API, use
1615: * <code>isRequestedSessionIdFromURL()</code> instead.
1616: */
1617: public boolean isRequestedSessionIdFromUrl() {
1618: return (isRequestedSessionIdFromURL());
1619: }
1620:
1621: /**
1622: * Return <code>true</code> if the session identifier included in this
1623: * request identifies a valid session.
1624: */
1625: public boolean isRequestedSessionIdValid() {
1626:
1627: if (requestedSessionId == null)
1628: return (false);
1629: if (context == null)
1630: return (false);
1631: Manager manager = context.getManager();
1632: if (manager == null)
1633: return (false);
1634: Session session = null;
1635: try {
1636: session = manager.findSession(requestedSessionId);
1637: } catch (IOException e) {
1638: session = null;
1639: }
1640: if ((session != null) && session.isValid())
1641: return (true);
1642: else
1643: return (false);
1644:
1645: }
1646:
1647: /**
1648: * Return <code>true</code> if the authenticated user principal
1649: * possesses the specified role name.
1650: *
1651: * @param role Role name to be validated
1652: */
1653: public boolean isUserInRole(String role) {
1654:
1655: // Have we got an authenticated principal at all?
1656: if (userPrincipal == null)
1657: return (false);
1658:
1659: // Identify the Realm we will use for checking role assignmenets
1660: if (context == null)
1661: return (false);
1662: Realm realm = context.getRealm();
1663: if (realm == null)
1664: return (false);
1665:
1666: // Check for a role alias defined in a <security-role-ref> element
1667: if (wrapper != null) {
1668: String realRole = wrapper.findSecurityReference(role);
1669: if ((realRole != null)
1670: && realm.hasRole(userPrincipal, realRole))
1671: return (true);
1672: }
1673:
1674: // Check for a role defined directly as a <security-role>
1675: return (realm.hasRole(userPrincipal, role));
1676:
1677: }
1678:
1679: /**
1680: * Return the principal that has been authenticated for this Request.
1681: */
1682: public Principal getUserPrincipal() {
1683: return (userPrincipal);
1684: }
1685:
1686: // ------------------------------------------------------ Protected Methods
1687:
1688: protected HttpSession doGetSession(boolean create) {
1689:
1690: // There cannot be a session if no context has been assigned yet
1691: if (context == null)
1692: return (null);
1693:
1694: // Return the current session if it exists and is valid
1695: if ((session != null) && !session.isValid())
1696: session = null;
1697: if (session != null)
1698: return (session.getSession());
1699:
1700: // Return the requested session if it exists and is valid
1701: Manager manager = null;
1702: if (context != null)
1703: manager = context.getManager();
1704: if (manager == null)
1705: return (null); // Sessions are not supported
1706: if (requestedSessionId != null) {
1707: try {
1708: session = manager.findSession(requestedSessionId);
1709: } catch (IOException e) {
1710: session = null;
1711: }
1712: if ((session != null) && !session.isValid())
1713: session = null;
1714: if (session != null) {
1715: return (session.getSession());
1716: }
1717: }
1718:
1719: // Create a new session if requested and the response is not committed
1720: if (!create)
1721: return (null);
1722: if ((context != null) && (response != null)
1723: && context.getCookies()
1724: && response.getResponse().isCommitted()) {
1725: throw new IllegalStateException(sm
1726: .getString("coyoteRequest.sessionCreateCommitted"));
1727: }
1728:
1729: session = manager.createSession();
1730:
1731: // Creating a new session cookie based on that session
1732: if ((session != null) && (getContext() != null)
1733: && getContext().getCookies()) {
1734: Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
1735: session.getId());
1736: cookie.setMaxAge(-1);
1737: String contextPath = null;
1738: if (context != null)
1739: contextPath = context.getPath();
1740: if ((contextPath != null) && (contextPath.length() > 0))
1741: cookie.setPath(contextPath);
1742: else
1743: cookie.setPath("/");
1744: if (isSecure())
1745: cookie.setSecure(true);
1746: ((HttpServletResponse) response).addCookie(cookie);
1747: }
1748:
1749: if (session != null)
1750: return (session.getSession());
1751: else
1752: return (null);
1753:
1754: }
1755:
1756: /**
1757: * Parse request parameters.
1758: */
1759: protected void parseRequestParameters() {
1760:
1761: requestParametersParsed = true;
1762:
1763: Parameters parameters = coyoteRequest.getParameters();
1764:
1765: String enc = coyoteRequest.getCharacterEncoding();
1766: boolean useBodyEncodingForURI = connector
1767: .getUseBodyEncodingForURI();
1768: if (enc != null) {
1769: parameters.setEncoding(enc);
1770: if (useBodyEncodingForURI) {
1771: parameters.setQueryStringEncoding(enc);
1772: }
1773: } else {
1774: parameters
1775: .setEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
1776: if (useBodyEncodingForURI) {
1777: parameters
1778: .setQueryStringEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
1779: }
1780: }
1781:
1782: parameters.handleQueryParameters();
1783:
1784: if (usingInputStream || usingReader)
1785: return;
1786:
1787: if (!getMethod().equalsIgnoreCase("POST"))
1788: return;
1789:
1790: String contentType = getContentType();
1791: if (contentType == null)
1792: contentType = "";
1793: int semicolon = contentType.indexOf(';');
1794: if (semicolon >= 0) {
1795: contentType = contentType.substring(0, semicolon).trim();
1796: } else {
1797: contentType = contentType.trim();
1798: }
1799: if (!("application/x-www-form-urlencoded".equals(contentType)))
1800: return;
1801:
1802: int len = getContentLength();
1803:
1804: if (len > 0) {
1805: try {
1806: byte[] formData = null;
1807: if (len < CACHED_POST_LEN) {
1808: if (postData == null)
1809: postData = new byte[CACHED_POST_LEN];
1810: formData = postData;
1811: } else {
1812: formData = new byte[len];
1813: }
1814: int actualLen = readPostBody(formData, len);
1815: if (actualLen == len) {
1816: parameters.processParameters(formData, 0, len);
1817: }
1818: } catch (Throwable t) {
1819: ; // Ignore
1820: }
1821: }
1822:
1823: }
1824:
1825: /**
1826: * Read post body in an array.
1827: */
1828: protected int readPostBody(byte body[], int len) throws IOException {
1829:
1830: int offset = 0;
1831: do {
1832: int inputLen = getStream().read(body, offset, len - offset);
1833: if (inputLen <= 0) {
1834: return offset;
1835: }
1836: offset += inputLen;
1837: } while ((len - offset) > 0);
1838: return len;
1839:
1840: }
1841:
1842: /**
1843: * Parse request locales.
1844: */
1845: protected void parseLocales() {
1846:
1847: localesParsed = true;
1848:
1849: Enumeration values = getHeaders("accept-language");
1850:
1851: while (values.hasMoreElements()) {
1852: String value = values.nextElement().toString();
1853: parseLocalesHeader(value);
1854: }
1855:
1856: }
1857:
1858: /**
1859: * Parse accept-language header value.
1860: */
1861: protected void parseLocalesHeader(String value) {
1862:
1863: // Store the accumulated languages that have been requested in
1864: // a local collection, sorted by the quality value (so we can
1865: // add Locales in descending order). The values will be ArrayLists
1866: // containing the corresponding Locales to be added
1867: TreeMap locales = new TreeMap();
1868:
1869: // Preprocess the value to remove all whitespace
1870: int white = value.indexOf(' ');
1871: if (white < 0)
1872: white = value.indexOf('\t');
1873: if (white >= 0) {
1874: StringBuffer sb = new StringBuffer();
1875: int len = value.length();
1876: for (int i = 0; i < len; i++) {
1877: char ch = value.charAt(i);
1878: if ((ch != ' ') && (ch != '\t'))
1879: sb.append(ch);
1880: }
1881: value = sb.toString();
1882: }
1883:
1884: // Process each comma-delimited language specification
1885: parser.setString(value); // ASSERT: parser is available to us
1886: int length = parser.getLength();
1887: while (true) {
1888:
1889: // Extract the next comma-delimited entry
1890: int start = parser.getIndex();
1891: if (start >= length)
1892: break;
1893: int end = parser.findChar(',');
1894: String entry = parser.extract(start, end).trim();
1895: parser.advance(); // For the following entry
1896:
1897: // Extract the quality factor for this entry
1898: double quality = 1.0;
1899: int semi = entry.indexOf(";q=");
1900: if (semi >= 0) {
1901: try {
1902: quality = Double.parseDouble(entry
1903: .substring(semi + 3));
1904: } catch (NumberFormatException e) {
1905: quality = 0.0;
1906: }
1907: entry = entry.substring(0, semi);
1908: }
1909:
1910: // Skip entries we are not going to keep track of
1911: if (quality < 0.00005)
1912: continue; // Zero (or effectively zero) quality factors
1913: if ("*".equals(entry))
1914: continue; // FIXME - "*" entries are not handled
1915:
1916: // Extract the language and country for this entry
1917: String language = null;
1918: String country = null;
1919: String variant = null;
1920: int dash = entry.indexOf('-');
1921: if (dash < 0) {
1922: language = entry;
1923: country = "";
1924: variant = "";
1925: } else {
1926: language = entry.substring(0, dash);
1927: country = entry.substring(dash + 1);
1928: int vDash = country.indexOf('-');
1929: if (vDash > 0) {
1930: String cTemp = country.substring(0, vDash);
1931: variant = country.substring(vDash + 1);
1932: country = cTemp;
1933: } else {
1934: variant = "";
1935: }
1936: }
1937:
1938: // Add a new Locale to the list of Locales for this quality level
1939: Locale locale = new Locale(language, country, variant);
1940: Double key = new Double(-quality); // Reverse the order
1941: ArrayList values = (ArrayList) locales.get(key);
1942: if (values == null) {
1943: values = new ArrayList();
1944: locales.put(key, values);
1945: }
1946: values.add(locale);
1947:
1948: }
1949:
1950: // Process the quality values in highest->lowest order (due to
1951: // negating the Double value when creating the key)
1952: Iterator keys = locales.keySet().iterator();
1953: while (keys.hasNext()) {
1954: Double key = (Double) keys.next();
1955: ArrayList list = (ArrayList) locales.get(key);
1956: Iterator values = list.iterator();
1957: while (values.hasNext()) {
1958: Locale locale = (Locale) values.next();
1959: addLocale(locale);
1960: }
1961: }
1962:
1963: }
1964:
1965: }
|