2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / java / net / URLStreamHandler.java
blobec2512974539f6c29f5f3c4f1b1b8382cbecdd04
1 /* URLStreamHandler.java -- Abstract superclass for all protocol handlers
2 Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.net;
41 import java.io.IOException;
42 import java.io.File;
45 * Written using on-line Java Platform 1.2 API Specification, as well
46 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
47 * Status: Believed complete and correct.
50 /**
51 * This class is the superclass of all URL protocol handlers. The URL
52 * class loads the appropriate protocol handler to establish a connection
53 * to a (possibly) remote service (eg, "http", "ftp") and to do protocol
54 * specific parsing of URL's. Refer to the URL class documentation for
55 * details on how that class locates and loads protocol handlers.
56 * <p>
57 * A protocol handler implementation should override the openConnection()
58 * method, and optionally override the parseURL() and toExternalForm()
59 * methods if necessary. (The default implementations will parse/write all
60 * URL's in the same form as http URL's). A protocol specific subclass
61 * of URLConnection will most likely need to be created as well.
62 * <p>
63 * Note that the instance methods in this class are called as if they
64 * were static methods. That is, a URL object to act on is passed with
65 * every call rather than the caller assuming the URL is stored in an
66 * instance variable of the "this" object.
67 * <p>
68 * The methods in this class are protected and accessible only to subclasses.
69 * URLStreamConnection objects are intended for use by the URL class only,
70 * not by other classes (unless those classes are implementing protocols).
72 * @author Aaron M. Renn (arenn@urbanophile.com)
73 * @author Warren Levy (warrenl@cygnus.com)
75 * @see URL
77 public abstract class URLStreamHandler
79 /**
80 * Creates a URLStreamHander
82 public URLStreamHandler ()
86 /**
87 * Returns a URLConnection for the passed in URL. Note that this should
88 * not actually create the connection to the (possibly) remote host, but
89 * rather simply return a URLConnection object. The connect() method of
90 * URL connection is used to establish the actual connection, possibly
91 * after the caller sets up various connection options.
93 * @param url The URL to get a connection object for
95 * @return A URLConnection object for the given URL
97 * @exception IOException If an error occurs
99 protected abstract URLConnection openConnection(URL u)
100 throws IOException;
103 * This method parses the string passed in as a URL and set's the
104 * instance data fields in the URL object passed in to the various values
105 * parsed out of the string. The start parameter is the position to start
106 * scanning the string. This is usually the position after the ":" which
107 * terminates the protocol name. The end parameter is the position to
108 * stop scanning. This will be either the end of the String, or the
109 * position of the "#" character, which separates the "file" portion of
110 * the URL from the "anchor" portion.
111 * <p>
112 * This method assumes URL's are formatted like http protocol URL's, so
113 * subclasses that implement protocols with URL's the follow a different
114 * syntax should override this method. The lone exception is that if
115 * the protocol name set in the URL is "file", this method will accept
116 * an empty hostname (i.e., "file:///"), which is legal for that protocol
118 * @param url The URL object in which to store the results
119 * @param spec The String-ized URL to parse
120 * @param start The position in the string to start scanning from
121 * @param end The position in the string to stop scanning
123 protected void parseURL(URL url, String spec, int start, int end)
125 String host = url.getHost();
126 int port = url.getPort();
127 String file = url.getFile();
128 String ref = url.getRef();
130 if (spec.regionMatches (start, "//", 0, 2))
132 String genuineHost;
133 int hostEnd;
134 int colon, at_host;
136 start += 2;
137 int slash = spec.indexOf ('/', start);
138 if (slash >= 0)
139 hostEnd = slash;
140 else
141 hostEnd = end;
143 host = spec.substring (start, hostEnd);
145 // We first need a genuine host name (with userinfo).
146 // So we check for '@': if it's present check the port in the
147 // section after '@' in the other case check it in the full string.
148 // P.S.: We don't care having '@' at the beginning of the string.
149 if ((at_host = host.indexOf ('@')) >= 0)
150 genuineHost = host.substring (at_host);
151 else
152 genuineHost = host;
154 // Look for optional port number. It is valid for the non-port
155 // part of the host name to be null (e.g. a URL "http://:80").
156 // TBD: JDK 1.2 in this case sets host to null rather than "";
157 // this is undocumented and likely an unintended side effect in 1.2
158 // so we'll be simple here and stick with "". Note that
159 // "http://" or "http:///" produce a "" host in JDK 1.2.
160 if ((colon = genuineHost.indexOf (':')) >= 0)
164 port = Integer.parseInt (genuineHost.substring (colon + 1));
166 catch (NumberFormatException e)
168 ; // Ignore invalid port values; port is already set to u's
169 // port.
171 // Now we must cut the port number in the original string.
172 if (at_host >= 0)
173 host = host.substring (0, at_host + colon);
174 else
175 host = host.substring (0, colon);
177 file = null;
178 start = hostEnd;
180 else if (host == null)
181 host = "";
183 if (file == null || file.length() == 0
184 || (start < end && spec.charAt(start) == '/'))
186 // No file context available; just spec for file.
187 // Or this is an absolute path name; ignore any file context.
188 file = spec.substring(start, end);
189 ref = null;
191 else if (start < end)
193 // Context is available, but only override it if there is a new file.
194 char sepChar = '/';
195 int lastSlash = file.lastIndexOf (sepChar);
196 if (lastSlash < 0 && File.separatorChar != sepChar
197 && url.getProtocol ().equals ("file"))
199 // On Windows, even '\' is allowed in a "file" URL.
200 sepChar = File.separatorChar;
201 lastSlash = file.lastIndexOf (sepChar);
204 file = file.substring(0, lastSlash)
205 + sepChar + spec.substring (start, end);
207 if (url.getProtocol ().equals ("file"))
209 // For "file" URLs constructed relative to a context, we
210 // need to canonicalise the file path.
213 boolean endsWithSlash = file.charAt(file.length() - 1) == '/';
214 file = new File (file).getCanonicalPath ();
215 if (endsWithSlash
216 && file.charAt(file.length() - 1) != '/')
217 file += '/';
219 catch (IOException e)
221 // Do nothing.
225 ref = null;
228 if (ref == null)
230 // Normally there should be no '#' in the file part,
231 // but we are nice.
232 int hash = file.indexOf('#');
233 if (hash != -1)
235 ref = file.substring(hash + 1, file.length());
236 file = file.substring(0, hash);
240 // XXX - Classpath used to call PlatformHelper.toCanonicalForm() on
241 // the file part. It seems like overhead, but supposedly there is some
242 // benefit in windows based systems (it also lowercased the string).
244 setURL(url, url.getProtocol(), host, port, file, ref);
248 * Canonicalize a filename.
250 private static String canonicalizeFilename(String file)
252 // XXX - GNU Classpath has an implementation that might be more appropriate
253 // for Windows based systems (gnu.java.io.PlatformHelper.toCanonicalForm)
255 int index;
257 // Replace "/./" with "/". This probably isn't very efficient in
258 // the general case, but it's probably not bad most of the time.
259 while ((index = file.indexOf("/./")) >= 0)
260 file = file.substring(0, index) + file.substring(index + 2);
262 // Process "/../" correctly. This probably isn't very efficient in
263 // the general case, but it's probably not bad most of the time.
264 while ((index = file.indexOf("/../")) >= 0)
266 // Strip of the previous directory - if it exists.
267 int previous = file.lastIndexOf('/', index - 1);
268 if (previous >= 0)
269 file = file.substring(0, previous) + file.substring(index + 3);
270 else
271 break;
273 return file;
277 * Compares two URLs, excluding the fragment component
279 * @param url1 The first url
280 * @param url2 The second url to compare with the first
282 * @return True if both URLs point to the same file, false otherwise.
284 * @specnote Now protected
286 protected boolean sameFile(URL url1, URL url2)
288 if (url1 == url2)
289 return true;
290 // This comparison is very conservative. It assumes that any
291 // field can be null.
292 if (url1 == null || url2 == null)
293 return false;
294 int p1 = url1.getPort ();
295 if (p1 == -1)
296 p1 = url1.ph.getDefaultPort ();
297 int p2 = url2.getPort ();
298 if (p2 == -1)
299 p2 = url2.ph.getDefaultPort ();
300 if (p1 != p2)
301 return false;
302 String s1, s2;
303 s1 = url1.getProtocol();
304 s2 = url2.getProtocol();
305 if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
306 return false;
307 s1 = url1.getHost();
308 s2 = url2.getHost();
309 if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
310 return false;
311 s1 = canonicalizeFilename(url1.getFile());
312 s2 = canonicalizeFilename(url2.getFile());
313 if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
314 return false;
315 return true;
319 * This methods sets the instance variables representing the various fields
320 * of the URL to the values passed in.
322 * @param u The URL to modify
323 * @param protocol The protocol to set
324 * @param host The host name to et
325 * @param port The port number to set
326 * @param file The filename to set
327 * @param ref The reference
329 * @exception SecurityException If the protocol handler of the URL is
330 * different from this one
332 * @deprecated 1.2 Please use
333 * #setURL(URL,String,String,int,String,String,String,String);
335 protected void setURL(URL u, String protocol, String host, int port,
336 String file, String ref)
338 u.set(protocol, host, port, file, ref);
342 * Sets the fields of the URL argument to the indicated values
344 * @param u The URL to modify
345 * @param protocol The protocol to set
346 * @param host The host name to set
347 * @param port The port number to set
348 * @param authority The authority to set
349 * @param userInfo The user information to set
350 * @param path The path/filename to set
351 * @param query The query part to set
352 * @param ref The reference
354 * @exception SecurityException If the protocol handler of the URL is
355 * different from this one
357 protected void setURL(URL u, String protocol, String host, int port,
358 String authority, String userInfo, String path,
359 String query, String ref)
361 u.set(protocol, host, port, authority, userInfo, path, query, ref);
365 * Provides the default equals calculation. May be overidden by handlers for
366 * other protocols that have different requirements for equals(). This method
367 * requires that none of its arguments is null. This is guaranteed by the
368 * fact that it is only called by java.net.URL class.
370 * @param url1 An URL object
371 * @param url2 An URL object
373 * @return True if both given URLs are equal, false otherwise.
375 protected boolean equals (URL url1, URL url2)
377 // This comparison is very conservative. It assumes that any
378 // field can be null.
379 return (url1.getPort () == url2.getPort ()
380 && ((url1.getProtocol () == null && url2.getProtocol () == null)
381 || (url1.getProtocol () != null
382 && url1.getProtocol ().equals (url2.getProtocol ())))
383 && ((url1.getUserInfo () == null && url2.getUserInfo () == null)
384 || (url1.getUserInfo () != null
385 && url1.getUserInfo ().equals(url2.getUserInfo ())))
386 && ((url1.getAuthority () == null && url2.getAuthority () == null)
387 || (url1.getAuthority () != null
388 && url1.getAuthority ().equals(url2.getAuthority ())))
389 && ((url1.getHost () == null && url2.getHost () == null)
390 || (url1.getHost () != null
391 && url1.getHost ().equals(url2.getHost ())))
392 && ((url1.getPath () == null && url2.getPath () == null)
393 || (url1.getPath () != null
394 && url1.getPath ().equals (url2.getPath ())))
395 && ((url1.getQuery () == null && url2.getQuery () == null)
396 || (url1.getQuery () != null
397 && url1.getQuery ().equals(url2.getQuery ())))
398 && ((url1.getRef () == null && url2.getRef () == null)
399 || (url1.getRef () != null
400 && url1.getRef ().equals(url2.getRef ()))));
404 * Compares the host components of two URLs.
406 * @param url1 The first URL.
407 * @param url2 The second URL.
409 * @return True if both URLs contain the same host.
411 * @exception UnknownHostException If an unknown host is found
413 protected boolean hostsEqual (URL url1, URL url2)
415 InetAddress addr1 = getHostAddress (url1);
416 InetAddress addr2 = getHostAddress (url2);
418 if (addr1 != null || addr2 != null)
419 return addr1.equals (addr2);
421 String host1 = url1.getHost();
422 String host2 = url2.getHost();
424 if (host1 != null && host2 != null)
425 return host1.equalsIgnoreCase (host2);
427 return host1 == null && host2 == null;
431 * Get the IP address of our host. An empty host field or a DNS failure will
432 * result in a null return.
434 * @param url The URL to return the host address for.
436 * @return The address of the hostname in url.
438 protected InetAddress getHostAddress (URL url)
440 String hostname = url.getHost ();
442 if (hostname.equals(""))
443 return null;
447 return InetAddress.getByName (hostname);
449 catch (UnknownHostException e)
451 return null;
456 * Returns the default port for a URL parsed by this handler. This method is
457 * meant to be overidden by handlers with default port numbers.
459 * @return The default port number.
461 protected int getDefaultPort ()
463 return -1;
467 * Provides the default hash calculation. May be overidden by handlers for
468 * other protocols that have different requirements for hashCode calculation.
470 * @param url The URL to calc the hashcode for.
472 * @return The hashcode for the given URL.
474 protected int hashCode (URL url)
476 return url.getProtocol ().hashCode () +
477 ((url.getHost () == null) ? 0 : url.getHost ().hashCode ()) +
478 url.getFile ().hashCode() +
479 url.getPort ();
483 * This method converts a URL object into a String. This method creates
484 * Strings in the mold of http URL's, so protocol handlers which use URL's
485 * that have a different syntax should override this method
487 * @param url The URL object to convert
489 * @return A string representation of the url
491 protected String toExternalForm(URL u)
493 String protocol, host, file, ref, user;
494 int port;
496 protocol = u.getProtocol();
498 // JDK 1.2 online doc infers that host could be null because it
499 // explicitly states that file cannot be null, but is silent on host.
500 host = u.getHost();
501 if (host == null)
502 host = "";
504 port = u.getPort();
505 file = u.getFile();
506 ref = u.getRef();
507 user = u.getUserInfo();
509 // Guess a reasonable size for the string buffer so we have to resize
510 // at most once.
511 int size = protocol.length() + host.length() + file.length() + 24;
512 StringBuffer sb = new StringBuffer(size);
514 if (protocol != null && protocol.length() > 0)
516 sb.append(protocol);
517 sb.append(":");
520 if (host.length() != 0)
522 sb.append("//");
523 if (user != null && !"".equals(user))
524 sb.append(user).append('@');
525 sb.append(host);
527 // Append port if port was in URL spec.
528 if (port >= 0)
529 sb.append(':').append(port);
532 sb.append(file);
534 if (ref != null)
535 sb.append('#').append(ref);
537 return sb.toString();