001: /*
002: * ========================================================================
003: *
004: * Copyright 2001-2003 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: * ========================================================================
019: */
020: package org.apache.cactus.internal.util;
021:
022: import java.net.URL;
023: import java.util.Vector;
024:
025: import org.apache.cactus.Cookie;
026: import org.apache.cactus.ServletURL;
027: import org.apache.cactus.WebRequest;
028: import org.apache.cactus.internal.client.ClientException;
029: import org.apache.commons.httpclient.Header;
030: import org.apache.commons.httpclient.cookie.CookiePolicy;
031: import org.apache.commons.httpclient.cookie.CookieSpec;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034:
035: /**
036: * Utility methods to manipulate cookies and transform Cactus cookie objects
037: * to HttpClient cookie objects.
038: *
039: * @version $Id: CookieUtil.java 238991 2004-05-22 11:34:50Z vmassol $
040: * @since 1.5
041: */
042: public class CookieUtil {
043: /**
044: * The logger
045: */
046: private static final Log LOGGER = LogFactory
047: .getLog(CookieUtil.class);
048:
049: /**
050: * Returns the domain that will be used to send the cookies. If a host
051: * was specified using <code>setURL()</code> then the domain will be
052: * this host. Otherwise it will be the real redirector host.
053: *
054: * @param theRequest the request containing all data to pass to the server
055: * redirector.
056: * @param theRealHost the real host to which we are connecting to. We will
057: * use it if no simulation host has been specified.
058: * @return the cookie domain to use
059: */
060: public static String getCookieDomain(WebRequest theRequest,
061: String theRealHost) {
062: String domain;
063: ServletURL url = theRequest.getURL();
064:
065: if ((url != null) && (url.getHost() != null)) {
066: domain = url.getHost();
067: } else {
068: domain = theRealHost;
069: }
070:
071: LOGGER.debug("Cookie validation domain = [" + domain + "]");
072:
073: return domain;
074: }
075:
076: /**
077: * Returns the port that will be used to send the cookies. If a port
078: * was specified using <code>setURL()</code> then the port sent will be
079: * this port. Otherwise it will be the real redirector port.
080: *
081: * @param theRequest the request containing all data to pass to the server
082: * redirector.
083: * @param theRealPort the real port to which we are connecting to. We will
084: * use it if no simulation port has been specified.
085: * @return the cookie domain to use
086: */
087: public static int getCookiePort(WebRequest theRequest,
088: int theRealPort) {
089: int port;
090: ServletURL url = theRequest.getURL();
091:
092: if ((url != null) && (url.getHost() != null)) {
093: port = url.getPort();
094: } else {
095: port = theRealPort;
096: }
097:
098: LOGGER.debug("Cookie validation port = [" + port + "]");
099:
100: return port;
101: }
102:
103: /**
104: * Returns the path that will be used to validate if a cookie will be
105: * sent or not. The algorithm is as follows : if the cookie path is not
106: * set (i.e. null) then the cookie is always sent (provided the domain
107: * is right). If the cookie path is set, the cookie is sent only if
108: * the request path starts with the same string as the cookie path. If
109: * <code>setURL()</code> has been called, return the path it has been
110: * set to (context + servletPath + pathInfo). Otherwise return the
111: * real redirector path.
112: *
113: * @param theRequest the request containing all data to pass to the server
114: * redirector.
115: * @param theRealPath the real path to which we are connecting to. We will
116: * use it if no simulation path has been specified.
117: * @return the path to use to decide if a cookie will get sent
118: */
119: public static String getCookiePath(WebRequest theRequest,
120: String theRealPath) {
121: String path;
122: ServletURL url = theRequest.getURL();
123:
124: if ((url != null) && (url.getPath() != null)) {
125: path = url.getPath();
126: } else {
127: String file = theRealPath;
128:
129: if (file != null) {
130: int q = file.lastIndexOf('?');
131:
132: if (q != -1) {
133: path = file.substring(0, q);
134: } else {
135: path = file;
136: }
137: } else {
138: path = null;
139: }
140: }
141:
142: LOGGER.debug("Cookie validation path = [" + path + "]");
143:
144: return path;
145: }
146:
147: /**
148: * Create a Commons-HttpClient cookie from a Cactus cookie, with information
149: * from the web request and the URL.
150: *
151: * @param theRequest The request
152: * @param theUrl The URL
153: * @param theCactusCookie The Cactus Cookie object
154: * @return The HttpClient cookie
155: */
156: public static org.apache.commons.httpclient.Cookie createHttpClientCookie(
157: WebRequest theRequest, URL theUrl, Cookie theCactusCookie) {
158: // If no domain has been specified, use a default one
159: String domain;
160: if (theCactusCookie.getDomain() == null) {
161: domain = CookieUtil.getCookieDomain(theRequest, theUrl
162: .getHost());
163: } else {
164: domain = theCactusCookie.getDomain();
165: }
166:
167: // If not path has been specified , use a default one
168: String path;
169: if (theCactusCookie.getPath() == null) {
170: path = CookieUtil.getCookiePath(theRequest, theUrl
171: .getFile());
172: } else {
173: path = theCactusCookie.getPath();
174: }
175:
176: // Assemble the HttpClient cookie
177: org.apache.commons.httpclient.Cookie httpclientCookie = new org.apache.commons.httpclient.Cookie(
178: domain, theCactusCookie.getName(), theCactusCookie
179: .getValue());
180: httpclientCookie.setComment(theCactusCookie.getComment());
181: httpclientCookie.setExpiryDate(theCactusCookie.getExpiryDate());
182: httpclientCookie.setPath(path);
183: httpclientCookie.setSecure(theCactusCookie.isSecure());
184:
185: return httpclientCookie;
186: }
187:
188: /**
189: * Transforms an array of Cactus cookies into an array of Commons-HttpClient
190: * cookies, using information from the request and URL.
191: *
192: * @param theRequest The request
193: * @param theUrl The URL
194: * @return The array of HttpClient cookies
195: */
196: public static org.apache.commons.httpclient.Cookie[] createHttpClientCookies(
197: WebRequest theRequest, URL theUrl) {
198: Vector cactusCookies = theRequest.getCookies();
199:
200: // transform the Cactus cookies into HttpClient cookies
201: org.apache.commons.httpclient.Cookie[] httpclientCookies = new org.apache.commons.httpclient.Cookie[cactusCookies
202: .size()];
203:
204: for (int i = 0; i < cactusCookies.size(); i++) {
205: Cookie cactusCookie = (Cookie) cactusCookies.elementAt(i);
206: httpclientCookies[i] = CookieUtil.createHttpClientCookie(
207: theRequest, theUrl, cactusCookie);
208: }
209:
210: return httpclientCookies;
211: }
212:
213: /**
214: * Create a HttpClient {@link Header} for cookies that matches
215: * the domain and path.
216: *
217: * @param theDomain the cookie domain to match
218: * @param thePath the cookie path to match
219: * @param theCookies the list of potential cookies
220: * @return the HttpClient {@link Header} containing the matching
221: * cookies
222: * @throws ClientException if no cookie was matching the domain
223: * and path
224: */
225: public static Header createCookieHeader(String theDomain,
226: String thePath,
227: org.apache.commons.httpclient.Cookie[] theCookies)
228: throws ClientException {
229: Header cookieHeader = null;
230:
231: // separate domain into host and port
232: int port = 80;
233: String host = theDomain;
234: int portIndex = theDomain.indexOf(":");
235: if (portIndex != -1) {
236: host = host.substring(0, portIndex);
237: port = Integer.parseInt(theDomain.substring(portIndex + 1));
238: }
239:
240: CookieSpec matcher = CookiePolicy.getDefaultSpec();
241: org.apache.commons.httpclient.Cookie[] cookies = matcher.match(
242: host, port, thePath, false, theCookies);
243: if ((cookies != null) && (cookies.length > 0)) {
244: cookieHeader = matcher.formatCookieHeader(cookies);
245: }
246:
247: if (cookieHeader == null) {
248: throw new ClientException(
249: "Failed to create Cookie header for ["
250: + "domain = ["
251: + theDomain
252: + ", path = ["
253: + thePath
254: + ", cookies = ["
255: + theCookies
256: + "]]. Turn on HttpClient "
257: + "logging for more information about the error");
258: }
259:
260: return cookieHeader;
261: }
262:
263: /**
264: * @return the cookie string which will be added as a HTTP "Cookie" header
265: * or null if no cookie has been set
266: * @param theRequest the request containing all data to pass to the server
267: * redirector.
268: * @param theUrl the URL to connect to
269: * @throws ClientException if an error occurred when creating the cookie
270: * string
271: */
272: public static String getCookieString(WebRequest theRequest,
273: URL theUrl) throws ClientException {
274: // If no Cookies, then exit
275: Vector cookies = theRequest.getCookies();
276:
277: if (!cookies.isEmpty()) {
278: // transform the Cactus cookies into HttpClient cookies
279: org.apache.commons.httpclient.Cookie[] httpclientCookies = CookieUtil
280: .createHttpClientCookies(theRequest, theUrl);
281:
282: // and create the cookie header to send
283: Header cookieHeader = createCookieHeader(CookieUtil
284: .getCookieDomain(theRequest, theUrl.getHost()),
285: CookieUtil.getCookiePath(theRequest, theUrl
286: .getFile()), httpclientCookies);
287:
288: return cookieHeader.getValue();
289: }
290:
291: return null;
292: }
293: }
|