0001: // JigsawHttpServletRequest.java
0002: // $Id: JigsawHttpServletRequest.java,v 1.72 2007/02/11 10:50:01 ylafon Exp $
0003: // (c) COPYRIGHT MIT, ERCIM and Keio, 1996-2004.
0004: // Please first read the full copyright statement in file COPYRIGHT.html
0005:
0006: package org.w3c.jigsaw.servlet;
0007:
0008: import java.io.BufferedReader;
0009: import java.io.IOException;
0010: import java.io.InputStream;
0011: import java.io.InputStreamReader;
0012: import java.io.PipedInputStream;
0013: import java.io.Reader;
0014: import java.io.StringReader;
0015: import java.io.UnsupportedEncodingException;
0016:
0017: import java.net.URL;
0018: import java.net.MalformedURLException;
0019:
0020: import java.util.Enumeration;
0021: import java.util.Hashtable;
0022: import java.util.Locale;
0023: import java.util.Map;
0024: import java.util.Vector;
0025:
0026: import java.security.Principal;
0027:
0028: import javax.servlet.RequestDispatcher;
0029: import javax.servlet.Servlet;
0030: import javax.servlet.ServletContext;
0031: import javax.servlet.ServletInputStream;
0032:
0033: import javax.servlet.http.Cookie;
0034: import javax.servlet.http.HttpServletRequest;
0035: import javax.servlet.http.HttpSession;
0036:
0037: import org.w3c.util.ArrayEnumeration;
0038: import org.w3c.util.EmptyEnumeration;
0039: import org.w3c.util.ObservableProperties;
0040:
0041: import org.w3c.jigsaw.http.Client;
0042: import org.w3c.jigsaw.http.Request;
0043: import org.w3c.jigsaw.http.httpd;
0044:
0045: import org.w3c.jigsaw.forms.URLDecoder;
0046: import org.w3c.jigsaw.forms.URLDecoderException;
0047: import org.w3c.jigsaw.resources.VirtualHostResource;
0048:
0049: import org.w3c.www.http.ContentLengthInputStream;
0050: import org.w3c.www.http.HeaderDescription;
0051: import org.w3c.www.http.HeaderValue;
0052: import org.w3c.www.http.HttpAcceptLanguage;
0053: import org.w3c.www.http.HttpCookie;
0054: import org.w3c.www.http.HttpCookieList;
0055: import org.w3c.www.http.HttpEntityMessage;
0056: import org.w3c.www.http.HttpMessage;
0057: import org.w3c.www.http.HttpRequestMessage;
0058:
0059: import org.w3c.www.mime.MimeType;
0060:
0061: import org.w3c.jigsaw.auth.AuthFilter; // for auth infos access
0062:
0063: import org.w3c.tools.resources.InvalidResourceException;
0064: import org.w3c.tools.resources.Resource;
0065: import org.w3c.tools.resources.ResourceReference;
0066:
0067: class HeaderNames implements Enumeration {
0068: // The HeaderDescription enumeration
0069: Enumeration e = null;
0070:
0071: public boolean hasMoreElements() {
0072: return e.hasMoreElements();
0073: }
0074:
0075: public Object nextElement() {
0076: HeaderDescription d = (HeaderDescription) e.nextElement();
0077: return d.getName();
0078: }
0079:
0080: HeaderNames(Enumeration e) {
0081: this .e = e;
0082: }
0083:
0084: }
0085:
0086: /**
0087: * @author Alexandre Rafalovitch <alex@access.com.au>
0088: * @author Anselm Baird-Smith <abaird@w3.org>
0089: * @author Benoit Mahe <bmahe@sophia.inria.fr>
0090: * @author Yves Lafon <ylafon@w3.org>
0091: */
0092:
0093: public class JigsawHttpServletRequest implements HttpServletRequest {
0094:
0095: // for null encoding
0096: private static final String nullEnc = "null".intern();
0097: /**
0098: * The InputStream state codes.
0099: */
0100:
0101: /**
0102: * The initial state of the request InputStream
0103: */
0104: private final static int STREAM_STATE_INITIAL = 0;
0105:
0106: /**
0107: * One reader has been created and is probably used.
0108: */
0109: private final static int STREAM_READER_USED = 1;
0110:
0111: /**
0112: * The input stream is used
0113: */
0114: private final static int INPUT_STREAM_USED = 2;
0115:
0116: /**
0117: * The inputstream state
0118: */
0119: private int stream_state = STREAM_STATE_INITIAL;
0120:
0121: public final static String STATE_PARAMETERS = "org.w3c.jigsaw.servlet.stateParam";
0122:
0123: private static MimeType type = MimeType.APPLICATION_X_WWW_FORM_URLENCODED;
0124: /**
0125: * The initial request.
0126: */
0127: private Request request = null;
0128: /**
0129: * The attached servlet.
0130: */
0131: private Servlet servlet = null;
0132: /**
0133: * The attached servlet context.
0134: */
0135: private JigsawServletContext servletContext = null;
0136: /**
0137: * The lazyly computed queryParameters hashtable.
0138: */
0139: private Hashtable queryParameters = null;
0140: protected JigsawHttpServletResponse response = null;
0141:
0142: protected JigsawHttpSession httpSession = null;
0143:
0144: protected JigsawHttpSessionContext sessionContext = null;
0145:
0146: protected String requestedSessionID = null;
0147:
0148: protected String encoding = null;
0149:
0150: private Hashtable convertParameters(Hashtable source) {
0151: if (source != null) {
0152: Enumeration e = source.keys();
0153: while (e.hasMoreElements()) {
0154: Object name = e.nextElement();
0155: Object value = source.get(name);
0156: if (value instanceof String) {
0157: String _newval[] = new String[1];
0158: _newval[0] = (String) value;
0159: source.put(name, _newval);
0160: }
0161: }
0162: return source;
0163: }
0164: return null;
0165: }
0166:
0167: private Hashtable mergeParameters(Hashtable source, Hashtable dest) {
0168: if (source == null)
0169: return dest;
0170: if (dest != null) {
0171: Enumeration e = source.keys();
0172: while (e.hasMoreElements()) {
0173: String name = (String) e.nextElement();
0174: Object value = dest.get(name);
0175: if (value == null)
0176: dest.put(name, source.get(name));
0177: else if (value instanceof String[]) {
0178: String oldValues[] = (String[]) value;
0179: String newValues[] = new String[oldValues.length + 1];
0180: System.arraycopy(oldValues, 0, newValues, 0,
0181: oldValues.length);
0182: newValues[oldValues.length] = (String) source
0183: .get(name);
0184: dest.put(name, newValues);
0185: } else {
0186: String newValues[] = new String[2];
0187: newValues[0] = (String) source.get(name);
0188: newValues[1] = (String) value;
0189: dest.put(name, newValues);
0190: }
0191: }
0192: return dest;
0193: } else {
0194: return source;
0195: }
0196: }
0197:
0198: private synchronized void prepareQueryParameters() {
0199: if (queryParameters != null)
0200: return;
0201: Hashtable postParameters = null;
0202: // What kinf of parameters are we expecting ?
0203: if (request.getMethod().equals("POST")) {
0204: // POSTed parameters, check content type:
0205: if ((!request.hasContentType())
0206: || (type.match(request.getContentType()) < 0))
0207: return;
0208: postParameters = new Hashtable(2);
0209: // Get and decode the request entity:
0210: URLDecoder dec = null;
0211: try {
0212: Reader in = getReader();
0213: // Notify the client that we are willing to continue
0214: String exp = request.getExpect();
0215: if (exp != null
0216: && (exp.equalsIgnoreCase("100-continue"))) {
0217: Client client = request.getClient();
0218: if (client != null) {
0219: client.sendContinue();
0220: }
0221: }
0222: String encoding = getCharacterEncoding();
0223: if (encoding == null) {
0224: dec = new URLDecoder(in, false, "8859_1");
0225: } else {
0226: dec = new URLDecoder(in, false,
0227: getCharacterEncoding());
0228: }
0229: postParameters = dec.parse();
0230: } catch (URLDecoderException e) {
0231: postParameters = null;
0232: } catch (IOException ex) {
0233: postParameters = null;
0234: }
0235: }
0236: // URL encoded parameters:
0237: String query = getQueryString();
0238: if (query != null) {
0239: Reader qis = null;
0240: qis = new StringReader(query);
0241: try {
0242: URLDecoder dec;
0243: String encoding = getCharacterEncoding();
0244: if (encoding == null) {
0245: dec = new URLDecoder(qis, false, "8859_1");
0246: } else {
0247: dec = new URLDecoder(qis, false,
0248: getCharacterEncoding());
0249: }
0250: queryParameters = dec.parse();
0251: } catch (Exception ex) {
0252: throw new RuntimeException("Java implementation bug.");
0253: }
0254: }
0255: queryParameters = mergeParameters(postParameters,
0256: queryParameters);
0257: // state parameters
0258: Hashtable param = (Hashtable) request
0259: .getState(STATE_PARAMETERS);
0260: queryParameters = mergeParameters(param, queryParameters);
0261: convertParameters(queryParameters);
0262: }
0263:
0264: protected String getURLParameter(String name) {
0265: Hashtable urlParameters = null;
0266: String query = getQueryString();
0267: if (query != null) {
0268: Reader qis = new StringReader(query);
0269: try {
0270: String encoding = getCharacterEncoding();
0271: if (encoding == null) {
0272: urlParameters = new URLDecoder(qis, false, "8859_1")
0273: .parse();
0274: } else {
0275: urlParameters = new URLDecoder(qis, false, encoding)
0276: .parse();
0277: }
0278: return (String) urlParameters.get(name);
0279: } catch (Exception ex) {
0280: throw new RuntimeException("Java implementation bug.");
0281: }
0282: }
0283: return null;
0284: }
0285:
0286: /**
0287: * Return the Charset parameter of content type
0288: * @return A String instance
0289: */
0290: public String getCharacterEncoding() {
0291: if (encoding == null) {
0292: org.w3c.www.mime.MimeType type = request.getContentType();
0293: if ((type != null) && (type.hasParameter("charset"))) {
0294: encoding = type.getParameterValue("charset");
0295: } else {
0296: encoding = nullEnc;
0297: }
0298: }
0299: if (encoding == nullEnc) {
0300: return null;
0301: }
0302: return encoding;
0303: }
0304:
0305: /**
0306: * Overrides the name of the character encoding used in the body of this
0307: * request
0308: * ServletRequest implementation - version 2.3
0309: * @param enc, a <code>String</code> specifying the encoding String
0310: */
0311: public void setCharacterEncoding(String enc)
0312: throws java.io.UnsupportedEncodingException {
0313: // a hack to see if the character encoding is supported
0314: InputStreamReader isr = new InputStreamReader(
0315: new PipedInputStream(), enc);
0316: encoding = enc;
0317: }
0318:
0319: /**
0320: * ServletRequest implementation - Get the length of request data.
0321: * @return An int, or <strong>-1</strong>.
0322: */
0323:
0324: public int getContentLength() {
0325: return request.getContentLength();
0326: }
0327:
0328: /**
0329: * ServletRequest implementation - Get the type of the request's body.
0330: * @return A String encoded mime type, or <strong>null</strong>.
0331: */
0332:
0333: public String getContentType() {
0334: org.w3c.www.mime.MimeType t = request.getContentType();
0335: return (t == null) ? null : t.toString();
0336: }
0337:
0338: /**
0339: * ServletRequest implementation - Get the protocol of that request.
0340: * @return A String encoded version of the protocol.
0341: */
0342:
0343: public String getProtocol() {
0344: return request.getVersion();
0345: }
0346:
0347: protected httpd getServer() {
0348: return request.getClient().getServer();
0349: }
0350:
0351: /**
0352: * ServletRequest implementation - Get the name of queried server.
0353: * @return Name of server, as a String.
0354: */
0355:
0356: public String getServerName() {
0357: String host = request.getHost();
0358: if (host != null) {
0359: int idx = host.lastIndexOf(':');
0360: if (idx != -1) {
0361: return host.substring(0, host.lastIndexOf(':'));
0362: } else {
0363: return host;
0364: }
0365: } else {
0366: return getServer().getHost();
0367: }
0368: }
0369:
0370: /**
0371: * ServletRequest implementation - Get the port of queried server.
0372: * @return A port number (int).
0373: */
0374:
0375: public int getServerPort() {
0376: if (request.isProxy()) {
0377: String host = request.getHost();
0378: if (host != null) {
0379: int idx = host.lastIndexOf(':');
0380: if (idx == -1)
0381: return 80;
0382: return Integer.parseInt(host.substring(idx + 1));
0383: }
0384: }
0385: return getServer().getLocalPort();
0386: }
0387:
0388: /**
0389: * ServletRequest implementation - Get the IP address of requests's sender.
0390: * @return Numeric IP address, as a String.
0391: */
0392:
0393: public String getRemoteAddr() {
0394: return request.getClient().getInetAddress().getHostAddress();
0395: }
0396:
0397: /**
0398: * ServletRequest implementation - FQDN of request's sender.
0399: * @return Name of client's machine (FQDN).
0400: */
0401:
0402: public String getRemoteHost() {
0403: return request.getClient().getInetAddress().getHostName();
0404: }
0405:
0406: /**
0407: * ServletRequest implementation - Get real path.
0408: * Jigsaw realy has no notion of <em>translation</em> stricto
0409: * sensu (it has much better in fact ;-). This is a pain here.
0410: * @return the real path.
0411: * @deprecated since jsdk1.2
0412: */
0413:
0414: public String getRealPath(String name) {
0415: httpd server = getServer();
0416: ResourceReference rr_root = server.getRootReference();
0417: return JigsawServletContext.getRealPath(name, rr_root, request
0418: .getTargetResource());
0419: }
0420:
0421: protected ServletInputStream is = null;
0422:
0423: /**
0424: * Returns an input stream for reading binary data in the request body.
0425: * @exception IllegalStateException if getReader has been called on
0426: * this same request.
0427: * @exception IOException on other I/O related errors.
0428: * @see JigsawHttpServletRequest#getReader
0429: */
0430: public ServletInputStream getInputStream() throws IOException {
0431: if (stream_state == STREAM_READER_USED)
0432: throw new IllegalStateException("Reader used");
0433: stream_state = INPUT_STREAM_USED;
0434: return getJigsawInputStream();
0435: }
0436:
0437: /**
0438: * @exception IOException if an IO error occurs
0439: */
0440: protected ServletInputStream getJigsawInputStream()
0441: throws IOException {
0442: // If alredy computed return:
0443: if (is != null)
0444: return is;
0445: // Built it:
0446: InputStream stream = null;
0447: if ((stream = request.getInputStream()) == null) {
0448: stream = new ContentLengthInputStream(null, 0);
0449: }
0450: return is = new JigsawServletInputStream(stream);
0451: }
0452:
0453: /**
0454: * ServletRequest implementation - Get a parameter value.
0455: * @return The String encoded value for the parameter.
0456: */
0457:
0458: public String getParameter(String name) {
0459: prepareQueryParameters();
0460: if (queryParameters != null) {
0461: Object value = queryParameters.get(name);
0462: if (value != null) {
0463: return ((String[]) value)[0];
0464: }
0465: }
0466: return null;
0467: }
0468:
0469: /**
0470: * ServletRequest implementation - Get a parameter value. (v2.3)
0471: * @return a Map of the parameters in this request
0472: */
0473: public Map getParameterMap() {
0474: prepareQueryParameters();
0475: return queryParameters;
0476: }
0477:
0478: /**
0479: * ServletRequest implementation - Get the parameters value.
0480: * @return The String array encoded value for the parameter.
0481: */
0482:
0483: public String[] getParameterValues(String parameter) {
0484: Vector V = new Vector(23);
0485: prepareQueryParameters();
0486: if (queryParameters == null) {
0487: return null;
0488: }
0489: Object value = queryParameters.get(parameter);
0490: if (value == null) {
0491: return null;
0492: }
0493: return (String[]) value;
0494: }
0495:
0496: /**
0497: * ServletRequest implementation - List available parameters.
0498: * @return An enumeration of parameter names.
0499: */
0500:
0501: public Enumeration getParameterNames() {
0502: prepareQueryParameters();
0503: return ((queryParameters == null) ? new EmptyEnumeration()
0504: : queryParameters.keys());
0505: }
0506:
0507: /**
0508: * ServletRequest implementation - Get an attribute of the request.
0509: * This closely match Jigsaw's notion of request state.
0510: * @param name The name of the attribute.
0511: * @return An object that gives the value of the attribute.
0512: */
0513:
0514: public Object getAttribute(String name) {
0515: return request.getState(name);
0516: }
0517:
0518: public void setAttribute(String name, Object object) {
0519: request.setState(name, object);
0520: }
0521:
0522: /**
0523: * Removes an attribute from this request. This method is not
0524: * generally needed as attributes only persist as long as the request
0525: * is being handled.
0526: *
0527: * <p>Attribute names should follow the same conventions as
0528: * package names. Names beginning with <code>java.*</code>,
0529: * <code>javax.*</code>, and <code>com.sun.*</code>, are
0530: * reserved for use by Sun Microsystems.
0531: *
0532: * @param name a <code>String</code> specifying
0533: * the name of the attribute to remove
0534: */
0535: public void removeAttribute(String name) {
0536: request.delState(name);
0537: }
0538:
0539: public Enumeration getAttributeNames() {
0540: return request.getStateNames();
0541: }
0542:
0543: /**
0544: * Returns the preferred <code>Locale</code> that the client will
0545: * accept content in, based on the Accept-Language header.
0546: * If the client request doesn't provide an Accept-Language header,
0547: * this method returns the default locale for the server.
0548: *
0549: * @return the preferred <code>Locale</code> for the client
0550: */
0551: public Locale getLocale() {
0552: return (Locale) getLocales().nextElement();
0553: }
0554:
0555: /**
0556: * Returns an <code>Enumeration</code> of <code>Locale</code> objects
0557: * indicating, in decreasing order starting with the preferred locale, the
0558: * locales that are acceptable to the client based on the Accept-Language
0559: * header.
0560: * If the client request doesn't provide an Accept-Language header,
0561: * this method returns an <code>Enumeration</code> containing one
0562: * <code>Locale</code>, the default locale for the server.
0563: *
0564: * @return an <code>Enumeration</code> of preferred
0565: * <code>Locale</code> objects for the client
0566: */
0567: public Enumeration getLocales() {
0568: HttpAcceptLanguage languages[] = request.getAcceptLanguage();
0569: if (languages == null) {
0570: Vector def = new Vector();
0571: def.addElement(Locale.getDefault());
0572: return def.elements();
0573: }
0574:
0575: //LinkedList is better, but we must be JDK1.1 compliant
0576: Vector locales = new Vector();
0577:
0578: for (int i = 0; i < languages.length; i++) {
0579: HttpAcceptLanguage language = languages[i];
0580: double quality = language.getQuality();
0581: String lang = language.getLanguage();
0582: String country = "";
0583: int idx = lang.indexOf('-');
0584: if (idx > -1) {
0585: country = lang.substring(idx + 1).trim();
0586: lang = lang.substring(0, idx).trim();
0587: }
0588: // insert the Locale in ordered list
0589: int qidx = 0;
0590: int size = locales.size();
0591: if (size > 0) {
0592: QLocale ql = (QLocale) locales.firstElement();
0593: while ((qidx < size)
0594: && (ql.getLanguageQuality() >= quality)) {
0595: try {
0596: ql = (QLocale) locales.elementAt(++qidx);
0597: } catch (ArrayIndexOutOfBoundsException ex) {
0598: //end of vector, so append
0599: }
0600: }
0601: locales.insertElementAt(new QLocale(lang, country,
0602: quality), qidx);
0603: } else {
0604: locales.addElement(new QLocale(lang, country, quality));
0605: }
0606: }
0607: // because Locale is final :(
0608: int size = locales.size();
0609: Vector vlocale = new Vector(size);
0610: for (int i = 0; i < size; i++) {
0611: vlocale.addElement(((QLocale) locales.elementAt(i))
0612: .getLocale());
0613: }
0614: return vlocale.elements();
0615: }
0616:
0617: /**
0618: * Returns a boolean indicating whether this request was made using a
0619: * secure channel, such as HTTPS.
0620: *
0621: * @return a boolean indicating if the request was made using a
0622: * secure channel
0623: */
0624:
0625: public boolean isSecure() {
0626: // only https secure?
0627: return (request.getURL().getProtocol()
0628: .equalsIgnoreCase("https"));
0629: }
0630:
0631: /**
0632: * HttpServletRequest implementation - Get the request's method.
0633: * @return A String instance.
0634: */
0635:
0636: public String getMethod() {
0637: return request.getMethod();
0638: }
0639:
0640: /**
0641: * HttpServletRequest implementation - Get the request's path info.
0642: * @return A String instance or <strong>null</strong>.
0643: */
0644:
0645: public String getPathInfo() {
0646: if (request.hasState(JigsawRequestDispatcher.PATH_INFO_P)) {
0647: String pathinfo = (String) request
0648: .getState(JigsawRequestDispatcher.PATH_INFO_P);
0649: return (pathinfo.equals("/")) ? null : pathinfo;
0650: }
0651: return null;
0652: }
0653:
0654: /**
0655: * HttpServletRequest implementation - Get the request's path translated.
0656: * @return A String instance or <strong>null</strong>.
0657: */
0658:
0659: public String getPathTranslated() {
0660: String pathinfo = getPathInfo();
0661: if (pathinfo != null)
0662: return getRealPath(pathinfo);
0663: return null;
0664: }
0665:
0666: /**
0667: * Returns the portion of the request URI that indicates the context
0668: * of the request. The context path always comes first in a request
0669: * URI. The path starts with a "/" character but does not end with a "/"
0670: * character. For servlets in the default (root) context, this method
0671: * returns "".
0672: * @return a <code>String</code> specifying the portion of the request
0673: * URI that indicates the context of the request
0674: */
0675: public String getContextPath() {
0676: return "";
0677: }
0678:
0679: public boolean hasQueryString() {
0680: if (request.hasQueryString()) {
0681: return true;
0682: } else {
0683: return request
0684: .hasState(JigsawRequestDispatcher.QUERY_STRING_P);
0685: }
0686: }
0687:
0688: /**
0689: * HttpServletRequest implementation - Get the request's query string.
0690: * @return A String instance or <strong>null</strong>.
0691: */
0692: public String getQueryString() {
0693: if (request.hasQueryString()) {
0694: return request.getQueryString();
0695: } else if (request
0696: .hasState(JigsawRequestDispatcher.QUERY_STRING_P)) {
0697: return (String) request
0698: .getState(JigsawRequestDispatcher.QUERY_STRING_P);
0699: }
0700: return null;
0701: }
0702:
0703: /**
0704: * HttpServletRequest implementation - Get the request's user (if any).
0705: * @return A String instance or <strong>null</strong>.
0706: */
0707:
0708: public String getRemoteUser() {
0709: return (String) request.getState(AuthFilter.STATE_AUTHUSER);
0710: }
0711:
0712: /**
0713: * Returns a boolean indicating whether the authenticated user is included
0714: * in the specified logical "role". Roles and role membership can be
0715: * defined using deployment descriptors. If the user has not been
0716: * authenticated, the method returns <code>false</code>.
0717: *
0718: * @param role a <code>String</code> specifying the name of the role
0719: * @return a <code>boolean</code> indicating whether the user making this
0720: * request belongs to a given role; <code>false</code> if the user has not
0721: * been authenticated
0722: */
0723:
0724: public boolean isUserInRole(String role) {
0725: throw new RuntimeException("Not Yet Implemented");
0726: }
0727:
0728: /**
0729: * Returns a <code>java.security.Principal</code> object containing
0730: * the name of the current authenticated user. If the user has not been
0731: * authenticated, the method returns <code>null</code>.
0732: *
0733: * @return a <code>java.security.Principal</code> containing
0734: * the name of the user making this request; <code>null</code> if the
0735: * user has not been authenticated
0736: */
0737: public Principal getUserPrincipal() {
0738: return new PrincipalImpl(getRemoteUser());
0739: }
0740:
0741: /**
0742: * HttpServletRequest implementation - Get the request's auth method.
0743: * @return A String instance or <strong>null</strong>.
0744: */
0745:
0746: public String getAuthType() {
0747: return (String) request.getState(AuthFilter.STATE_AUTHTYPE);
0748: }
0749:
0750: /**
0751: * HttpServletRequest implementation - Get a request header as a String.
0752: * @return A String instance or <strong>null</strong>.
0753: */
0754:
0755: public String getHeader(String name) {
0756: return request.getValue(name);
0757: }
0758:
0759: /**
0760: * Returns all the values of the specified request header
0761: * as an <code>Enumeration</code> of <code>String</code> objects.
0762: *
0763: * <p>Some headers, such as <code>Accept-Language</code> can be sent
0764: * by clients as several headers each with a different value rather than
0765: * sending the header as a comma separated list.
0766: *
0767: * <p>WARNING, this can't happen with Jigsaw, all multiple values are
0768: * grouped in one, and only one, header. So, this method always return
0769: * ONE header value.
0770: *
0771: * <p>If the request did not include any headers
0772: * of the specified name, this method returns an empty
0773: * <code>Enumeration</code>.
0774: * The header name is case insensitive. You can use
0775: * this method with any request header.
0776: *
0777: * @param name a <code>String</code> specifying the header name
0778: * @return a <code>Enumeration</code> containing the values of the
0779: * requested header, or <code>null</code> if the request does not
0780: * have any headers of that name
0781: */
0782:
0783: public Enumeration getHeaders(String name) {
0784: String value = getHeader(name);
0785: String array[] = { value };
0786: return new ArrayEnumeration(array);
0787: }
0788:
0789: /**
0790: * HttpServletRequest implementation - Get a request header as an int.
0791: * @return An int, or <strong>-1</strong>.
0792: */
0793:
0794: public int getIntHeader(String name) {
0795: HeaderValue v = request.getHeaderValue(name);
0796: if (v != null) {
0797: Object o = v.getValue();
0798: if ((o != null) && (o instanceof Integer))
0799: return ((Integer) o).intValue();
0800: }
0801: return -1;
0802: }
0803:
0804: /**
0805: * HttpServletRequest implementation - Get a request header as an date.
0806: * @return An long (as a number of milliseconds), or <strong>-1</strong>.
0807: */
0808:
0809: public long getDateHeader(String name) {
0810: HeaderValue v = request.getHeaderValue(name, null);
0811: if (v != null) {
0812: Object o = v.getValue();
0813: if ((o != null) && (o instanceof Long))
0814: return ((Long) o).longValue();
0815: }
0816: return (long) -1;
0817: }
0818:
0819: /**
0820: * HttpServletRequest implementation - Get a all header names.
0821: * @return An enumeration.
0822: */
0823:
0824: public Enumeration getHeaderNames() {
0825: return new HeaderNames(request.enumerateHeaderDescriptions());
0826: }
0827:
0828: /**
0829: * Gets, from the first line of the HTTP request,
0830: * the part of this request's URI that is to the left of any query string.
0831: */
0832: public String getRequestURI() {
0833: String uri = null;
0834: if (request.hasState(JigsawRequestDispatcher.REQUEST_URI_P)) {
0835: uri = (String) request
0836: .getState(JigsawRequestDispatcher.REQUEST_URI_P);
0837: try {
0838: URL u = new URL(request.getURL(), uri);
0839: uri = u.getFile();
0840: } catch (MalformedURLException muex) {
0841: }
0842: } else {
0843: //fixme test
0844: if (request.isProxy()) {
0845: uri = request.getURL().toExternalForm();
0846: } else {
0847: uri = request.getURLPath();
0848: }
0849: if (hasQueryString()) {
0850: String query = getQueryString();
0851: int idx = uri.lastIndexOf(query);
0852: uri = uri.substring(0, idx - 1);
0853: }
0854: }
0855: return uri;
0856: }
0857:
0858: /**
0859: * Gets, from the first line of the HTTP request,
0860: * the part of this request's URI that is to the left of any query string.
0861: */
0862: public StringBuffer getRequestURL() {
0863: String uri = null;
0864: if (request.hasState(JigsawRequestDispatcher.REQUEST_URI_P)) {
0865: uri = (String) request
0866: .getState(JigsawRequestDispatcher.REQUEST_URI_P);
0867: try {
0868: URL u = new URL(request.getURL(), uri);
0869: uri = u.toExternalForm();
0870: } catch (MalformedURLException muex) {
0871: }
0872: } else {
0873: uri = request.getURL().toExternalForm();
0874: if (hasQueryString()) {
0875: String query = getQueryString();
0876: int idx = uri.lastIndexOf(query);
0877: uri = uri.substring(0, idx - 1);
0878: }
0879: }
0880: return new StringBuffer(uri);
0881: }
0882:
0883: /**
0884: * Returns a {@link RequestDispatcher} object that acts as a wrapper for
0885: * the resource located at the given path.
0886: * A <code>RequestDispatcher</code> object can be used to forward
0887: * a request to the resource or to include the resource in a response.
0888: * The resource can be dynamic or static.
0889: *
0890: * <p>The pathname specified may be relative, although it cannot extend
0891: * outside the current servlet context. If the path begins with
0892: * a "/" it is interpreted as relative to the current context root.
0893: * This method returns <code>null</code> if the servlet container
0894: * cannot return a <code>RequestDispatcher</code>.
0895: *
0896: * <p>The difference between this method and {@link
0897: * ServletContext#getRequestDispatcher} is that this method can take a
0898: * relative path.
0899: *
0900: * @param path a <code>String</code> specifying the pathname
0901: * to the resource
0902: * @return a <code>RequestDispatcher</code> object that acts as a
0903: * wrapper for the resource at the specified path
0904: * @see RequestDispatcher
0905: * @see ServletContext#getRequestDispatcher
0906: */
0907: public RequestDispatcher getRequestDispatcher(String path) {
0908: if (path == null) {
0909: throw new IllegalArgumentException("null");
0910: }
0911: String urlpath = null;
0912: ResourceReference rr = request.getTargetResource();
0913: if (!path.startsWith("/")) {
0914: String uri = null;
0915: try {
0916: ResourceReference rrp = rr.lock().getParent();
0917: try {
0918: Resource r = rrp.lock();
0919: uri = r.getURLPath();
0920: } catch (InvalidResourceException irex) {
0921: return null;
0922: } finally {
0923: rrp.unlock();
0924: }
0925: } catch (InvalidResourceException ex) {
0926: return null;
0927: } finally {
0928: rr.unlock();
0929: }
0930: urlpath = (uri.endsWith("/") ? uri + path : uri + "/"
0931: + path);
0932: } else {
0933: urlpath = path;
0934: }
0935: return JigsawRequestDispatcher.getRequestDispatcher(urlpath,
0936: getServer(), rr);
0937: }
0938:
0939: /**
0940: * Gets the part of this request's URI that refers to the servlet
0941: * being invoked. Analogous to the CGI variable SCRIPT_NAME.
0942: */
0943: public String getServletPath() {
0944: if (request.hasState(JigsawRequestDispatcher.SERVLET_PATH_P)) {
0945: return (String) request
0946: .getState(JigsawRequestDispatcher.SERVLET_PATH_P);
0947: } else {
0948: ResourceReference rr = request.getTargetResource();
0949: try {
0950: return rr.lock().getURLPath();
0951: } catch (InvalidResourceException ex) {
0952: return null;
0953: } finally {
0954: rr.unlock();
0955: }
0956: }
0957: }
0958:
0959: /**
0960: * @return the scheme of the URL used in this request, for example "http",
0961: * "https", or "ftp". Different schemes have different rules
0962: * for constructing URLs, as noted in RFC 1738. The URL used to create
0963: * a request may be reconstructed using this scheme, the server name
0964: * and port, and additional information such as URIs.
0965: */
0966: public String getScheme() {
0967: return request.getURL().getProtocol();
0968: }
0969:
0970: /**
0971: * Gets the array of cookies found in this request.
0972: * @return the array of cookies found in this request or
0973: * <strong>null</strong> if there is no cookie.
0974: */
0975: public Cookie[] getCookies() {
0976: HttpCookieList cookielist = request.getCookie();
0977: Cookie[] Scookies = null;
0978: if (cookielist != null) {
0979: HttpCookie[] cookies = cookielist.getCookies();
0980: Scookies = new Cookie[cookies.length];
0981: for (int i = 0; i < cookies.length; i++) {
0982: Scookies[i] = convertCookie(cookies[i]);
0983: }
0984: }
0985: return Scookies;
0986: }
0987:
0988: protected Cookie convertCookie(HttpCookie httpCookie) {
0989: Cookie cookie = new Cookie(httpCookie.getName(), httpCookie
0990: .getValue());
0991: String val = null;
0992: if ((val = httpCookie.getDomain()) != null)
0993: cookie.setDomain(val);
0994: if ((val = httpCookie.getPath()) != null)
0995: cookie.setPath(val);
0996: cookie.setVersion(httpCookie.getVersion());
0997: return cookie;
0998: }
0999:
1000: protected String getRequestedSessionIdFromCookie() {
1001: HttpCookieList cookielist = request.getCookie();
1002: if (cookielist != null) {
1003: HttpCookie httpCookie = request.getCookie().getCookie(
1004: getCookieName());
1005: if (httpCookie != null)
1006: return httpCookie.getValue();
1007: }
1008: return null;
1009: }
1010:
1011: protected String getRequestedSessionIdFromURL() {
1012: return getURLParameter(getCookieName());
1013: }
1014:
1015: /**
1016: * Gets the session id specified with this request. This may differ
1017: * from the actual session id. For example, if the request specified an
1018: * id for an invalid session, then this will get a new session with a
1019: * new id.
1020: * @return the session id specified by this request, or null if the
1021: * request did not specify a session id.
1022: */
1023: public String getRequestedSessionId() {
1024: if (requestedSessionID == null) {
1025: requestedSessionID = getRequestedSessionIdFromCookie();
1026: if (requestedSessionID == null)
1027: requestedSessionID = getRequestedSessionIdFromURL();
1028: }
1029: return requestedSessionID;
1030: }
1031:
1032: protected synchronized JigsawHttpSessionContext getSessionContext() {
1033: return sessionContext;
1034: }
1035:
1036: /**
1037: * Gets the current valid session associated with this request, if create
1038: * is false or, if necessary, creates a new session for the request, if
1039: * create is true.
1040: * @return the session associated with this request or null if create
1041: * was false and no valid session is associated with this request.
1042: */
1043: public HttpSession getSession(boolean create) {
1044: if (httpSession == null) {
1045: httpSession = (JigsawHttpSession) getSession(getRequestedSessionId());
1046: if (httpSession != null) // the client join the session
1047: httpSession.setNoMoreNew();
1048: }
1049: if (httpSession == null & create) {
1050: httpSession = new JigsawHttpSession(getSessionContext(),
1051: servletContext, createCookie());
1052: response.addCookie(httpSession.getCookie());
1053: } else if (httpSession != null) {
1054: httpSession.setLastAccessedTime();
1055: if (!httpSession.isValid()) {
1056: httpSession = new JigsawHttpSession(
1057: getSessionContext(), servletContext,
1058: createCookie());
1059: response.addCookie(httpSession.getCookie());
1060: }
1061: }
1062: return httpSession;
1063: }
1064:
1065: /**
1066: * Gets the current valid session associated with this request.
1067: * @return the session associated with this request.
1068: */
1069: public HttpSession getSession() {
1070: return getSession(true);
1071: }
1072:
1073: protected String getCookieName() {
1074: ObservableProperties props = request.getClient().getServer()
1075: .getProperties();
1076: return props.getString(ServletProps.SERVLET_COOKIE_NAME,
1077: ServletProps.DEFAULT_COOKIE_NAME);
1078: }
1079:
1080: protected Cookie createCookie() {
1081: ObservableProperties props = request.getClient().getServer()
1082: .getProperties();
1083: String name = props.getString(ServletProps.SERVLET_COOKIE_NAME,
1084: ServletProps.DEFAULT_COOKIE_NAME);
1085: String path = props.getString(ServletProps.SERVLET_COOKIE_PATH,
1086: "/");
1087: String domain = props.getString(
1088: ServletProps.SERVLET_COOKIE_DOMAIN, null);
1089: String comment = props.getString(
1090: ServletProps.SERVLET_COOKIE_COMMENT, null);
1091: int maxage = props.getInteger(
1092: ServletProps.SERVLET_COOKIE_MAXAGE, -1);
1093: boolean secure = props.getBoolean(
1094: ServletProps.SERVLET_COOKIE_SECURE, isSecure());
1095:
1096: Cookie cookie = new Cookie(name, null);
1097: cookie.setPath(path);
1098: cookie.setMaxAge(maxage);
1099: if ((comment != null) && (comment.length() > 0))
1100: cookie.setComment(comment);
1101: if ((domain != null) && (domain.length() > 0))
1102: cookie.setDomain(domain);
1103: cookie.setSecure(secure);
1104: return cookie;
1105: }
1106:
1107: protected HttpSession getSession(String sessionId) {
1108: if (sessionId != null)
1109: return getSessionContext().getSession(sessionId);
1110: return null;
1111: }
1112:
1113: /**
1114: * Checks whether this request is associated with a session that is valid
1115: * in the current session context. If it is not valid, the requested
1116: * session will never be returned from the getSession method.
1117: * @return true if this request is assocated with a session that is valid
1118: * in the current session context.
1119: */
1120: public boolean isRequestedSessionIdValid() {
1121: JigsawHttpSession session = (JigsawHttpSession) getSession(getRequestedSessionId());
1122: if (session == null)
1123: return false;
1124: return (session.isValid());
1125: }
1126:
1127: /**
1128: * Checks whether the session id specified by this request came in as
1129: * a cookie. (The requested session may not be one returned by the
1130: * getSession method.)
1131: * @return true if the session id specified by this request came
1132: * in as a cookie; false otherwise
1133: */
1134: public boolean isRequestedSessionIdFromCookie() {
1135: return (getRequestedSessionIdFromCookie() != null);
1136: }
1137:
1138: /**
1139: * Checks whether the session id specified by this request came in as
1140: * part of the URL. (The requested session may not be the one returned
1141: * by the getSession method.)
1142: * @return true if the session id specified by the request for this
1143: * session came in as part of the URL; false otherwise
1144: * @deprecated since jsdk2.1
1145: */
1146: public boolean isRequestedSessionIdFromUrl() {
1147: return (getRequestedSessionIdFromURL() != null);
1148: }
1149:
1150: /**
1151: * Checks whether the session id specified by this request came in as
1152: * part of the URL. (The requested session may not be the one returned
1153: * by the getSession method.)
1154: * @return true if the session id specified by the request for this
1155: * session came in as part of the URL; false otherwise
1156: */
1157: public boolean isRequestedSessionIdFromURL() {
1158: return (getRequestedSessionIdFromURL() != null);
1159: }
1160:
1161: protected BufferedReader reader = null;
1162:
1163: /**
1164: * Returns a buffered reader for reading text in the request body.
1165: * This translates character set encodings as appropriate.
1166: * @exception UnsupportedEncodingException if the character set encoding
1167: * is unsupported, so the text can't be correctly decoded.
1168: * @exception IllegalStateException if getInputStream has been called on
1169: * this same request.
1170: * @exception IOException on other I/O related errors.
1171: * @see JigsawHttpServletRequest#getInputStream
1172: */
1173: public BufferedReader getReader() throws IOException {
1174: if (stream_state == INPUT_STREAM_USED)
1175: throw new IllegalStateException("Input Stream used");
1176: stream_state = STREAM_READER_USED;
1177: if (reader == null) {
1178: InputStream is = getJigsawInputStream();
1179: String enc = getCharacterEncoding();
1180: if (enc != null) {
1181: InputStreamReader isr = null;
1182: try {
1183: isr = new InputStreamReader(is, enc);
1184: } catch (UnsupportedEncodingException ex) {
1185: // not a valid encoding, skip it
1186: isr = null;
1187: }
1188: if (isr != null)
1189: reader = new BufferedReader(isr);
1190: else
1191: reader = new BufferedReader(new InputStreamReader(
1192: is));
1193: } else {
1194: reader = new BufferedReader(new InputStreamReader(is));
1195: }
1196: }
1197: return reader;
1198: }
1199:
1200: /**
1201: * Get the wrapped Jigsaw Request.
1202: * @return the request
1203: */
1204: protected Request getRequest() {
1205: return request;
1206: }
1207:
1208: JigsawHttpServletRequest(Servlet servlet,
1209: JigsawServletContext servletContext, Request request,
1210: JigsawHttpServletResponse response,
1211: JigsawHttpSessionContext sessionContext) {
1212: this.servlet = servlet;
1213: this.servletContext = servletContext;
1214: this.request = request;
1215: this.response = response;
1216: this.sessionContext = sessionContext;
1217: }
1218:
1219: }
|