001: /*
002: Copyright (c) 2003 eInnovation Inc. All rights reserved
003:
004: This library is free software; you can redistribute it and/or modify it under the terms
005: of the GNU Lesser General Public License as published by the Free Software Foundation;
006: either version 2.1 of the License, or (at your option) any later version.
007:
008: This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
009: without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: See the GNU Lesser General Public License for more details.
011: */
012:
013: /*--
014:
015: Copyright (C) 2001-2002 Anthony Eden.
016: All rights reserved.
017:
018: Redistribution and use in source and binary forms, with or without
019: modification, are permitted provided that the following conditions
020: are met:
021:
022: 1. Redistributions of source code must retain the above copyright
023: notice, this list of conditions, and the following disclaimer.
024:
025: 2. Redistributions in binary form must reproduce the above copyright
026: notice, this list of conditions, and the disclaimer that follows
027: these conditions in the documentation and/or other materials
028: provided with the distribution.
029:
030: 3. The name "JPublish" must not be used to endorse or promote products
031: derived from this software without prior written permission. For
032: written permission, please contact me@anthonyeden.com.
033:
034: 4. Products derived from this software may not be called "JPublish", nor
035: may "JPublish" appear in their name, without prior written permission
036: from Anthony Eden (me@anthonyeden.com).
037:
038: In addition, I request (but do not require) that you include in the
039: end-user documentation provided with the redistribution and/or in the
040: software itself an acknowledgement equivalent to the following:
041: "This product includes software developed by
042: Anthony Eden (http://www.anthonyeden.com/)."
043:
044: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
045: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
046: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
047: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
048: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
049: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
050: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
051: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
052: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
053: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
054: POSSIBILITY OF SUCH DAMAGE.
055:
056: For more information on JPublish, please see <http://www.jpublish.org/>.
057:
058: */
059: package com.openedit.util;
060:
061: import java.io.UnsupportedEncodingException;
062: import java.net.URLDecoder;
063: import java.net.URLEncoder;
064:
065: import javax.servlet.http.HttpServletRequest;
066: import javax.servlet.http.HttpServletResponse;
067:
068: import org.apache.commons.logging.Log;
069: import org.apache.commons.logging.LogFactory;
070:
071: /**
072: * Utility class for building URLs.
073: *
074: * @author Anthony Eden
075: */
076: public class URLUtilities {
077: /** The URL path separator. */
078: public static final String URL_PATH_SEPARATOR = "/";
079: private static Log log = LogFactory.getLog(URLUtilities.class);
080:
081: /**
082: * Construct a new URLUtilities class which can use the given request and response objects to
083: * build URLs.
084: */
085: private HttpServletRequest fieldRequest;
086: private HttpServletResponse fieldResponse;
087:
088: public URLUtilities(HttpServletRequest request,
089: HttpServletResponse response) {
090: this .fieldRequest = request;
091: this .fieldResponse = response;
092: }
093:
094: /**
095: * The only non-buggy way to get a file name is to look at the full URL then chop off the
096: * context to make it a relative URL
097: *
098: * @return /index.html
099: */
100: public static String getPathWithoutContext(String inContext,
101: String fullpath, String inDefault) {
102: String nameOnly = fullpath;
103: if (fullpath.startsWith(inContext)) {
104: nameOnly = fullpath.substring(inContext.length());
105: }
106:
107: if (nameOnly.equals("/") || (nameOnly.length() == 0)) {
108: nameOnly += inDefault;
109: } else if (nameOnly.indexOf('.') == -1) {
110: if (!nameOnly.endsWith("/")) {
111: nameOnly += '/';
112: }
113: nameOnly += inDefault;
114: }
115:
116: return nameOnly;
117: }
118:
119: /**
120: * This includes the webapp name but not the page name
121: *
122: * @return http://www.acme.com/webapp/
123: */
124: public String buildBasePath(String path) {
125: StringBuffer ctx = fieldRequest.getRequestURL();
126: String servername = ctx.substring(0, ctx.indexOf("/", 7)); //just the server name
127:
128: if (path.lastIndexOf('/') > -1) {
129: path = path.substring(0, path.lastIndexOf('/'));
130:
131: return servername + path + "/";
132: } else {
133: return servername + "/";
134: }
135: }
136:
137: /**
138: * This is the server name only
139: *
140: * returns http://www.acme.com/
141: */
142: public String buildRoot() {
143: StringBuffer ctx = fieldRequest.getRequestURL();
144: String servername = ctx.substring(0, ctx.indexOf("/", 7));
145:
146: return servername + "/";
147: }
148:
149: /**
150: * Build an HTTPS (Secure Socket Layer) method relative to the application context using the
151: * given path.
152: *
153: */
154: public String buildSecure(String path) {
155: return buildSecure(path, 0);
156: }
157:
158: /**
159: * Build an HTTPS (Secure Socket Layer) method relative to the application context using the
160: * given path. This version of the <code>buildSecure</code> method allows you to specify the
161: * port number. A port number of 0 will cause the port argument to be ignored.
162: *
163: * @param path The path
164: * @param port The port
165: *
166: * @return DOCME
167: */
168: public String buildSecure(String path, int port) {
169: return build(path, "https", port);
170: }
171:
172: /**
173: * Build an HTTP URL relative to the application context using the given path.
174: *
175: * @param path The path
176: *
177: * @return DOCME
178: */
179: public String buildStandard(String path) {
180: return buildStandard(path, 0);
181: }
182:
183: /**
184: * Build an HTTP URL relative to the application context using the given path. This version
185: * of the <code>buildStandard</code> method allows you to specify the port number. A port
186: * number of 0 will cause the port argument to be ignored.
187: *
188: * @param path The path
189: * @param port The port
190: *
191: * @return DOCME
192: */
193: public String buildStandard(String path, int port) {
194: return build(path, "http", port);
195: }
196:
197: /**
198: * Percent-encode the given String. This method delegates to the URLEncoder.encode() method.
199: *
200: * @param s The String to encode
201: *
202: * @return The encoded String
203: *
204: * @see java.net.URLEncoder
205: */
206: public String encode(String s) {
207: if (s == null) {
208: return null;
209: }
210:
211: return URLEncoder.encode(s);
212: }
213:
214: /**
215: * Build an HTTP URL relative to the application context using the given path. This is a path
216: * such as /path/myfile.html but is encoded
217: * If you want to unencoded path use $content.path or getOriginalPath()
218: *
219: * @return /webapp/path/myfile.html
220: */
221: public String getOriginalUrl() {
222: String path = fieldRequest.getRequestURI();
223: String home = relativeHomePrefix();
224: path = path.substring(home.length());
225: return encode(path);
226: }
227:
228: /**
229: * This is the path that the browser is on.
230: * /sub/index page.html
231: * @return
232: */
233: public String getOriginalPath() {
234: String requestedPath = getRequest().getRequestURI();
235: try {
236: requestedPath = URLDecoder.decode(requestedPath, "UTF-8");
237: } catch (UnsupportedEncodingException ex) {
238: log.error(ex);
239: }
240:
241: String contextPath = getRequest().getContextPath();
242: if (requestedPath.startsWith(contextPath)) {
243: requestedPath = requestedPath.substring(contextPath
244: .length());
245: }
246: return requestedPath;
247: }
248:
249: /**
250: * Build an HTTP URL relative to the application context using the given path. This is a path
251: * such as http://servername/webapp/path/myfile.html
252: *
253: * @return /webapp/path/myfile.html
254: */
255: public String requestPath() {
256: StringBuffer ctx = fieldRequest.getRequestURL();
257: String requestPath = ctx.substring(ctx.indexOf("/", 7)); //just the path
258:
259: return requestPath;
260: }
261:
262: /**
263: * Is the full path with arguments included
264: * /webappname/sub/index.html?test=1234
265: */
266:
267: public String requestPathWithArguments() {
268: String path = fieldRequest.getRequestURI();
269: if (fieldRequest.getQueryString() != null
270: && fieldRequest.getQueryString().length() > 0) {
271: path = path + "?" + fieldRequest.getQueryString();
272: }
273: return path;
274: }
275:
276: /**
277: * Is the full path with arguments included
278: * /sub/index.html?test=1234
279: */
280:
281: public String requestPathWithArgumentsNoContext() {
282: String path = fieldRequest.getRequestURI();
283: if (fieldRequest.getQueryString() != null
284: && fieldRequest.getQueryString().length() > 0) {
285: path = path + "?" + fieldRequest.getQueryString();
286: }
287: String home = relativeHomePrefix();
288: path = path.substring(home.length());
289: return path;
290: }
291:
292: /**
293: * Report the site name, e.g. http://www.openeditpro.com
294: *
295: * @return The site's root URL
296: */
297: public String siteRoot() {
298: StringBuffer ctx = fieldRequest.getRequestURL();
299: String siteRoot = ctx.substring(0, ctx.indexOf("/", 8)); //8 comes from https://
300: return siteRoot;
301: }
302:
303: public static String xmlEscapeWithWrap(String inStr) {
304: return xmlEscapeWithWrap(inStr, 100);
305: }
306:
307: public static String xmlEscapeWithWrap(String inStr, int inWrap) {
308: if (inStr == null) {
309: return null;
310: }
311: String inCode = xmlEscape(inStr);
312: int LINE_LENGTH = inWrap;
313: StringBuffer sb = new StringBuffer();
314: int linecount = 0;
315: boolean nextSpace = false;
316:
317: for (int n = 0; n < inCode.length(); n++) {
318: char c = inCode.charAt(n);
319: linecount++;
320: if (linecount > LINE_LENGTH) {
321: nextSpace = true;
322: }
323:
324: switch (c) {
325: case '\n': {
326: sb.append("\n");
327: linecount = 0;
328: nextSpace = false;
329: break;
330: }
331: case '\r': {
332: break;
333: }
334: default:
335: if (nextSpace && c == ' ') {
336: sb.append("\n");
337: nextSpace = false;
338: linecount = 0;
339: }
340: sb.append(c);
341: }
342: }
343: return sb.toString();
344: }
345:
346: /**
347: * A simple hack to escape XML, stolen from Jakarta commons XmlUtils
348: *
349: * @param inStr
350: *
351: * @return String
352: */
353: public static String xmlEscape(String inStr) {
354: if (inStr == null) {
355: return null;
356: }
357: //can you just blindly replace any & since it might be part of '?
358: inStr = inStr.replaceAll("&", "&");
359:
360: inStr = inStr.replaceAll("<", "<");
361: inStr = inStr.replaceAll(">", ">");
362: inStr = inStr.replaceAll("\"", """);
363:
364: //IE seems to espace the & for some reason inStr = inStr.replaceAll("'", "'");
365: return inStr;
366: }
367:
368: public static String xmlUnescape(String inStr) {
369: if (inStr == null) {
370: return null;
371: }
372: //can you just blindly replace any & since it might be part of '?
373: inStr = inStr.replaceAll("&", "&");
374:
375: inStr = inStr.replaceAll("<", "<");
376: inStr = inStr.replaceAll(">", ">");
377: inStr = inStr.replaceAll(""", "\"");
378:
379: //IE seems to espace the & for some reason inStr = inStr.replaceAll("'", "'");
380: return inStr;
381: }
382:
383: /**
384: * If I am located in /webapp/demo/test.html my prefix would be /demo/ to get back to the base
385: * /webapp level
386: *
387: * The rule is you can tack on $home + "/somepage.html" without getting //somepage.html
388: *
389: *
390: * @return Object
391: */
392: public String relativeHomePrefix() {
393: String rootdir = fieldRequest.getContextPath();
394:
395: if ((rootdir != null) && (rootdir.length() > 0)) {
396: if (rootdir.endsWith("/")) {
397: rootdir = rootdir.substring(0, rootdir.length() - 1);
398: }
399: return rootdir;
400: } else {
401: return "";
402: }
403:
404: }
405:
406: /**
407: * Build a URL using the given path, protocol and port. The path will be relative to the
408: * current context.
409: *
410: * @param path The path
411: * @param protocol (i.e. http or https)
412: * @param port The port (0 to ignore the port argument)
413: *
414: * @return The URL as a String
415: */
416: protected String build(String path, String protocol, int port) {
417: String serverName = fieldRequest.getServerName();
418: String contextPath = fieldRequest.getContextPath();
419:
420: log.debug("Server name: " + serverName);
421: log.debug("Context path: " + contextPath);
422:
423: if (!contextPath.endsWith(URL_PATH_SEPARATOR)) {
424: contextPath = contextPath + URL_PATH_SEPARATOR;
425: }
426:
427: if (path.startsWith(URL_PATH_SEPARATOR)) {
428: path = path.substring(1);
429: }
430:
431: String requestPath = contextPath + path;
432: log.debug("Request path: " + requestPath);
433:
434: StringBuffer buffer = new StringBuffer();
435: buffer.append(protocol);
436: buffer.append("://");
437: buffer.append(serverName);
438:
439: int realPort = fieldRequest.getServerPort();
440:
441: if (port > 0) {
442: realPort = port;
443: }
444:
445: if ((realPort > 0)
446: && !((protocol.equals("http") && (realPort == 80)) || (protocol
447: .equals("https") && (realPort == 443)))) {
448: buffer.append(":");
449: buffer.append(realPort);
450: }
451:
452: if (!requestPath.startsWith(URL_PATH_SEPARATOR)) {
453: buffer.append(URL_PATH_SEPARATOR);
454: }
455:
456: buffer.append(requestPath);
457:
458: log.debug("URL: '" + buffer + "'");
459:
460: return buffer.toString();
461: }
462:
463: public PathUtilities getPathUtilities() {
464: return new PathUtilities();
465: }
466:
467: public HttpServletResponse getResponse() {
468: return fieldResponse;
469: }
470:
471: public void setResponse(HttpServletResponse inResponse) {
472: fieldResponse = inResponse;
473: }
474:
475: public HttpServletRequest getRequest() {
476: return fieldRequest;
477: }
478:
479: public void setRequest(HttpServletRequest inRequest) {
480: fieldRequest = inRequest;
481: }
482: }
|