001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2003 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.util;
021:
022: import java.text.DateFormat;
023: import java.text.ParseException;
024: import java.text.SimpleDateFormat;
025: import java.util.Date;
026:
027: import javax.servlet.http.Cookie;
028: import javax.servlet.http.HttpServletRequest;
029:
030: import org.apache.log4j.Logger;
031:
032: import com.ecyrd.jspwiki.WikiPage;
033:
034: /**
035: * Contains useful utilities for some common HTTP tasks.
036: *
037: * @author Janne Jalkanen
038: * @since 2.1.61.
039: */
040: public final class HttpUtil {
041: static Logger log = Logger.getLogger(HttpUtil.class);
042:
043: /**
044: * Private constructor to prevent direct instantiation.
045: */
046: private HttpUtil() {
047: }
048:
049: /**
050: * Attempts to retrieve the given cookie value from the request.
051: * Returns the string value (which may or may not be decoded
052: * correctly, depending on browser!), or null if the cookie is
053: * not found. The algorithm will automatically trim leading
054: * and trailing double quotes, if found.
055: *
056: * @param request The current request
057: * @param cookieName The name of the cookie to fetch.
058: * @return Value of the cookie, or null, if there is no such cookie.
059: */
060:
061: public static String retrieveCookieValue(
062: HttpServletRequest request, String cookieName) {
063: Cookie[] cookies = request.getCookies();
064:
065: if (cookies != null) {
066: for (int i = 0; i < cookies.length; i++) {
067: if (cookies[i].getName().equals(cookieName)) {
068: String value = cookies[i].getValue();
069: if (value.length() == 0) {
070: return null;
071: }
072: if (value.charAt(0) == '"'
073: && value.charAt(value.length() - 1) == '"') {
074: value = value.substring(1, value.length() - 1);
075: }
076: return value;
077: }
078: }
079: }
080:
081: return null;
082: }
083:
084: /**
085: * Creates an ETag based on page information. An ETag is unique to each page
086: * and version, so it can be used to check if the page has changed. Do not
087: * assume that the ETag is in any particular format.
088: *
089: * @param p The page for which the ETag should be created.
090: * @return A String depiction of an ETag.
091: */
092: public static String createETag(WikiPage p) {
093: return Long.toString(p.getName().hashCode()
094: ^ p.getLastModified().getTime());
095: }
096:
097: /**
098: * If returns true, then should return a 304 (HTTP_NOT_MODIFIED)
099: * @param req the HTTP request
100: * @param page the wiki page to check for
101: * @return the result of the check
102: */
103: public static boolean checkFor304(HttpServletRequest req,
104: WikiPage page) {
105: //
106: // We'll do some handling for CONDITIONAL GET (and return a 304)
107: // If the client has set the following headers, do not try for a 304.
108: //
109: // pragma: no-cache
110: // cache-control: no-cache
111: //
112:
113: if ("no-cache".equalsIgnoreCase(req.getHeader("Pragma"))
114: || "no-cache".equalsIgnoreCase(req
115: .getHeader("cache-control"))) {
116: // Wants specifically a fresh copy
117: } else {
118: //
119: // HTTP 1.1 ETags go first
120: //
121: String this Tag = createETag(page);
122:
123: String eTag = req.getHeader("If-None-Match");
124:
125: if (eTag != null) {
126: if (eTag.equals(this Tag)) {
127: return true;
128: }
129: }
130:
131: //
132: // Next, try if-modified-since
133: //
134: DateFormat rfcDateFormat = new SimpleDateFormat(
135: "EEE, dd MMM yyyy HH:mm:ss z");
136: Date lastModified = page.getLastModified();
137:
138: try {
139: long ifModifiedSince = req
140: .getDateHeader("If-Modified-Since");
141:
142: //log.info("ifModifiedSince:"+ifModifiedSince);
143: if (ifModifiedSince != -1) {
144: long lastModifiedTime = lastModified.getTime();
145:
146: //log.info("lastModifiedTime:" + lastModifiedTime);
147: if (lastModifiedTime <= ifModifiedSince) {
148: return true;
149: }
150: } else {
151: try {
152: String s = req.getHeader("If-Modified-Since");
153:
154: if (s != null) {
155: Date ifModifiedSinceDate = rfcDateFormat
156: .parse(s);
157: //log.info("ifModifiedSinceDate:" + ifModifiedSinceDate);
158: if (lastModified
159: .before(ifModifiedSinceDate)) {
160: return true;
161: }
162: }
163: } catch (ParseException e) {
164: log.warn(e.getLocalizedMessage(), e);
165: }
166: }
167: } catch (IllegalArgumentException e) {
168: // Illegal date/time header format.
169: // We fail quietly, and return false.
170: // FIXME: Should really move to ETags.
171: }
172: }
173:
174: return false;
175: }
176:
177: /**
178: * Attempts to form a valid URI based on the string given. Currently
179: * it can guess email addresses (mailto:). If nothing else is given,
180: * it assumes it to be a http:// url.
181: *
182: * @param uri URI to take a poke at
183: * @return Possibly a valid URI
184: * @since 2.2.8
185: */
186: public static String guessValidURI(String uri) {
187: if (uri.indexOf('@') != -1) {
188: if (!uri.startsWith("mailto:")) {
189: // Assume this is an email address
190:
191: uri = "mailto:" + uri;
192: }
193: } else if (uri.length() > 0
194: && !((uri.startsWith("http://") || uri
195: .startsWith("https://")))) {
196: uri = "http://" + uri;
197: }
198:
199: return uri;
200: }
201:
202: }
|