123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- /* URLStreamHandler.java -- Abstract superclass for all protocol handlers
- Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package java.net;
- import java.io.IOException;
- import java.io.File;
- /*
- * Written using on-line Java Platform 1.2 API Specification, as well
- * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
- * Status: Believed complete and correct.
- */
- /**
- * This class is the superclass of all URL protocol handlers. The URL
- * class loads the appropriate protocol handler to establish a connection
- * to a (possibly) remote service (eg, "http", "ftp") and to do protocol
- * specific parsing of URL's. Refer to the URL class documentation for
- * details on how that class locates and loads protocol handlers.
- * <p>
- * A protocol handler implementation should override the openConnection()
- * method, and optionally override the parseURL() and toExternalForm()
- * methods if necessary. (The default implementations will parse/write all
- * URL's in the same form as http URL's). A protocol specific subclass
- * of URLConnection will most likely need to be created as well.
- * <p>
- * Note that the instance methods in this class are called as if they
- * were static methods. That is, a URL object to act on is passed with
- * every call rather than the caller assuming the URL is stored in an
- * instance variable of the "this" object.
- * <p>
- * The methods in this class are protected and accessible only to subclasses.
- * URLStreamConnection objects are intended for use by the URL class only,
- * not by other classes (unless those classes are implementing protocols).
- *
- * @author Aaron M. Renn (arenn@urbanophile.com)
- * @author Warren Levy (warrenl@cygnus.com)
- *
- * @see URL
- */
- public abstract class URLStreamHandler
- {
- /**
- * Creates a URLStreamHander
- */
- public URLStreamHandler ()
- {
- }
- /**
- * Returns a URLConnection for the passed in URL. Note that this should
- * not actually create the connection to the (possibly) remote host, but
- * rather simply return a URLConnection object. The connect() method of
- * URL connection is used to establish the actual connection, possibly
- * after the caller sets up various connection options.
- *
- * @param url The URL to get a connection object for
- *
- * @return A URLConnection object for the given URL
- *
- * @exception IOException If an error occurs
- */
- protected abstract URLConnection openConnection(URL u)
- throws IOException;
- /**
- * This method parses the string passed in as a URL and set's the
- * instance data fields in the URL object passed in to the various values
- * parsed out of the string. The start parameter is the position to start
- * scanning the string. This is usually the position after the ":" which
- * terminates the protocol name. The end parameter is the position to
- * stop scanning. This will be either the end of the String, or the
- * position of the "#" character, which separates the "file" portion of
- * the URL from the "anchor" portion.
- * <p>
- * This method assumes URL's are formatted like http protocol URL's, so
- * subclasses that implement protocols with URL's the follow a different
- * syntax should override this method. The lone exception is that if
- * the protocol name set in the URL is "file", this method will accept
- * an empty hostname (i.e., "file:///"), which is legal for that protocol
- *
- * @param url The URL object in which to store the results
- * @param spec The String-ized URL to parse
- * @param start The position in the string to start scanning from
- * @param end The position in the string to stop scanning
- */
- protected void parseURL(URL url, String spec, int start, int end)
- {
- String host = url.getHost();
- int port = url.getPort();
- String file = url.getFile();
- String ref = url.getRef();
-
- if (spec.regionMatches (start, "//", 0, 2))
- {
- int hostEnd;
- int colon;
- start += 2;
- int slash = spec.indexOf('/', start);
- if (slash >= 0)
- hostEnd = slash;
- else
- hostEnd = end;
- host = spec.substring (start, hostEnd);
-
- // Look for optional port number. It is valid for the non-port
- // part of the host name to be null (e.g. a URL "http://:80").
- // TBD: JDK 1.2 in this case sets host to null rather than "";
- // this is undocumented and likely an unintended side effect in 1.2
- // so we'll be simple here and stick with "". Note that
- // "http://" or "http:///" produce a "" host in JDK 1.2.
- if ((colon = host.indexOf(':')) >= 0)
- {
- try
- {
- port = Integer.parseInt(host.substring(colon + 1));
- }
- catch (NumberFormatException e)
- {
- ; // Ignore invalid port values; port is already set to u's
- // port.
- }
- host = host.substring(0, colon);
- }
- file = null;
- start = hostEnd;
- }
- else if (host == null)
- host = "";
- if (file == null || file.length() == 0
- || (start < end && spec.charAt(start) == '/'))
- {
- // No file context available; just spec for file.
- // Or this is an absolute path name; ignore any file context.
- file = spec.substring(start, end);
- ref = null;
- }
- else if (start < end)
- {
- // Context is available, but only override it if there is a new file.
- char sepChar = '/';
- int lastSlash = file.lastIndexOf (sepChar);
- if (lastSlash < 0 && File.separatorChar != sepChar
- && url.getProtocol ().equals ("file"))
- {
- // On Windows, even '\' is allowed in a "file" URL.
- sepChar = File.separatorChar;
- lastSlash = file.lastIndexOf (sepChar);
- }
-
- file = file.substring(0, lastSlash)
- + sepChar + spec.substring (start, end);
- if (url.getProtocol ().equals ("file"))
- {
- // For "file" URLs constructed relative to a context, we
- // need to canonicalise the file path.
- try
- {
- file = new File (file).getCanonicalPath ();
- }
- catch (IOException e)
- {
- }
- }
- ref = null;
- }
- if (ref == null)
- {
- // Normally there should be no '#' in the file part,
- // but we are nice.
- int hash = file.indexOf('#');
- if (hash != -1)
- {
- ref = file.substring(hash + 1, file.length());
- file = file.substring(0, hash);
- }
- }
- // XXX - Classpath used to call PlatformHelper.toCanonicalForm() on
- // the file part. It seems like overhead, but supposedly there is some
- // benefit in windows based systems (it also lowercased the string).
- setURL(url, url.getProtocol(), host, port, file, ref);
- }
-
- private static String canonicalizeFilename(String file)
- {
- // XXX - GNU Classpath has an implementation that might be more appropriate
- // for Windows based systems (gnu.java.io.PlatformHelper.toCanonicalForm)
- int index;
- // Replace "/./" with "/". This probably isn't very efficient in
- // the general case, but it's probably not bad most of the time.
- while ((index = file.indexOf("/./")) >= 0)
- file = file.substring(0, index) + file.substring(index + 2);
- // Process "/../" correctly. This probably isn't very efficient in
- // the general case, but it's probably not bad most of the time.
- while ((index = file.indexOf("/../")) >= 0)
- {
- // Strip of the previous directory - if it exists.
- int previous = file.lastIndexOf('/', index - 1);
- if (previous >= 0)
- file = file.substring(0, previous) + file.substring(index + 3);
- else
- break;
- }
- return file;
- }
- /**
- * Compares two URLs, excluding the fragment component
- *
- * @param url1 The first url
- * @param url2 The second url to compare with the first
- *
- * @specnote Now protected
- */
- protected boolean sameFile(URL url1, URL url2)
- {
- if (url1 == url2)
- return true;
- // This comparison is very conservative. It assumes that any
- // field can be null.
- if (url1 == null || url2 == null || url1.getPort() != url2.getPort())
- return false;
- String s1, s2;
- s1 = url1.getProtocol();
- s2 = url2.getProtocol();
- if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
- return false;
- s1 = url1.getHost();
- s2 = url2.getHost();
- if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
- return false;
- s1 = canonicalizeFilename(url1.getFile());
- s2 = canonicalizeFilename(url2.getFile());
- if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
- return false;
- return true;
- }
- /**
- * This methods sets the instance variables representing the various fields
- * of the URL to the values passed in.
- *
- * @param u The URL to modify
- * @param protocol The protocol to set
- * @param host The host name to et
- * @param port The port number to set
- * @param file The filename to set
- * @param ref The reference
- *
- * @exception SecurityException If the protocol handler of the URL is
- * different from this one
- *
- * @deprecated 1.2 Please use
- * #setURL(URL,String,String,int,String,String,String,String);
- */
- protected void setURL(URL u, String protocol, String host, int port,
- String file, String ref)
- {
- u.set(protocol, host, port, file, ref);
- }
- /**
- * Sets the fields of the URL argument to the indicated values
- *
- * @param u The URL to modify
- * @param protocol The protocol to set
- * @param host The host name to set
- * @param port The port number to set
- * @param authority The authority to set
- * @param userInfo The user information to set
- * @param path The path/filename to set
- * @param query The query part to set
- * @param ref The reference
- *
- * @exception SecurityException If the protocol handler of the URL is
- * different from this one
- */
- protected void setURL(URL u, String protocol, String host, int port,
- String authority, String userInfo, String path,
- String query, String ref)
- {
- u.set(protocol, host, port, authority, userInfo, path, query, ref);
- }
- /**
- * Provides the default equals calculation. May be overidden by handlers for
- * other protocols that have different requirements for equals(). This method
- * requires that none of its arguments is null. This is guaranteed by the
- * fact that it is only called by java.net.URL class.
- *
- * @param url1 An URL object
- * @param url2 An URL object
- */
- protected boolean equals (URL url1, URL url2)
- {
- // This comparison is very conservative. It assumes that any
- // field can be null.
- return (url1.getPort () == url2.getPort ()
- && ((url1.getProtocol () == null && url2.getProtocol () == null)
- || (url1.getProtocol () != null
- && url1.getProtocol ().equals (url2.getProtocol ())))
- && ((url1.getUserInfo () == null && url2.getUserInfo () == null)
- || (url1.getUserInfo () != null
- && url1.getUserInfo ().equals(url2.getUserInfo ())))
- && ((url1.getAuthority () == null && url2.getAuthority () == null)
- || (url1.getAuthority () != null
- && url1.getAuthority ().equals(url2.getAuthority ())))
- && ((url1.getHost () == null && url2.getHost () == null)
- || (url1.getHost () != null
- && url1.getHost ().equals(url2.getHost ())))
- && ((url1.getPath () == null && url2.getPath () == null)
- || (url1.getPath () != null
- && url1.getPath ().equals (url2.getPath ())))
- && ((url1.getQuery () == null && url2.getQuery () == null)
- || (url1.getQuery () != null
- && url1.getQuery ().equals(url2.getQuery ())))
- && ((url1.getRef () == null && url2.getRef () == null)
- || (url1.getRef () != null
- && url1.getRef ().equals(url2.getRef ()))));
- }
- /**
- * Compares the host components of two URLs.
- *
- * @exception UnknownHostException If an unknown host is found
- */
- protected boolean hostsEqual (URL url1, URL url2)
- throws UnknownHostException
- {
- InetAddress addr1 = InetAddress.getByName (url1.getHost ());
- InetAddress addr2 = InetAddress.getByName (url2.getHost ());
- return addr1.equals (addr2);
- }
- /**
- * Get the IP address of our host. An empty host field or a DNS failure will
- * result in a null return.
- */
- protected InetAddress getHostAddress (URL url)
- {
- String hostname = url.getHost ();
- if (hostname == "")
- return null;
-
- try
- {
- return InetAddress.getByName (hostname);
- }
- catch (UnknownHostException e)
- {
- return null;
- }
- }
- /**
- * Returns the default port for a URL parsed by this handler. This method is
- * meant to be overidden by handlers with default port numbers.
- */
- protected int getDefaultPort ()
- {
- return -1;
- }
- /**
- * Provides the default hash calculation. May be overidden by handlers for
- * other protocols that have different requirements for hashCode calculation.
- */
- protected int hashCode (URL url)
- {
- return url.getProtocol ().hashCode () +
- ((url.getHost () == null) ? 0 : url.getHost ().hashCode ()) +
- url.getFile ().hashCode() +
- url.getPort ();
- }
- /**
- * This method converts a URL object into a String. This method creates
- * Strings in the mold of http URL's, so protocol handlers which use URL's
- * that have a different syntax should override this method
- *
- * @param url The URL object to convert
- */
- protected String toExternalForm(URL u)
- {
- String protocol, host, file, ref;
- int port;
- protocol = u.getProtocol();
- // JDK 1.2 online doc infers that host could be null because it
- // explicitly states that file cannot be null, but is silent on host.
- host = u.getHost();
- if (host == null)
- host = "";
- port = u.getPort();
- file = u.getFile();
- ref = u.getRef();
- // Guess a reasonable size for the string buffer so we have to resize
- // at most once.
- int size = protocol.length() + host.length() + file.length() + 24;
- StringBuffer sb = new StringBuffer(size);
- sb.append(protocol);
- sb.append(':');
- if (host.length() != 0)
- sb.append("//").append(host);
- // Note that this produces different results from JDK 1.2 as JDK 1.2
- // ignores a non-default port if host is null or "". That is inconsistent
- // with the spec since the result of this method is spec'ed so it can be
- // used to construct a new URL that is equivalent to the original.
- boolean port_needed = port > 0 && port != getDefaultPort();
- if (port_needed)
- sb.append(':').append(port);
- sb.append(file);
- if (ref != null)
- sb.append('#').append(ref);
- return sb.toString();
- }
- }
|