001: /*
002: * @(#)URLStreamHandler.java 1.53 05/03/12
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package com.sun.perseus.platform;
029:
030: /**
031: * The abstract class <code>URLStreamHandler</code> is the common
032: * superclass for all stream protocol handlers. A stream protocol
033: * handler knows how to make a connection for a particular protocol
034: * type, such as <code>http</code>.
035: * <p>
036: * In most cases, an instance of a <code>URLStreamHandler</code>
037: * subclass is not created directly by an application. Rather, the
038: * first time a protocol name is encountered when constructing a
039: * <code>URL</code>, the appropriate stream protocol handler is
040: * automatically loaded.
041: *
042: */
043: class PURLStreamHandler {
044:
045: /**
046: * Converts a <code>URL</code> of a specific protocol to a
047: * <code>String</code>.
048: *
049: * @param u the URL.
050: * @return a string representation of the <code>URL</code> argument.
051: */
052: protected static String toExternalForm(PURL u) {
053:
054: // pre-compute length of StringBuffer
055: int len = u.getProtocol().length() + 1;
056: if (u.getAuthority() != null && u.getAuthority().length() > 0)
057: len += 2 + u.getAuthority().length();
058: if (u.getPath() != null) {
059: len += u.getPath().length();
060: }
061: if (u.getQuery() != null) {
062: len += 1 + u.getQuery().length();
063: }
064: if (u.getRef() != null)
065: len += 1 + u.getRef().length();
066:
067: StringBuffer result = new StringBuffer(len);
068: result.append(u.getProtocol());
069: result.append(":");
070: if (u.getAuthority() != null && u.getAuthority().length() > 0) {
071: result.append("//");
072: result.append(u.getAuthority());
073: }
074: if (u.getPath() != null) {
075: result.append(u.getPath());
076: }
077: if (u.getQuery() != null) {
078: result.append('?');
079: result.append(u.getQuery());
080: }
081: if (u.getRef() != null) {
082: result.append("#");
083: result.append(u.getRef());
084: }
085: return result.toString();
086: }
087:
088: /**
089: * Sets the fields of the <code>URL</code> argument to the indicated values.
090: * Only classes derived from URLStreamHandler are supposed to be able
091: * to call the set method on a URL.
092: *
093: * @param u the URL to modify.
094: * @param protocol the protocol name.
095: * @param host the remote host value for the URL.
096: * @param port the port on the remote machine.
097: * @param authority the authority part for the URL.
098: * @param userInfo the userInfo part of the URL.
099: * @param path the path component of the URL.
100: * @param query the query part for the URL.
101: * @param ref the reference.
102: * @exception SecurityException if the protocol handler of the URL is
103: * different from this one
104: * @see java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
105: */
106: protected static void setURL(PURL u, String protocol, String host,
107: int port, String authority, String userInfo, String path,
108: String query, String ref) {
109:
110: // ensure that no one can reset the protocol on a given URL.
111: u.set(u.getProtocol(), host, port, authority, userInfo, path,
112: query, ref);
113: }
114:
115: /**
116: * Parses the string representation of a <code>URL</code> into a
117: * <code>URL</code> object.
118: * <p>
119: * If there is any inherited context, then it has already been
120: * copied into the <code>URL</code> argument.
121: * <p>
122: * The <code>parseURL</code> method of <code>URLStreamHandler</code>
123: * parses the string representation as if it were an
124: * <code>http</code> specification. Most URL protocol families have a
125: * similar parsing. A stream protocol handler for a protocol that has
126: * a different syntax must override this routine.
127: *
128: * @param u the <code>URL</code> to receive the result of parsing
129: * the spec.
130: * @param spec the <code>String</code> representing the URL that
131: * must be parsed.
132: * @param start the character index at which to begin parsing. This is
133: * just past the '<code>:</code>' (if there is one) that
134: * specifies the determination of the protocol name.
135: * @param limit the character position to stop parsing at. This is the
136: * end of the string or the position of the
137: * "<code>#</code>" character, if present. All information
138: * after the sharp sign indicates an anchor.
139: */
140: public static void parseURL(PURL u, String spec, int start,
141: int limit) {
142: // These fields may receive context content if this was relative URL
143: String protocol = u.getProtocol();
144: String authority = u.getAuthority();
145: String userInfo = u.getUserInfo();
146: String host = u.getHost();
147: int port = u.getPort();
148: String path = u.getPath();
149: String query = u.getQuery();
150:
151: // This field has already been parsed
152: String ref = u.getRef();
153:
154: boolean isRelPath = false;
155: boolean queryOnly = false;
156:
157: // FIX: should not assume query if opaque
158: // Strip off the query part
159: if (start < limit) {
160: int queryStart = spec.indexOf('?');
161: queryOnly = queryStart == start;
162: if ((queryStart != -1) && (queryStart < limit)) {
163: query = spec.substring(queryStart + 1, limit);
164: if (limit > queryStart)
165: limit = queryStart;
166: spec = spec.substring(0, queryStart);
167: }
168: }
169:
170: int i = 0;
171: // Parse the authority part if any
172: if ((start <= limit - 2) && (spec.charAt(start) == '/')
173: && (spec.charAt(start + 1) == '/')) {
174: start += 2;
175: i = spec.indexOf('/', start);
176: if (i < 0) {
177: i = spec.indexOf('?', start);
178: if (i < 0)
179: i = limit;
180: }
181:
182: host = authority = spec.substring(start, i);
183:
184: int ind = authority.indexOf('@');
185: if (ind != -1) {
186: userInfo = authority.substring(0, ind);
187: host = authority.substring(ind + 1);
188: } else {
189: userInfo = null;
190: }
191: if (host != null) {
192: // If the host is surrounded by [ and ] then its an IPv6
193: // literal address as specified in RFC2732
194: if (host.length() > 0 && (host.charAt(0) == '[')) {
195: //PURLStreamHandler has been modified - it does not
196: //handle IPV6 addresses
197: //this is an ipv6 address
198:
199: throw new Error("Can't handle IPv6 addresses!");
200:
201: } else {
202: ind = host.indexOf(':');
203: port = -1;
204: if (ind >= 0) {
205: // port can be null according to RFC2396
206: if (host.length() > (ind + 1)) {
207: port = Integer.parseInt(host
208: .substring(ind + 1));
209: }
210: host = host.substring(0, ind);
211: }
212: }
213: } else {
214: host = "";
215: }
216: if (port < -1)
217: throw new IllegalArgumentException(
218: "Invalid port number :" + port);
219: start = i;
220: // If the authority is defined then the path is defined by the
221: // spec only; See RFC 2396 Section 5.2.4.
222: if (authority != null && authority.length() > 0)
223: path = "";
224: }
225:
226: if (host == null) {
227: host = "";
228: }
229:
230: // Parse the file path if any
231: if (start < limit) {
232: if (spec.charAt(start) == '/') {
233: path = spec.substring(start, limit);
234: } else if (path != null && path.length() > 0) {
235: isRelPath = true;
236: int ind = path.lastIndexOf('/');
237: String seperator = "";
238: if (ind == -1 && authority != null)
239: seperator = "/";
240: path = path.substring(0, ind + 1) + seperator
241: + spec.substring(start, limit);
242:
243: } else {
244: String seperator = (authority != null) ? "/" : "";
245: path = seperator + spec.substring(start, limit);
246: }
247: } else if (queryOnly && path != null) {
248: int ind = path.lastIndexOf('/');
249: if (ind < 0)
250: ind = 0;
251: path = path.substring(0, ind) + "/";
252: }
253: if (path == null)
254: path = "";
255:
256: if (isRelPath) {
257: // Remove embedded /./
258: while ((i = path.indexOf("/./")) >= 0) {
259: path = path.substring(0, i) + path.substring(i + 2);
260: }
261: // Remove embedded /../ if possible
262: i = 0;
263: while ((i = path.indexOf("/../", i)) > 0) {
264: if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
265: path = path.substring(0, limit)
266: + path.substring(i + 3);
267: i = 0;
268: } else {
269: i = i + 3;
270: }
271: }
272: // Remove trailing .. if possible
273: while (path.endsWith("/..")) {
274: i = path.indexOf("/..");
275: if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
276: path = path.substring(0, limit + 1);
277: } else {
278: break;
279: }
280: }
281: // Remove starting .
282: if (path.startsWith("./") && path.length() > 2)
283: path = path.substring(2);
284:
285: // Remove trailing .
286: if (path.endsWith("/."))
287: path = path.substring(0, path.length() - 1);
288: }
289:
290: setURL(u, protocol, host, port, authority, userInfo, path,
291: query, ref);
292: }
293:
294: }
|