0001: /*
0002: License $Id: JoServletRequest.java,v 1.22 2005/03/15 20:08:14 hendriks73 Exp $
0003:
0004: Copyright (c) 2001-2005 tagtraum industries.
0005:
0006: LGPL
0007: ====
0008:
0009: jo! is free software; you can redistribute it and/or
0010: modify it under the terms of the GNU Lesser General Public
0011: License as published by the Free Software Foundation; either
0012: version 2.1 of the License, or (at your option) any later version.
0013:
0014: jo! is distributed in the hope that it will be useful,
0015: but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017: Lesser General Public License for more details.
0018:
0019: You should have received a copy of the GNU Lesser General Public
0020: License along with this library; if not, write to the Free Software
0021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0022:
0023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
0024:
0025:
0026: Sun license
0027: ===========
0028:
0029: This release contains software by Sun Microsystems. Therefore
0030: the following conditions have to be met, too. They apply to the
0031: files
0032:
0033: - lib/mail.jar
0034: - lib/activation.jar
0035: - lib/jsse.jar
0036: - lib/jcert.jar
0037: - lib/jaxp.jar
0038: - lib/crimson.jar
0039: - lib/servlet.jar
0040: - lib/jnet.jar
0041: - lib/jaas.jar
0042: - lib/jaasmod.jar
0043:
0044: contained in this release.
0045:
0046: a. Licensee may not modify the Java Platform
0047: Interface (JPI, identified as classes contained within the javax
0048: package or any subpackages of the javax package), by creating additional
0049: classes within the JPI or otherwise causing the addition to or modification
0050: of the classes in the JPI. In the event that Licensee creates any
0051: Java-related API and distribute such API to others for applet or
0052: application development, you must promptly publish broadly, an accurate
0053: specification for such API for free use by all developers of Java-based
0054: software.
0055:
0056: b. Software is confidential copyrighted information of Sun and
0057: title to all copies is retained by Sun and/or its licensors. Licensee
0058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
0059: reverse engineer Software. Software may not be leased, assigned, or
0060: sublicensed, in whole or in part. Software is not designed or intended
0061: for use in on-line control of aircraft, air traffic, aircraft navigation
0062: or aircraft communications; or in the design, construction, operation or
0063: maintenance of any nuclear facility. Licensee warrants that it will not
0064: use or redistribute the Software for such purposes.
0065:
0066: c. Software is provided "AS IS," without a warranty
0067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
0068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
0069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
0070:
0071: d. This License is effective until terminated. Licensee may
0072: terminate this License at any time by destroying all copies of Software.
0073: This License will terminate immediately without notice from Sun if Licensee
0074: fails to comply with any provision of this License. Upon such termination,
0075: Licensee must destroy all copies of Software.
0076:
0077: e. Software, including technical data, is subject to U.S.
0078: export control laws, including the U.S. Export Administration Act and its
0079: associated regulations, and may be subject to export or import regulations
0080: in other countries. Licensee agrees to comply strictly with all such
0081: regulations and acknowledges that it has the responsibility to obtain
0082: licenses to export, re-export, or import Software. Software may not be
0083: downloaded, or otherwise exported or re-exported (i) into, or to a national
0084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
0085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
0086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
0087: Commerce Department's Table of Denial Orders.
0088:
0089:
0090: Feedback
0091: ========
0092:
0093: We encourage your feedback and suggestions and want to use your feedback to
0094: improve the Software. Send all such feedback to:
0095: <feedback@tagtraum.com>
0096:
0097: For more information on tagtraum industries and jo!
0098: please see <http://www.tagtraum.com/>.
0099:
0100:
0101: */
0102: package com.tagtraum.jo;
0103:
0104: import com.tagtraum.framework.http.*;
0105: import com.tagtraum.framework.log.Log;
0106: import com.tagtraum.framework.recycler.Recycler;
0107: import com.tagtraum.framework.util.ArrayEnumeration;
0108: import com.tagtraum.framework.util.Ciphers;
0109: import com.tagtraum.framework.util.FactoryException;
0110: import com.tagtraum.framework.util.OrderedMap;
0111: import com.tagtraum.jo.security.CertificateConverter;
0112: import com.tagtraum.jo.security.I_JoSecurityRole;
0113: import com.tagtraum.jo.security.I_JoSecurityRoleRef;
0114:
0115: import javax.net.ssl.SSLPeerUnverifiedException;
0116: import javax.net.ssl.SSLSession;
0117: import javax.security.cert.X509Certificate;
0118: import javax.servlet.RequestDispatcher;
0119: import javax.servlet.ServletException;
0120: import javax.servlet.ServletInputStream;
0121: import javax.servlet.http.Cookie;
0122: import javax.servlet.http.HttpServletRequest;
0123: import javax.servlet.http.HttpSession;
0124: import javax.servlet.http.HttpUtils;
0125: import java.io.*;
0126: import java.net.InetAddress;
0127: import java.net.Socket;
0128: import java.net.UnknownHostException;
0129: import java.util.*;
0130:
0131: /**
0132: * Represents the request.
0133: *
0134: * @version 1.1beta1 $Id: JoServletRequest.java,v 1.22 2005/03/15 20:08:14 hendriks73 Exp $
0135: * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
0136: * @see JoServletResponse
0137: * @see I_JoServletResponse
0138: * @see I_JoServletRequest
0139: * @see JoServletRequest
0140: */
0141: public class JoServletRequest implements I_JoServletRequest, C_Jo,
0142: C_Http {
0143:
0144: /**
0145: * Source-Version
0146: */
0147: public static String vcid = "$Id: JoServletRequest.java,v 1.22 2005/03/15 20:08:14 hendriks73 Exp $";
0148: /**
0149: * MIME-Type for forms.
0150: */
0151: public static final String C_MIME_WWW_FORM = "application/x-www-form-urlencoded";
0152: private static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite";
0153: private static final String CIPHER_KEY_SIZE_KEY = "javax.servlet.request.key_size";
0154:
0155: private static ResourceBundle localStrings = ResourceBundle
0156: .getBundle("com.tagtraum.jo.localStrings");
0157: private static Set nonSSLSocketClasses = new HashSet();
0158:
0159: private HttpHeader header;
0160: /** Parameters, which have been sent with a form. */
0161: private OrderedMap formParameters;
0162: private Map parameterMap;
0163: /** Indicates whether we already parsed formparameters. */
0164: private boolean parsedFormParameters;
0165: private RequestLine requestLine;
0166: /** Path of the calles servlet. */
0167: private String servletPath;
0168: /** Optional path following the servletpath. */
0169: private String pathInfo;
0170: /** Translated optional path. */
0171: private String pathTranslated;
0172: private String remoteUser;
0173: /** Roles the remote user is in. */
0174: private Set authRoles;
0175: /** Authentication type */
0176: private String authType;
0177: private String requestedSessionID;
0178: /** SessionID requested with a cookie. */
0179: private String cookieSessionID;
0180: /** SessionID from the URL. */
0181: private String urlSessionID;
0182: private I_JoSessionContext sessionContext;
0183: private I_JoSession session;
0184: private I_JoHost host;
0185: private I_JoServletContextPeer peer;
0186: private I_JoServletContext servletContext;
0187: private I_JoServletResponse response;
0188: /** Accept-Language locales. */
0189: private Locale[] acceptLanguageLocales;
0190: private Socket socket;
0191: private JoInputStream servletInputStream;
0192: private InputStream bufferedSocketInputStream;
0193: private String serverName;
0194: private int serverPort;
0195: private String remoteAddr;
0196: private InetAddress remoteInetAddr;
0197: private String remoteHost;
0198: private Hashtable attributes;
0199: /** Indicates whether a reader has been obtained. */
0200: private boolean gotReader;
0201: /** Indicates whether am InputStream has been obtained. */
0202: private boolean gotInputStream;
0203: /** Indicates whether this request was transmitted over a secure protocol. */
0204: private boolean secure;
0205: private BufferedReader reader;
0206: /** Char encoding of the reader. */
0207: private String encoding;
0208: private I_JoServletModel model;
0209:
0210: /**
0211: * No-arg-constructor.
0212: */
0213: public JoServletRequest() {
0214: this .requestLine = new RequestLine();
0215: this .header = new HttpHeader();
0216: this .servletInputStream = new JoInputStream();
0217: this .formParameters = new OrderedMap();
0218: this .attributes = new Hashtable();
0219: this .authRoles = new HashSet();
0220: }
0221:
0222: /**
0223: * Initializes this request object.
0224: */
0225: public void init() {
0226: this .encoding = null;
0227: this .gotReader = false;
0228: this .gotInputStream = false;
0229: this .serverPort = 0;
0230: this .serverName = null;
0231: this .remoteAddr = null;
0232: this .remoteInetAddr = null;
0233: this .response = null;
0234: this .servletContext = null;
0235: this .reader = null;
0236: this .attributes.clear();
0237: this .formParameters.clear();
0238: this .parsedFormParameters = false;
0239: this .parameterMap = null;
0240: this .servletPath = null;
0241: this .pathInfo = null;
0242: this .remoteUser = null;
0243: this .authType = null;
0244: this .authRoles.clear();
0245: this .requestedSessionID = null;
0246: this .pathTranslated = null;
0247: this .cookieSessionID = null;
0248: this .urlSessionID = null;
0249: this .sessionContext = null;
0250: this .session = null;
0251: this .host = null;
0252: this .peer = null;
0253: this .acceptLanguageLocales = null;
0254: this .model = null;
0255: this .header.init();
0256: }
0257:
0258: public void setModel(I_JoServletModel model) {
0259: this .model = model;
0260: }
0261:
0262: /**
0263: * Returns the socket of this request.
0264: *
0265: * @return this request's socket
0266: */
0267: public Socket getSocket() {
0268: return socket;
0269: }
0270:
0271: /**
0272: * Sets the socket of this request.
0273: *
0274: * @param aSocket this request's socket
0275: */
0276: public void setSocket(Socket aSocket) throws IOException {
0277: this .socket = aSocket;
0278: this .bufferedSocketInputStream = new BufferedInputStream(socket
0279: .getInputStream());
0280: }
0281:
0282: private void setSSLRelatedAttributes() {
0283: this .secure = true;
0284: try {
0285: javax.net.ssl.SSLSocket sslSocket = ((javax.net.ssl.SSLSocket) socket);
0286: SSLSession sslSession = sslSocket.getSession();
0287: if (sslSession != null) {
0288: // See Servlet Spec 2.3, Section 4.7
0289: final String cipherSuite = sslSession.getCipherSuite();
0290: setAttribute(CIPHER_SUITE_KEY, cipherSuite);
0291: setAttribute(CIPHER_KEY_SIZE_KEY, Ciphers
0292: .getKeySize(cipherSuite));
0293: X509Certificate[] peerCertificateChain = new X509Certificate[0];
0294: try {
0295: peerCertificateChain = sslSession
0296: .getPeerCertificateChain();
0297: } catch (SSLPeerUnverifiedException e) {
0298: if (Log.isLog(Log.ERROR, host.getName())) {
0299: Log
0300: .getLog(host.getName())
0301: .log(
0302: localStrings
0303: .getString("no_peer_certificatechain"),
0304: Log.MODULE);
0305: Log.getLog(host.getName()).log(e, Log.FORTYTWO);
0306: }
0307: }
0308: if (peerCertificateChain != null) {
0309: setAttribute(
0310: C_Request_Attribute_X509Certificate,
0311: CertificateConverter
0312: .convertX509Certificates(peerCertificateChain));
0313: } else {
0314: if (Log.isLog(Log.ERROR, host.getName())) {
0315: Log
0316: .getLog(host.getName())
0317: .log(
0318: localStrings
0319: .getString("no_peer_certificatechain"),
0320: Log.MODULE);
0321: }
0322: }
0323: } else {
0324: if (Log.isLog(Log.ERROR, host.getName())) {
0325: Log.getLog(host.getName()).log(
0326: localStrings.getString("no_ssl_session"),
0327: Log.ERROR);
0328: }
0329: }
0330: // if a certificate was present set SSL as AuthType
0331: setAuthType(HttpServletRequest.CLIENT_CERT_AUTH);
0332: } catch (Exception e) {
0333: if (Log.isLog(Log.ERROR, host.getName())) {
0334: Log
0335: .getLog(host.getName())
0336: .log(
0337: localStrings
0338: .getString("peer_certificate_conversion_failed"),
0339: Log.ERROR);
0340: Log.getLog(host.getName()).log(e, Log.METHOD);
0341: }
0342: }
0343: }
0344:
0345: /**
0346: * Helpermethod that provides a way to NOT load ssl related classes and therefore allows
0347: * for jo being distributed without all the SSL stuff.
0348: */
0349: private static synchronized boolean isSSLSocket(Socket socket) {
0350: if (!nonSSLSocketClasses.contains(socket.getClass())) {
0351: try {
0352: socket.getClass().getMethod("getSession",
0353: (java.lang.Class[]) null);
0354: return true;
0355: } catch (NoSuchMethodException nsme) {
0356: // ignore
0357: }
0358: nonSSLSocketClasses.add(socket.getClass());
0359: }
0360: return false;
0361: }
0362:
0363: /**
0364: * Sets the response for this request. Request and response always
0365: * know each other.
0366: *
0367: * @param aResponse Response of this request.
0368: */
0369: public void setResponse(I_JoServletResponse aResponse) {
0370: this .response = aResponse;
0371: }
0372:
0373: /**
0374: * Returns the remote address.
0375: *
0376: * @return remote address
0377: */
0378: public String getRemoteAddr() {
0379: if (remoteAddr == null) {
0380: remoteAddr = getRemoteInetAddr().getHostAddress();
0381: }
0382: return remoteAddr;
0383: }
0384:
0385: /**
0386: * Returns the remote address.
0387: *
0388: * @return remote address
0389: */
0390: public InetAddress getRemoteInetAddr() {
0391: if (remoteInetAddr == null) {
0392: remoteInetAddr = socket.getInetAddress();
0393: }
0394: return remoteInetAddr;
0395: }
0396:
0397: /**
0398: * Returns the remote hostname.
0399: *
0400: * @return remote hostname
0401: */
0402: public String getRemoteHost() {
0403: if (remoteHost == null) {
0404: remoteHost = getRemoteInetAddr().getHostName();
0405: }
0406: return remoteHost;
0407: }
0408:
0409: /**
0410: * Returns an attribute of this request.
0411: *
0412: * @param aName name
0413: * @return value
0414: */
0415: public Object getAttribute(String aName) {
0416: return attributes.get(aName);
0417: }
0418:
0419: /**
0420: * Returns an enumeration of the attribute names.
0421: *
0422: * @return enumeration
0423: */
0424: public Enumeration getAttributeNames() {
0425: return attributes.keys();
0426: }
0427:
0428: /**
0429: * Sets an attribute.
0430: *
0431: * @param aName name
0432: * @param aValue value
0433: */
0434: public void setAttribute(String aName, Object aValue) {
0435: if (aValue == null) {
0436: attributes.remove(aName);
0437: } else {
0438: attributes.put(aName, aValue);
0439: }
0440: }
0441:
0442: /**
0443: * Removes an attribute.
0444: *
0445: * @param aName Name of the attribute
0446: */
0447: public void removeAttribute(String aName) {
0448: if (aName != null) {
0449: attributes.remove(aName);
0450: }
0451: }
0452:
0453: /**
0454: * Closes the underlying stream.
0455: *
0456: * @exception IOException
0457: */
0458: public void close() throws IOException {
0459: this .servletInputStream.close();
0460: }
0461:
0462: /**
0463: * Sets the {@link I_JoServletContext} for this request.
0464: *
0465: * @param aServletContext corresponding context
0466: */
0467: public void setServletContext(I_JoServletContext aServletContext) {
0468: this .servletContext = aServletContext;
0469: }
0470:
0471: /**
0472: * Returns the char encoding of the current content type.
0473: *
0474: * @return the Charset or <code>null</code>, if none has been set
0475: */
0476: public String getCharacterEncoding() {
0477: // Servlet Spec, Section 4.9
0478: if (encoding == null) {
0479: String contentType = getContentType();
0480: if (contentType != null) {
0481: // does this work in every case?
0482: int i = contentType.indexOf('=');
0483: if (i != -1) {
0484: encoding = contentType.substring(i).trim();
0485: if (encoding.length() > 1) {
0486: encoding = encoding.substring(1);
0487: }
0488: }
0489: }
0490: }
0491: return encoding;
0492: }
0493:
0494: public void setCharacterEncoding(String encoding) {
0495: // Servlet Spec, Section 4.9
0496: this .encoding = encoding;
0497: }
0498:
0499: /**
0500: * Translates a virtual path into a real path.
0501: *
0502: * @param path virtual path to translate
0503: * @return real path
0504: * @deprecated
0505: */
0506: public String getRealPath(String path) {
0507: return servletContext.getRealPath(path);
0508: }
0509:
0510: /**
0511: * If a request has been transmitted over a secure protocol,
0512: * such as HTTPS, this method returns true.
0513: *
0514: * @return always returns false
0515: */
0516: public boolean isSecure() {
0517: return secure;
0518: }
0519:
0520: /**
0521: * Reads the Request.
0522: */
0523: public void readRequest() throws IOException {
0524: requestLine.read(bufferedSocketInputStream);
0525: if (!requestLine.getProtocol().equals(C_HTTP_0_9)) {
0526: header.read(bufferedSocketInputStream);
0527: // has to be called after header.read(),
0528: // otherwise scheme does not return the right value,
0529: // and getServerName returns the localhost
0530: // because it depends on getServerPort. hm nasty (rik)
0531: absoluteURIToHostHeader();
0532: checkRequest();
0533: } else {
0534: absoluteURIToHostHeader(); // if GET http://www.foo.bar/ HTTP*** set host header automatically
0535: }
0536: if ("chunked".equals(header.getHeader(C_HTTP_TransferEncoding))) {
0537: (servletInputStream).init(new ChunkedInputStream(
0538: bufferedSocketInputStream));
0539: } else {
0540: (servletInputStream).init(bufferedSocketInputStream, header
0541: .getIntHeader(C_HTTP_ContentLength));
0542: }
0543: }
0544:
0545: /**
0546: * Sets the peer associated with this object.
0547: *
0548: * @param aPeer I_JoServletContextPeer
0549: */
0550: public void setServletContextPeer(I_JoServletContextPeer aPeer) {
0551: this .peer = aPeer;
0552: this .host = aPeer.getHost();
0553: // set ssl attributes (certificate)
0554: if (isSSLSocket(socket)) {
0555: setSSLRelatedAttributes();
0556: }
0557: this .sessionContext = peer.getSessionContext();
0558: setServletContext(aPeer.getServletContext());
0559: if (Log.isLog(Log.FORTYTWO, host.getName())) {
0560: StringBuffer sb = new StringBuffer();
0561: sb.append("Request-Header:\n");
0562: sb.append(requestLine.toString());
0563: sb.append('\n');
0564: sb.append(header.toString());
0565: Log.getLog(host.getName()).log(sb.toString(), Log.FORTYTWO);
0566: }
0567: }
0568:
0569: /**
0570: * Checks, whether this request comforms to the spec.
0571: */
0572: private void checkRequest() throws HttpException {
0573: if (requestLine != null && header != null
0574: && header.getHeader(C_HTTP_Host) == null
0575: && C_HTTP_1_1.equals(requestLine.getProtocol())) {
0576: throw new HttpException(StatusCodes.SC_BAD_REQUEST,
0577: localStrings.getString("missing_headerfield_host"));
0578: }
0579: String expectation;
0580: if ((expectation = header.getHeader(C_HTTP_Expect)) != null) {
0581: throw new HttpException(StatusCodes.SC_EXPECTATION_FAILED,
0582: localStrings.getString("expectation_failed")
0583: + expectation);
0584: }
0585: if (getProtocol().charAt(5) > '1') {
0586: throw new HttpException(
0587: StatusCodes.SC_HTTP_VERSION_NOT_SUPPORTED,
0588: localStrings
0589: .getString("http_version_not_supported"));
0590: }
0591: }
0592:
0593: /**
0594: * Returns a ServletInputStream.
0595: *
0596: * @return ServletInputStream
0597: */
0598: public ServletInputStream getInputStream() throws IOException {
0599: if (gotReader) {
0600: throw new IllegalStateException(localStrings
0601: .getString("illegal_getinputstream_call"));
0602: }
0603: if (!gotInputStream) {
0604: gotInputStream = true;
0605: }
0606: return servletInputStream;
0607: }
0608:
0609: /**
0610: * Returns a reader.
0611: *
0612: * @return Reader
0613: */
0614: public BufferedReader getReader() throws IOException {
0615: if (gotInputStream) {
0616: throw new IllegalStateException(localStrings
0617: .getString("illegal_getreader_call"));
0618: }
0619: if (reader == null) {
0620: InputStreamReader aStreamReader;
0621: String encoding = getCharacterEncoding() == null ? "ISO-8859-1"
0622: : getCharacterEncoding();
0623: aStreamReader = new InputStreamReader(servletInputStream,
0624: encoding);
0625: reader = new BufferedReader(aStreamReader);
0626: gotReader = true;
0627: }
0628: return reader;
0629: }
0630:
0631: /**
0632: * Try to obtain a session id from the read cookies.
0633: *
0634: * @return sessionid or null, if no sessionid was found.
0635: */
0636: private String getCookieSessionID() {
0637: Cookie[] cookies = getCookies();
0638: if (cookies == null || cookies.length == 0) {
0639: return null;
0640: }
0641: for (int i = 0; i < cookies.length; i++) {
0642: if (cookies[i].getName().equals(C_DefaultSessionCookieName)) {
0643: return cookies[i].getValue();
0644: }
0645: }
0646: return null;
0647: }
0648:
0649: /**
0650: * Try to obtain a session id from the requested URL.
0651: *
0652: * @return sessionid or null, if no sessionid was found.
0653: */
0654: private String getURLSessionID() {
0655: String theParameter = requestLine.getURI().getParameter();
0656: String theSessionID = null;
0657: if (theParameter != null) {
0658: int idx = theParameter.indexOf(C_DefaultSessionIDName);
0659: if (idx != -1
0660: && theParameter.length() > C_DefaultSessionIDNameLength + 1) {
0661: theSessionID = theParameter
0662: .substring(C_DefaultSessionIDNameLength + 1);
0663: }
0664: }
0665: return theSessionID;
0666: }
0667:
0668: public HttpHeader getHttpHeader() {
0669: return header;
0670: }
0671:
0672: /**
0673: * Returns the requestline.
0674: *
0675: * @return the requestline
0676: */
0677: public RequestLine getRequestLine() {
0678: return requestLine;
0679: }
0680:
0681: /**
0682: * Sets the requestline.
0683: *
0684: * @param aRequestLine the requestline
0685: */
0686: public void setRequestLine(RequestLine aRequestLine) {
0687: this .requestLine = aRequestLine;
0688: }
0689:
0690: /**
0691: * Sets the path of the servlet that is executing this request.
0692: * See spec.
0693: *
0694: * @param servletPath Path of the servlet
0695: */
0696: public void setServletPath(String servletPath) {
0697: this .servletPath = servletPath;
0698: this .pathTranslated = null;
0699: this .pathInfo = null;
0700: }
0701:
0702: /**
0703: * Sets the name of the remote user.
0704: *
0705: * @param aName name of the remote user
0706: */
0707: public void setRemoteUser(String aName) {
0708: this .remoteUser = aName;
0709: }
0710:
0711: /**
0712: * Decodes formparameters.
0713: */
0714: private OrderedMap getFormParameters() {
0715: String theContentType = getContentType();
0716: if (!parsedFormParameters
0717: && theContentType != null
0718: && (theContentType == C_MIME_WWW_FORM || theContentType
0719: .startsWith(C_MIME_WWW_FORM))
0720: && getMethod().equals(C_HTTP_POST)) {
0721: parsePostData(getContentLength(), servletInputStream);
0722: }
0723: return formParameters;
0724: }
0725:
0726: /**
0727: * Returns the Content-Length of the body.
0728: *
0729: * @return Content-Length
0730: */
0731: public int getContentLength() {
0732: return header.getIntHeader(C_HTTP_ContentLength);
0733: }
0734:
0735: /**
0736: * Returns the Content-Type of the body.
0737: *
0738: * @return Content-Type
0739: */
0740: public String getContentType() {
0741: return header.getHeader(C_HTTP_ContentType);
0742: }
0743:
0744: /**
0745: * Retruns the used Protocol.
0746: *
0747: * @return Protocol
0748: */
0749: public String getProtocol() {
0750: return requestLine.getProtocol();
0751: }
0752:
0753: /**
0754: * Returns the Servernamen.
0755: *
0756: * @return server name
0757: */
0758: public String getServerName() {
0759: // first try to read the servername from the header.
0760: if (serverName == null) {
0761: serverName = getHeader(C_HTTP_Host);
0762: if (serverName != null && serverName.length() > 0) {
0763: int colon = serverName.indexOf(':');
0764: if (colon >= 0) {
0765: if (colon < serverName.length()) {
0766: serverPort = Integer.parseInt(serverName
0767: .substring(colon + 1));
0768: }
0769: serverName = serverName.substring(0, colon);
0770: } else {
0771: serverPort = socket.getLocalPort();
0772: }
0773: } else {
0774: serverName = socket.getLocalAddress().getHostName();
0775: }
0776: if (serverName == null) {
0777: try {
0778: serverName = InetAddress.getLocalHost()
0779: .getHostName();
0780: } catch (UnknownHostException uhe) {
0781: /* do nothing */
0782: }
0783: }
0784: }
0785: return serverName;
0786: }
0787:
0788: /**
0789: * Returns the portnumber.
0790: *
0791: * @return portnumber
0792: */
0793: public int getServerPort() {
0794: if (serverPort != 0) {
0795: return serverPort;
0796: }
0797: if (serverName == null) {
0798: getServerName();
0799: }
0800: if (serverPort == 0) {
0801: serverPort = socket.getLocalPort();
0802: }
0803: return serverPort;
0804: }
0805:
0806: /**
0807: * Returns a value (the first one) for a parametername.
0808: *
0809: * @param aName name
0810: * @return value or <code>null</code>
0811: */
0812: public String getParameter(String aName) {
0813: String[] values = getParameterValues(aName);
0814: if (values == null || values.length == 0)
0815: return null;
0816: return values[0];
0817: }
0818:
0819: /**
0820: * Returns a java.util.Map of the parameters of this request. Request parameters
0821: * are extra information sent with the request. For HTTP servlets, parameters
0822: * are contained in the query string or posted form data.
0823: *
0824: * @return an immutable {@link java.util.Map} containing parameter names as keys
0825: * and parameter values as map values. The keys in the parameter map are of
0826: * type String. The values in the parameter map are of type String array.
0827: */
0828: public Map getParameterMap() {
0829: if (parameterMap == null) {
0830: parameterMap = new HashMap();
0831: Set parameterNames = new HashSet(requestLine.getURI()
0832: .getParameterNamesSet());
0833: parameterNames.addAll(getFormParameters().keySet());
0834: for (Iterator names = parameterNames.iterator(); names
0835: .hasNext();) {
0836: String name = (String) names.next();
0837: String[] values = internalGetParameterValues(name);
0838: if (values != null && values.length > 0)
0839: parameterMap.put(name, values);
0840: }
0841: parameterMap = Collections.unmodifiableMap(parameterMap);
0842: }
0843: return parameterMap;
0844: }
0845:
0846: /**
0847: * Returns all parameter values for a given name
0848: *
0849: * @param name name
0850: * @return array of values
0851: */
0852: public String[] getParameterValues(String name) {
0853: return (String[]) getParameterMap().get(name);
0854: }
0855:
0856: /**
0857: * Returns all parameter values for a given name
0858: *
0859: * @param name name
0860: * @return array of values
0861: */
0862: private String[] internalGetParameterValues(String name) {
0863: String[] uriValues = requestLine.getURI().getValues(name);
0864: String[] formValues;
0865: Object fv;
0866: fv = getFormParameters().get(name);
0867: if (fv != null && fv instanceof String) {
0868: formValues = new String[1];
0869: formValues[0] = (String) fv;
0870: } else {
0871: formValues = (String[]) fv;
0872: }
0873: if (formValues == null && uriValues == null)
0874: return null;
0875: int formLen = 0;
0876: int uriLen = 0;
0877: if (formValues != null)
0878: formLen = formValues.length;
0879: if (uriValues != null)
0880: uriLen = uriValues.length;
0881: if (formLen == 0 && uriLen == 0)
0882: return null;
0883:
0884: String[] values = new String[formLen + uriLen];
0885: // as per servlet spec 2.3, 4.1: quey string data is presented before post body data
0886: if (uriValues != null)
0887: System.arraycopy(uriValues, 0, values, 0, uriLen);
0888: if (formValues != null)
0889: System.arraycopy(formValues, 0, values, uriLen, formLen);
0890: return values;
0891: }
0892:
0893: /**
0894: * Returns an enumeration of all parameternames.
0895: *
0896: * @return enumeration
0897: */
0898: public Enumeration getParameterNames() {
0899: return Collections.enumeration(getParameterMap().keySet());
0900: }
0901:
0902: /**
0903: * Returns the scheme "http" or "https".
0904: *
0905: * @return scheme
0906: */
0907: public String getScheme() {
0908: if (isSecure()) {
0909: return "https";
0910: }
0911: return "http";
0912: }
0913:
0914: /**
0915: * Returns the request method.
0916: *
0917: * @return request methode (GET, POST, ...)
0918: */
0919: public String getMethod() {
0920: return requestLine.getMethod();
0921: }
0922:
0923: /**
0924: * Sets the request method.
0925: */
0926: public void setMethod(String method) {
0927: this .requestLine.setMethod(method);
0928: }
0929:
0930: /**
0931: * Returns the url encoded URI.
0932: *
0933: * @return URI
0934: */
0935: public String getRequestURI() {
0936: return requestLine.getURI().getPath();
0937: }
0938:
0939: public StringBuffer getRequestURL() {
0940: return HttpUtils.getRequestURL(this );
0941: }
0942:
0943: /**
0944: * See if the current URI is absolute. If so
0945: * set the appropiate header.
0946: * Also replace * with /.
0947: */
0948: private void absoluteURIToHostHeader() {
0949: // this is cheaper than calling getPath(), if the URI has not been parsed yet (rik)
0950: String path = requestLine.getURI().toString();
0951:
0952: // FIXME!!!
0953: // Usually only the HTTP method OPTIONS uses a * as URI
0954: // In order to avoid a Servlet-Not-Found, this quick hack
0955: // that does not work if a servlet is mapped to "/" that understands
0956: // only some methods. :-( (rik)
0957: if (path.equals("*")) {
0958: requestLine.getURI().init("/");
0959: } else if (!path.startsWith("/")
0960: && path.startsWith(getScheme())) {
0961: // !path.startsWith("/") is cheaper and more likely to succeed and short circuits the long comparison
0962: int schemeLength = getScheme().length() + 3; // that's "://"
0963: int hostend = path.indexOf("/", schemeLength);
0964: setHeader(C_HTTP_Host, path
0965: .substring(schemeLength, hostend));
0966: requestLine.getURI().init(path.substring(hostend));
0967: }
0968:
0969: }
0970:
0971: /**
0972: * Overwrites the URI of this request.
0973: *
0974: * @param aRequestURI this request's URI
0975: */
0976: public void setRequestURI(String aRequestURI) {
0977: this .requestLine.getURI().init(aRequestURI);
0978: absoluteURIToHostHeader();
0979: }
0980:
0981: /**
0982: * Returns the not URL encoded ServletPath.
0983: *
0984: * @return ServletPath
0985: */
0986: public String getServletPath() {
0987: return servletPath;
0988: }
0989:
0990: /**
0991: * Returns teh not url-encoded part after the the ServletPath.
0992: *
0993: * @return pathinfo
0994: */
0995: public String getPathInfo() {
0996: if (pathInfo == null) {
0997: try {
0998: pathInfo = com.tagtraum.framework.util.URLDecoder
0999: .decode(requestLine.getURI().getPath())
1000: .substring(
1001: servletPath.length()
1002: + getContextPath().length());
1003: } catch (Exception e) {
1004: e.printStackTrace();
1005: }
1006: }
1007: if (pathInfo.length() == 0)
1008: return null;
1009: return pathInfo;
1010: }
1011:
1012: /**
1013: * Returns the translated path.
1014: *
1015: * @return path translated
1016: */
1017: public String getPathTranslated() {
1018: if (pathTranslated == null && getPathInfo() != null) {
1019: pathTranslated = getRealPath(getPathInfo());
1020: }
1021: return pathTranslated;
1022: }
1023:
1024: /**
1025: * Returns the context path
1026: *
1027: * @return context path
1028: */
1029: public String getContextPath() {
1030: return peer.getContextPath();
1031: }
1032:
1033: /**
1034: * Returns the url-encoded query string.
1035: *
1036: * @return QueryString
1037: */
1038: public String getQueryString() {
1039: return requestLine.getURI().getQuery();
1040: }
1041:
1042: /**
1043: * Returns the remote user.
1044: *
1045: * @return remote user
1046: */
1047: public String getRemoteUser() {
1048: return remoteUser;
1049: }
1050:
1051: /**
1052: * Returns the type of authentification.
1053: *
1054: * @return type of authentification
1055: */
1056: public String getAuthType() {
1057: return authType;
1058: }
1059:
1060: /**
1061: * Sets the auth type.
1062: *
1063: * @param aType
1064: */
1065: public void setAuthType(String aType) {
1066: this .authType = aType;
1067: }
1068:
1069: /**
1070: * Sets the auth role-names.
1071: *
1072: * @param authRoles an array of role-names that are authorized
1073: * to acces the current resource
1074: */
1075: public void setAuthRoles(String[] authRoles) {
1076: this .authRoles.addAll(Arrays.asList(authRoles));
1077: }
1078:
1079: public boolean isUserInRole(String aRoleName) {
1080: if (authRoles == null)
1081: return false;
1082: I_JoSecurityRoleRef roleRef = model
1083: .getSecurityRoleRefByLink(aRoleName);
1084: if (roleRef == null)
1085: roleRef = model.getSecurityRoleRef(aRoleName);
1086: if (roleRef != null)
1087: aRoleName = roleRef.getRoleName();
1088: I_JoSecurityRole securityRole = peer.getSecurityRole(aRoleName);
1089: return authRoles.contains(securityRole.getName());
1090: }
1091:
1092: /**
1093: * Returns a <code>java.security.Principal</code> object containing
1094: * the name of the current authenticated user. If the user has not been
1095: * authenticated, the method returns <code>null</code>.
1096: *
1097: * @return a <code>java.security.Principal</code> containing
1098: * the name of the user making this request;
1099: * <code>null</code> if the user has not been
1100: * authenticated
1101: */
1102: public java.security.Principal getUserPrincipal() {
1103: if (remoteUser == null)
1104: return null;
1105: return host.getService().getAccessController().getPrincipal(
1106: remoteUser);
1107: }
1108:
1109: /**
1110: * Returns this request's SessionID.
1111: *
1112: * @return SessionID
1113: */
1114: public String getRequestedSessionId() {
1115: if (requestedSessionID == null) {
1116: if (!peer.isNoSessionCookies()) {
1117: cookieSessionID = getCookieSessionID();
1118: if (cookieSessionID != null) {
1119: requestedSessionID = cookieSessionID;
1120: } else {
1121: urlSessionID = getURLSessionID();
1122: requestedSessionID = urlSessionID;
1123: }
1124: } else {
1125: urlSessionID = getURLSessionID();
1126: requestedSessionID = urlSessionID;
1127: }
1128: }
1129: return requestedSessionID;
1130: }
1131:
1132: /**
1133: * Returns an already existing session, or creates one
1134: * if no session exists yet.
1135: *
1136: * @return the Session or <code>null</code>
1137: */
1138: public HttpSession getSession() {
1139: return getSession(true);
1140: }
1141:
1142: /**
1143: * Returns an already existing session, or creates one
1144: * if no session exists yet and the argument is true.
1145: *
1146: * @param create true, if a session should be created if it does not
1147: * exist
1148: * @return the Session or <code>null</code>
1149: */
1150: public HttpSession getSession(boolean create) {
1151: // did we already get a session?
1152: if (session != null && session.isValid())
1153: return session;
1154: // do we have a sessioncontext? do we really have to test this? (rik)
1155: if (sessionContext == null)
1156: return null;
1157: // get the ID
1158: String id = getRequestedSessionId();
1159: // if there is an ID, get the session
1160: if (id != null)
1161: session = (I_JoSession) sessionContext.getSession(id);
1162: // if we don't have to create and didn't get a session, return null
1163: if (!create && (session == null || !session.isValid()))
1164: return null;
1165: try {
1166: if (session == null || !session.isValid()) {
1167: session = sessionContext.newSession();
1168: if (session == null)
1169: return null;
1170: String theSessionID = getHeader(C_DefaultSessionIDName);
1171: if (theSessionID != null)
1172: session.setId(theSessionID);
1173: else
1174: session.setId(sessionContext.getNewId());
1175: if (!peer.isNoSessionCookies()) {
1176: Cookie SessionCookie = new Cookie(
1177: C_DefaultSessionCookieName, session.getId());
1178: SessionCookie.setPath("/");
1179: if (peer.getSessionCookieDomain() != null)
1180: SessionCookie.setDomain(peer
1181: .getSessionCookieDomain());
1182: response.addCookie(SessionCookie);
1183: }
1184: }
1185: } catch (Exception e) {
1186: if (Log.isLog(host.getName())) {
1187: Log
1188: .getLog(host.getName())
1189: .log(
1190: localStrings
1191: .getString("session_instantiation_failed")
1192: + Log.getStackTrace(e));
1193: }
1194: }
1195: return session;
1196: }
1197:
1198: /**
1199: * Indicates whether the SessionID is from a Cookie.
1200: *
1201: * @return <code>true</code> or <code>false</code>
1202: */
1203: public boolean isRequestedSessionIdFromCookie() {
1204: getRequestedSessionId();
1205: return cookieSessionID != null;
1206: }
1207:
1208: /**
1209: * Indicates whether the SessionID is from a URL.
1210: *
1211: * @return <code>true</code> or <code>false</code>
1212: */
1213: public boolean isRequestedSessionIdFromUrl() {
1214: return isRequestedSessionIdFromURL();
1215: }
1216:
1217: /**
1218: * Indicates whether the SessionID is from a URL.
1219: *
1220: * @return <code>true</code> or <code>false</code>
1221: */
1222: public boolean isRequestedSessionIdFromURL() {
1223: getRequestedSessionId();
1224: return urlSessionID != null;
1225: }
1226:
1227: /**
1228: * Indicates whether the sessionID is valid.
1229: *
1230: * @return <code>true</code> or <code>false</code>
1231: */
1232: public boolean isRequestedSessionIdValid() {
1233: return getSession(false) != null;
1234: }
1235:
1236: /**
1237: * Retruns an array of all sent cookies.
1238: *
1239: * @return Cookies
1240: */
1241: public Cookie[] getCookies() {
1242: return header.getCookies();
1243: }
1244:
1245: /**
1246: * Returns a headervalue as <code>long</code>.
1247: *
1248: * @param aName name of the header
1249: * @return <code>long</code> or -1 if the header is not found
1250: */
1251: public long getDateHeader(String aName) {
1252: return header.getDateHeader(aName);
1253: }
1254:
1255: /**
1256: * Returns an enumaretion of the headername.
1257: *
1258: * @return enumeration
1259: */
1260: public Enumeration getHeaderNames() {
1261: return header.getHeaderNames();
1262: }
1263:
1264: /**
1265: * Returns a value as String.
1266: *
1267: * @param aKey name of the header
1268: * @return header or null
1269: */
1270: public String getHeader(String aKey) {
1271: return header.getHeader(aKey);
1272: }
1273:
1274: /**
1275: * Returns an Enumeration of all header values.
1276: *
1277: * @param aKey the headerkey
1278: * @return the header
1279: */
1280: public Enumeration getHeaders(String aKey) {
1281: return new ArrayEnumeration(header.getHeaders(aKey));
1282: }
1283:
1284: /**
1285: * Returns a headervalue as <code>int</code>.
1286: *
1287: * @param aName name of the header
1288: * @return <code>long</code> or -1 if the header is not found
1289: */
1290: public int getIntHeader(String aName) {
1291: return header.getIntHeader(aName);
1292: }
1293:
1294: /**
1295: * Sets a header.
1296: *
1297: * @param aKey key
1298: * @param aValue value
1299: */
1300: public void setHeader(String aKey, String aValue) {
1301: header.setHeader(aKey, aValue);
1302: }
1303:
1304: /**
1305: * Returns the AcceptLanguageLocales with the highest
1306: * priority or default value.
1307: *
1308: * @return highest accept language locale or default
1309: *
1310: * @see #getLocales()
1311: * @see #getAcceptLanguageLocales()
1312: */
1313: public Locale getLocale() {
1314: Locale[] acceptedLanguageLocales = getAcceptLanguageLocales();
1315: if (acceptedLanguageLocales.length >= 1)
1316: return acceptedLanguageLocales[0];
1317: else
1318: return Locale.getDefault();
1319: }
1320:
1321: /**
1322: * Returns a sorted enumeration of the AcceptLanguageLocales
1323: * beginning with the highest priority.
1324: *
1325: * @return enumeration
1326: *
1327: * @see #getLocale()
1328: * @see #getAcceptLanguageLocales()
1329: */
1330: public Enumeration getLocales() {
1331: Locale[] acceptedLanguageLocales = getAcceptLanguageLocales();
1332: if (acceptedLanguageLocales.length >= 1)
1333: new ArrayEnumeration(getAcceptLanguageLocales());
1334: return new ArrayEnumeration(
1335: new Locale[] { Locale.getDefault() });
1336: }
1337:
1338: /**
1339: * Returns a sorted array of the AcceptLanguageLocales
1340: * beginning with the highest priority.
1341: *
1342: * @return array
1343: *
1344: * @see #getLocale()
1345: * @see #getLocales()
1346: */
1347: private Locale[] getAcceptLanguageLocales() {
1348: if (acceptLanguageLocales == null) {
1349: WeightedValue[] weightedValueArray = WeightedValue
1350: .parse(header.getHeader(C_HTTP_Accept_Language));
1351: acceptLanguageLocales = new Locale[weightedValueArray.length];
1352: for (int i = 0; i < weightedValueArray.length; i++) {
1353: acceptLanguageLocales[i] = getLocale(weightedValueArray[i]
1354: .getValue());
1355: }
1356: }
1357: return acceptLanguageLocales;
1358: }
1359:
1360: private static Locale getLocale(String aValue) {
1361: if (aValue.equals("*")) {
1362: return Locale.getDefault();
1363: }
1364: String language;
1365: String country = "";
1366: String variant = "";
1367: int idx = aValue.indexOf('-');
1368: if (idx == -1) {
1369: language = aValue.toLowerCase();
1370: } else {
1371: language = aValue.substring(0, idx).toLowerCase();
1372: aValue = aValue.substring(idx + 1);
1373: idx = aValue.indexOf('-');
1374: if (idx == -1) {
1375: country = aValue.toUpperCase();
1376: } else {
1377: country = aValue.substring(0, idx).toUpperCase();
1378: variant = aValue.substring(idx + 1);
1379: }
1380: }
1381: return new Locale(language, country, variant);
1382: }
1383:
1384: /**
1385: * Returns RequestDispatcher relative to the current ressource.
1386: */
1387: public RequestDispatcher getRequestDispatcher(String aURI) {
1388: if (aURI == null)
1389: throw new NullPointerException(localStrings
1390: .getString("uri_cannot_be_null"));
1391: URI theURI = new URI(aURI);
1392: aURI = theURI.getPath();
1393: String servletPath = (String) getAttribute(C_Request_Attribute_ServletPath);
1394: if (servletPath == null)
1395: servletPath = getServletPath();
1396: if (!aURI.startsWith("/")) {
1397: int i = servletPath.lastIndexOf('/');
1398: if (i != -1) {
1399: aURI = getContextPath()
1400: + servletPath.substring(0, i + 1) + aURI;
1401: } else {
1402: aURI = getContextPath() + "/" + aURI; // is this possible?
1403: }
1404: } else {
1405: aURI = getContextPath() + aURI;
1406: }
1407: try {
1408: I_JoServletModel theModel = peer.getServletModel(aURI);
1409: if (theModel == null)
1410: return null;
1411: } catch (ServletException se) {
1412: return null;
1413: }
1414: theURI.setPath(aURI);
1415: try {
1416: I_JoRequestDispatcher aDispatcher = (I_JoRequestDispatcher) Recycler
1417: .getNamedRecycler(host.getName()).get(
1418: C_FactoryKey_RequestDispatcher);
1419: aDispatcher.init(theURI, peer);
1420: return aDispatcher;
1421: } catch (FactoryException fe) {
1422: if (Log.isLog(host.getName()))
1423: Log.getLog(host.getName()).log(fe);
1424: }
1425: return null;
1426: }
1427:
1428: /**
1429: * Parses the posted data.
1430: */
1431: private void parsePostData(int len, ServletInputStream in) {
1432: this .parsedFormParameters = true;
1433: if (len <= 0)
1434: return;
1435: try {
1436: // Make sure we read the entire POSTed body.
1437: byte[] postedBytes = new byte[len];
1438: int offset = 0;
1439: do {
1440: int inputLen = in.read(postedBytes, offset, len
1441: - offset);
1442: if (inputLen <= 0)
1443: throw new IOException("Unexpected end of stream.");
1444: offset += inputLen;
1445: } while ((len - offset) > 0);
1446: String encoding = getCharacterEncoding() == null ? "ISO-8859-1"
1447: : getCharacterEncoding();
1448: parseQueryString(new String(postedBytes, 0, len, encoding));
1449: } catch (IOException e) {
1450: return;
1451: }
1452: }
1453:
1454: /**
1455: * Utility method that parses the querystring.
1456: *
1457: * @param s QueryString to parse
1458: */
1459: private void parseQueryString(String s) {
1460: if (s == null)
1461: return;
1462: StringTokenizer st = new StringTokenizer(s, "&");
1463: while (st.hasMoreTokens()) {
1464: String valArray[];
1465: String pair = st.nextToken();
1466: int pos = pair.indexOf('=');
1467: if (pos == -1)
1468: continue;
1469: try {
1470: String key = com.tagtraum.framework.util.URLDecoder
1471: .decode(pair.substring(0, pos));
1472: String val = com.tagtraum.framework.util.URLDecoder
1473: .decode(pair.substring(pos + 1, pair.length()));
1474: if (formParameters.containsKey(key)) {
1475: String oldVals[] = (String[]) formParameters
1476: .get(key);
1477: valArray = new String[oldVals.length + 1];
1478: System.arraycopy(oldVals, 0, valArray, 0,
1479: oldVals.length);
1480: valArray[oldVals.length] = val;
1481: } else {
1482: valArray = new String[] { val };
1483: }
1484: formParameters.put(key, valArray);
1485: } catch (Exception e) {
1486: if (e instanceof IllegalArgumentException) {
1487: throw (IllegalArgumentException) e;
1488: }
1489: }
1490: }
1491: }
1492: }
|