001: /* Copyright 2002 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.utils;
007:
008: import org.jasig.portal.PortalException;
009: import org.xml.sax.Attributes;
010: import org.xml.sax.ContentHandler;
011: import org.xml.sax.helpers.AttributesImpl;
012:
013: /**
014: * <p>Replaces all relative URLs with absolute URLs.</p>
015: * @author Ken Weiner, kweiner@unicon.net
016: * @version $Revision: 34793 $
017: */
018: public abstract class AbsoluteURLFilter extends SAX2FilterImpl {
019:
020: protected String baseUrl = null;
021:
022: /**
023: * A constructor which receives a ContentHandler to which
024: * filtered SAX events are passed
025: * @param handler the ContentHandler to which filtered SAX events are passed
026: */
027: protected AbsoluteURLFilter(ContentHandler handler) {
028: super (handler);
029: }
030:
031: /**
032: * A factory method that uses a mime type to decide which kind of
033: * AbsoluteURLFilter to instantiate. There are currently two types
034: * of markup supported: XHTML and WML.
035: * @param mimeType the mime type of the markup that this filter will apply to
036: * @param baseUrl the base URL to be prepended to relative URL paths
037: * @param handler the ContentHandler to which to pass along filtered SAX events
038: * @return filter the AbsoluteURLFilter matching the mimeType
039: */
040: public static final AbsoluteURLFilter newAbsoluteURLFilter(
041: String mimeType, String baseUrl, ContentHandler handler)
042: throws PortalException {
043: AbsoluteURLFilter filter = null;
044:
045: if (mimeType != null) {
046: if (mimeType.equals("text/html")) {
047: filter = new XHTMLURLFilter(handler);
048: } else if (mimeType.equals("text/vnd.wap.wml")) {
049: filter = new WMLURLFilter(handler);
050: } else {
051: throw new PortalException(
052: "AbsoluteURLFilter.newAbsoluteURLFilter(): Unable to locate AbsoluteURLFilter for mime type '"
053: + mimeType + "'");
054: }
055: } else {
056: throw new PortalException(
057: "AbsoluteURLFilter.newAbsoluteURLFilter(): Unable to create AbsoluteURLFilter. Mime type is null.");
058: }
059:
060: filter.baseUrl = baseUrl;
061:
062: return filter;
063: }
064:
065: /**
066: * Sets the base URL.
067: * @param url the new base URL
068: */
069: protected void setBaseUrl(String url) {
070: if (url != null)
071: this .baseUrl = url;
072: }
073:
074: /**
075: * A helper method for derivitive classes to easily fix an attribute
076: * that has a relative URL value
077: * @param elementName the element name containing an attribute of name attName
078: * @param attName the name of the attribute of elementName
079: * @param qName the name of the current element
080: * @param atts the attibutes of the current element
081: * @param attsImpl the attributes implementation to contain the new attribute value
082: */
083: protected final void fixURL(String elementName, String attName,
084: String qName, Attributes atts, AttributesImpl attsImpl) {
085: if (qName.equalsIgnoreCase(elementName)) {
086: String attValue = atts.getValue(attName);
087: if (attValue != null) {
088: // Assume that if the attribute value exists and doesn't contain a
089: // colon, or if the URL contains a colon and there's a
090: // slash before the first colon, then it is a relative URL
091: // (http://<something> and mailto:<something> are both valid,
092: // absolute URLs)
093: int i = attValue.indexOf(":");
094: if (i == -1
095: || (i != -1 && attValue.substring(0, i)
096: .indexOf("/") != -1)) {
097: i = baseUrl.indexOf("://");
098: int i2 = baseUrl.indexOf("/", i + 3);
099: if (attValue.startsWith("/")) {
100: // Prepend the scheme and the host to the attribute value (HTTP)
101: if (i != -1) {
102: if (i2 != -1)
103: attValue = baseUrl.substring(0, i2)
104: .concat(attValue);
105: else
106: attValue = baseUrl.concat(attValue);
107: }
108: } else if (attValue.trim().equals(""))
109: attValue = baseUrl;
110: else if (attValue.trim().startsWith("?")
111: || attValue.trim().startsWith("#"))
112: attValue = baseUrl.concat(attValue);
113: else {
114: if (i2 != -1) {
115: if (baseUrl.indexOf("?") != -1)
116: attValue = baseUrl.substring(
117: 0,
118: baseUrl.substring(0,
119: baseUrl.indexOf("?"))
120: .lastIndexOf("/") + 1)
121: .concat(attValue);
122: else
123: attValue = baseUrl.substring(0,
124: baseUrl.lastIndexOf("/") + 1)
125: .concat(attValue);
126: } else
127: attValue = baseUrl.concat("/").concat(
128: attValue);
129: }
130:
131: if (attValue.indexOf("/../") != -1)
132: attValue = removeUpDirs(attValue);
133: }
134:
135: int index = atts.getIndex(attName);
136: attsImpl.setAttribute(index, atts.getURI(index), atts
137: .getLocalName(index), attName, atts
138: .getType(index), attValue);
139: }
140: }
141: }
142:
143: /**
144: * Removes the '/../' in the URL. Some browsers and web
145: * servers do not handle these URLs correctly.
146: * @param url the absolute URL generated from the fixURL method
147: */
148: private String removeUpDirs(String url) {
149: String begin;
150: String end;
151: int upDirIndex;
152: int endProtoIndex = url.indexOf("//");
153:
154: while ((upDirIndex = url.indexOf("/../")) != -1) {
155: end = url.substring(upDirIndex + 4);
156: begin = url.substring(0, upDirIndex);
157:
158: if (begin.indexOf("/", endProtoIndex + 2) != -1)
159: begin = url.substring(0, begin.lastIndexOf("/") + 1);
160: else
161: begin += "/";
162:
163: url = begin.concat(end);
164: }
165:
166: return url;
167: }
168: }
|