/[classpath]/classpath/java/net/URLStreamHandler.java
ViewVC logotype

Diff of /classpath/java/net/URLStreamHandler.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.9 by mark, Fri Oct 18 20:40:50 2002 UTC revision 1.10 by mark, Fri Nov 22 02:42:26 2002 UTC
# Line 1  Line 1 
1  /* URLStreamHandler.java -- Abstract superclass for all protocol handlers  /* URLStreamHandler.java -- Abstract superclass for all protocol handlers
2     Copyright (C) 1998 Free Software Foundation, Inc.     Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
3    
4  This file is part of GNU Classpath.  This file is part of GNU Classpath.
5    
# Line 39  exception statement from your version. * Line 39  exception statement from your version. *
39  package java.net;  package java.net;
40    
41  import java.io.IOException;  import java.io.IOException;
42  import gnu.java.io.PlatformHelper;  
43    /*
44     * Written using on-line Java Platform 1.2 API Specification, as well
45     * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
46     * Status:  Believed complete and correct.
47     */
48    
49  /**  /**
50    * This class is the superclass of all URL protocol handlers.  The URL   * This class is the superclass of all URL protocol handlers.  The URL
51    * class loads the appropriate protocol handler to establish a connection   * class loads the appropriate protocol handler to establish a connection
52    * to a (possibly) remote service (eg, "http", "ftp") and to do protocol   * to a (possibly) remote service (eg, "http", "ftp") and to do protocol
53    * specific parsing of URL's.  Refer to the URL class documentation for   * specific parsing of URL's.  Refer to the URL class documentation for
54    * details on how that class locates and loads protocol handlers.   * details on how that class locates and loads protocol handlers.
55    * <p>   * <p>
56    * A protocol handler implementation should override the openConnection()   * A protocol handler implementation should override the openConnection()
57    * method, and optionally override the parseURL() and toExternalForm()   * method, and optionally override the parseURL() and toExternalForm()
58    * methods if necessary. (The default implementations will parse/write all   * methods if necessary. (The default implementations will parse/write all
59    * URL's in the same form as http URL's).  A protocol  specific subclass   * URL's in the same form as http URL's).  A protocol  specific subclass
60    * of URLConnection will most likely need to be created as well.   * of URLConnection will most likely need to be created as well.
61    * <p>   * <p>
62    * Note that the instance methods in this class are called as if they   * Note that the instance methods in this class are called as if they
63    * were static methods.  That is, a URL object to act on is passed with   * were static methods.  That is, a URL object to act on is passed with
64    * every call rather than the caller assuming the URL is stored in an   * every call rather than the caller assuming the URL is stored in an
65    * instance variable of the "this" object.   * instance variable of the "this" object.
66    * <p>   * <p>
67    * The methods in this class are protected and accessible only to subclasses.   * The methods in this class are protected and accessible only to subclasses.
68    * URLStreamConnection objects are intended for use by the URL class only,   * URLStreamConnection objects are intended for use by the URL class only,
69    * not by other classes (unless those classes are implementing protocols).   * not by other classes (unless those classes are implementing protocols).
70    *   *
71    * @version 0.5   * @author Aaron M. Renn (arenn@urbanophile.com)
72    *   * @author Warren Levy (warrenl@cygnus.com)
73    * @author Aaron M. Renn (arenn@urbanophile.com)   *
74    *   * @see URL
75    * @see URL   */
   */  
76  public abstract class URLStreamHandler  public abstract class URLStreamHandler
77  {  {
78      /**
79       * Creates a URLStreamHander
80       */
81      public URLStreamHandler ()
82      {
83      }
84    
85  /*************************************************************************/    /**
86       * Returns a URLConnection for the passed in URL.  Note that this should
87       * not actually create the connection to the (possibly) remote host, but
88       * rather simply return a URLConnection object.  The connect() method of
89       * URL connection is used to establish the actual connection, possibly
90       * after the caller sets up various connection options.
91       *
92       * @param url The URL to get a connection object for
93       *
94       * @return A URLConnection object for the given URL
95       *
96       * @exception IOException If an error occurs
97       */
98      protected abstract URLConnection openConnection(URL u)
99        throws IOException;
100    
101      /**
102       * This method parses the string passed in as a URL and set's the
103       * instance data fields in the URL object passed in to the various values
104       * parsed out of the string.  The start parameter is the position to start
105       * scanning the string.  This is usually the position after the ":" which
106       * terminates the protocol name.  The end parameter is the position to
107       * stop scanning.  This will be either the end of the String, or the
108       * position of the "#" character, which separates the "file" portion of
109       * the URL from the "anchor" portion.
110       * <p>
111       * This method assumes URL's are formatted like http protocol URL's, so
112       * subclasses that implement protocols with URL's the follow a different
113       * syntax should override this method.  The lone exception is that if
114       * the protocol name set in the URL is "file", this method will accept
115       * a an empty hostname (i.e., "file:///"), which is legal for that protocol
116       *
117       * @param url The URL object in which to store the results
118       * @param spec The String-ized URL to parse
119       * @param start The position in the string to start scanning from
120       * @param end The position in the string to stop scanning
121       */
122      protected void parseURL(URL url, String spec, int start, int end)
123      {
124        String host = url.getHost();
125        int port = url.getPort();
126        String file = url.getFile();
127        String ref = url.getRef();
128        
129        if (spec.regionMatches (start, "//", 0, 2))
130          {
131            int hostEnd;
132            int colon;
133    
134            start += 2;
135            int slash = spec.indexOf('/', start);
136            if (slash >= 0)
137              hostEnd = slash;
138            else
139              hostEnd = end;
140    
141            host = spec.substring (start, hostEnd);
142            
143            // Look for optional port number.  It is valid for the non-port
144            // part of the host name to be null (e.g. a URL "http://:80").
145            // TBD: JDK 1.2 in this case sets host to null rather than "";
146            // this is undocumented and likely an unintended side effect in 1.2
147            // so we'll be simple here and stick with "". Note that
148            // "http://" or "http:///" produce a "" host in JDK 1.2.
149            if ((colon = host.indexOf(':')) >= 0)
150              {
151                try
152                  {
153                    port = Integer.parseInt(host.substring(colon + 1));
154                  }
155                catch (NumberFormatException e)
156                  {
157                    ; // Ignore invalid port values; port is already set to u's
158                      // port.
159                  }
160                host = host.substring(0, colon);
161              }
162            file = null;
163            start = hostEnd;
164          }
165        else if (host == null)
166          host = "";
167    
168        if (file == null || file.length() == 0
169            || (start < end && spec.charAt(start) == '/'))
170          {
171            // No file context available; just spec for file.
172            // Or this is an absolute path name; ignore any file context.
173            file = spec.substring(start, end);
174            ref = null;
175          }
176        else if (start < end)
177          {
178            // Context is available, but only override it if there is a new file.
179            file = file.substring(0, file.lastIndexOf('/'))
180                    + '/' + spec.substring(start, end);
181            ref = null;
182          }
183    
184        if (ref == null)
185          {
186            // Normally there should be no '#' in the file part,
187            // but we are nice.
188            int hash = file.indexOf('#');
189            if (hash != -1)
190              {
191                ref = file.substring(hash + 1, file.length());
192                file = file.substring(0, hash);
193              }
194          }
195    
196        // XXX - Classpath used to call PlatformHelper.toCanonicalForm() on
197        // the file part. It seems like overhead, but supposedly there is some
198        // benefit in windows based systems (it also lowercased the string).
199    
200  /*      setURL(url, url.getProtocol(), host, port, file, ref);
201   * Constructors    }
202   */    
203      private static String canonicalizeFilename(String file)
204      {
205        // XXX - GNU Classpath has an implementation that might be more appropriate
206        // for Windows based systems (gnu.java.io.PlatformHelper.toCanonicalForm)
207    
208        int index;
209    
210        // Replace "/./" with "/".  This probably isn't very efficient in
211        // the general case, but it's probably not bad most of the time.
212        while ((index = file.indexOf("/./")) >= 0)
213          file = file.substring(0, index) + file.substring(index + 2);
214    
215        // Process "/../" correctly.  This probably isn't very efficient in
216        // the general case, but it's probably not bad most of the time.
217        while ((index = file.indexOf("/../")) >= 0)
218          {
219            // Strip of the previous directory - if it exists.
220            int previous = file.lastIndexOf('/', index - 1);
221            if (previous >= 0)
222              file = file.substring(0, previous) + file.substring(index + 3);
223            else
224              break;
225          }
226        return file;
227      }
228    
229  /**    /**
230    * Do nothing constructor for subclass     * Compares two URLs, excluding the fragment component
231    */     *
232  public     * @param url1 The first url
233  URLStreamHandler()     * @param url2 The second url to compare with the first
234  {     *
235    ;     * @specnote Now protected
236  }     */
237      protected boolean sameFile(URL url1, URL url2)
238      {
239        if (url1 == url2)
240          return true;
241        // This comparison is very conservative.  It assumes that any
242        // field can be null.
243        if (url1 == null || url2 == null || url1.getPort() != url2.getPort())
244          return false;
245        String s1, s2;
246        s1 = url1.getProtocol();
247        s2 = url2.getProtocol();
248        if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
249          return false;
250        s1 = url1.getHost();
251        s2 = url2.getHost();
252        if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
253          return false;
254        s1 = canonicalizeFilename(url1.getFile());
255        s2 = canonicalizeFilename(url2.getFile());
256        if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
257          return false;
258        return true;
259      }
260    
261  /*************************************************************************/    /**
262       * This methods sets the instance variables representing the various fields
263       * of the URL to the values passed in.
264       *
265       * @param u The URL to modify
266       * @param protocol The protocol to set
267       * @param host The host name to et
268       * @param port The port number to set
269       * @param file The filename to set
270       * @param ref The reference
271       *
272       * @exception SecurityException If the protocol handler of the URL is
273       * different from this one
274       *
275       * @deprecated 1.2 Please use
276       * #setURL(URL,String,String,int,String,String,String,String);
277       */
278      protected void setURL(URL u, String protocol, String host, int port,
279                            String file, String ref)
280      {
281        u.set(protocol, host, port, file, ref);
282      }
283    
284  /*    /**
285   * Instance Methods     * Sets the fields of the URL argument to the indicated values
286   */     *
287       * @param u The URL to modify
288       * @param protocol The protocol to set
289       * @param host The host name to set
290       * @param port The port number to set
291       * @param authority The authority to set
292       * @param userInfo The user information to set
293       * @param path The path/filename to set
294       * @param query The query part to set
295       * @param ref The reference
296       *
297       * @exception SecurityException If the protocol handler of the URL is
298       * different from this one
299       */
300      protected void setURL(URL u, String protocol, String host, int port,
301                            String authority, String userInfo, String path,
302                            String query, String ref)
303      {
304        u.set(protocol, host, port, authority, userInfo, path, query, ref);
305      }
306    
307  /**    /**
308    * Returns a URLConnection for the passed in URL.  Note that this should     * Provides the default equals calculation. May be overidden by handlers for
309    * not actually create the connection to the (possibly) remote host, but     * other protocols that have different requirements for equals(). This method
310    * rather simply return a URLConnection object.  The connect() method of     * requires that none of its arguments is null. This is guaranteed by the
311    * URL connection is used to establish the actual connection, possibly     * fact that it is only called by java.net.URL class.
312    * after the caller sets up various connection options.     *
313    *     * @param url1 An URL object
314    * @param url The URL to get a connection object for     * @param url2 An URL object
315    *     */
316    * @return A URLConnection object for the given URL    protected boolean equals (URL url1, URL url2)
317    *    {
318    * @exception IOException If an error occurs      // This comparison is very conservative.  It assumes that any
319    */      // field can be null.
320  protected abstract URLConnection      return (url1.getPort () == url2.getPort ()
321  openConnection(URL url) throws IOException;              && ((url1.getProtocol () == null && url2.getProtocol () == null)
322                    || (url1.getProtocol () != null
323                            && url1.getProtocol ().equals (url2.getProtocol ())))
324                && ((url1.getUserInfo () == null && url2.getUserInfo () == null)
325                    || (url1.getUserInfo () != null
326                            && url1.getUserInfo ().equals(url2.getUserInfo ())))
327                && ((url1.getAuthority () == null && url2.getAuthority () == null)
328                    || (url1.getAuthority () != null
329                            && url1.getAuthority ().equals(url2.getAuthority ())))
330                && ((url1.getHost () == null && url2.getHost () == null)
331                    || (url1.getHost () != null
332                            && url1.getHost ().equals(url2.getHost ())))
333                && ((url1.getPath () == null && url2.getPath () == null)
334                    || (url1.getPath () != null
335                            && url1.getPath ().equals (url2.getPath ())))
336                && ((url1.getQuery () == null && url2.getQuery () == null)
337                    || (url1.getQuery () != null
338                            && url1.getQuery ().equals(url2.getQuery ())))
339                && ((url1.getRef () == null && url2.getRef () == null)
340                    || (url1.getRef () != null
341                            && url1.getRef ().equals(url2.getRef ()))));
342      }
343    
344  /*************************************************************************/    /**
345       * Compares the host components of two URLs.
346       *
347       * @exception UnknownHostException If an unknown host is found
348       */
349      protected boolean hostsEqual (URL url1, URL url2)
350        throws UnknownHostException
351      {
352        InetAddress addr1 = InetAddress.getByName (url1.getHost ());
353        InetAddress addr2 = InetAddress.getByName (url2.getHost ());
354    
355  /**      return addr1.equals (addr2);
356    * This method parses the string passed in as a URL and set's the    }
357    * instance data fields in the URL object passed in to the various values  
358    * parsed out of the string.  The start parameter is the position to start    /**
359    * scanning the string.  This is usually the position after the ":" which     * Get the IP address of our host. An empty host field or a DNS failure will
360    * terminates the protocol name.  The end parameter is the position to     * result in a null return.
361    * stop scanning.  This will be either the end of the String, or the     */
362    * position of the "#" character, which separates the "file" portion of    protected InetAddress getHostAddress (URL url)
363    * the URL from the "anchor" portion.    {
364    * <p>      String hostname = url.getHost ();
365    * This method assumes URL's are formatted like http protocol URL's, so  
366    * subclasses that implement protocols with URL's the follow a different      if (hostname == "")
367    * syntax should override this method.  The lone exception is that if        return null;
   * the protocol name set in the URL is "file", this method will accept  
   * a an empty hostname (i.e., "file:///"), which is legal for that protocol  
   *  
   * @param url The URL object in which to store the results  
   * @param url_string 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 url_string, int start, int end)  
 {  
   // This method does not throw an exception or return a value.  Thus our  
   // strategy when we encounter an error in parsing is to return without  
   // doing anything.  
   
   // Bunches of things should be true.  Make sure.  
   if (end < start)  
     return;  
   if ((end - start) < 2)  
     return;  
   if (start > url_string.length())  
     return;  
   if (end > url_string.length())  
     end = url_string.length(); // This should be safe  
   
   // Turn end into an offset from the end of the string instead of  
   // the beginning  
   end = url_string.length() - end;  
   
   // Skip remains of protocol  
   url_string = url_string.substring(start);  
   
   boolean needContext = url.getFile() != null;  
   
   // Skip the leading "//"  
   if (url_string.startsWith("//"))  
     {  
       url_string = url_string.substring (2);  
       needContext = false;  
     }  
           
   // Declare some variables  
   String host = null;  
   int port = -1;  
   String file = null;  
   String anchor = null;  
   
   if (!needContext)  
     {  
       // Process host and port  
       int slash_index = url_string.indexOf("/");  
       int colon_index = url_string.indexOf(":");  
         
       if (slash_index > (url_string.length() - end))  
         return;  
       else if (slash_index == -1)  
         slash_index = url_string.length() - end;  
         
       if ((colon_index == -1) || (colon_index > slash_index))  
         {  
           host = url_string.substring(0, slash_index);  
         }  
       else  
         {  
           host = url_string.substring(0, colon_index);  
             
           String port_str = url_string.substring(colon_index + 1, slash_index);  
           try  
             {  
               port = Integer.parseInt(port_str);  
             }  
           catch (NumberFormatException e)  
             {  
               return;  
             }  
         }  
       if (slash_index < (url_string.length() - 1))  
         url_string = url_string.substring(slash_index + 1);  
       else  
         url_string = "";  
     }  
   
   // Process file and anchor  
   if (needContext)  
     {  
       host = url.getHost();  
       port = url.getPort();  
       if (url_string.startsWith("/")) //url string is an absolute path  
         file = url_string;  
       else  
         {  
           file = url.getFile();  
           int idx = file.lastIndexOf("/");    
           if (idx == -1) //context path is weird  
             file = "/" + url_string;  
           else if (idx == (file.length() - 1))  
             //just concatenate two parts  
             file = file + url_string;  
           else  
             file = file.substring(0, idx+1) + url_string;  
         }  
     }  
   else  
     file = "/" + url_string;  
   
   if (end == 0)  
     {  
       anchor = null;  
     }  
   else  
     {  
       // Only set anchor if end char is a '#'.  Otherwise assume we're  
       // just supposed to stop scanning for some reason  
       if (file.charAt(file.length() - end) == '#')  
         {  
           int len = file.length();  
           anchor = file.substring( len - end + 1, len);  
           file = file.substring(0, len - end);  
         }  
       else  
         anchor = null;  
     }  
368            
369    file = PlatformHelper.toCanonicalForm(file, '/');      try
370          {
371            return InetAddress.getByName (hostname);
372          }
373        catch (UnknownHostException e)
374          {
375            return null;
376          }
377      }
378    
379    // Now set the values    /**
380    setURL(url, url.getProtocol(), host, port, file, anchor);     * Returns the default port for a URL parsed by this handler. This method is
381  }     * meant to be overidden by handlers with default port numbers.
382       */
383      protected int getDefaultPort ()
384      {
385        return -1;
386      }
387    
388  /*************************************************************************/    /**
389       * Provides the default hash calculation. May be overidden by handlers for
390       * other protocols that have different requirements for hashCode calculation.
391       */
392      protected int hashCode (URL url)
393      {
394        return url.getProtocol ().hashCode () +
395               ((url.getHost () == null) ? 0 : url.getHost ().hashCode ()) +
396               url.getFile ().hashCode() +
397               url.getPort ();
398      }
399    
400  /**    /**
401    * This method converts a URL object into a String.  This method creates     * This method converts a URL object into a String.  This method creates
402    * Strings in the mold of http URL's, so protocol handlers which use URL's     * Strings in the mold of http URL's, so protocol handlers which use URL's
403    * that have a different syntax should override this method     * that have a different syntax should override this method
404    *     *
405    * @param url The URL object to convert     * @param url The URL object to convert
406    */     */
407  protected String    protected String toExternalForm(URL u)
408  toExternalForm(URL url)    {
409  {      String protocol, host, file, ref;
410    String protocol = url.getProtocol();      int port;
411    String host = url.getHost();  
412    int port = url.getPort();      protocol = u.getProtocol();
413    String file = url.getFile();  
414    String anchor = url.getRef();      // JDK 1.2 online doc infers that host could be null because it
415        // explicitly states that file cannot be null, but is silent on host.
416        host = u.getHost();
417        if (host == null)
418          host = "";
419    
420        port = u.getPort();
421        file = u.getFile();
422        ref = u.getRef();
423    
424        // Guess a reasonable size for the string buffer so we have to resize
425        // at most once.
426        int size = protocol.length() + host.length() + file.length() + 24;
427        StringBuffer sb = new StringBuffer(size);
428    
   StringBuffer sb = new StringBuffer(PlatformHelper.INITIAL_MAX_PATH);  
     
   if (protocol != null){  
429      sb.append(protocol);      sb.append(protocol);
     sb.append("://");  
   }  
     
   if (host != null)  
     sb.append(host);  
       
   if (port != -1){  
430      sb.append(':');      sb.append(':');
     sb.append(port);  
   }  
     
   if (file != null)  
     sb.append(file);  
   else  
     sb.append('/');  
       
   if (anchor != null){  
     sb.append('#');  
     sb.append(anchor);  
   }  
     
   return sb.toString();  
431    
432  }      if (host.length() != 0)
433          sb.append("//").append(host);
434    
435  /*************************************************************************/      // Note that this produces different results from JDK 1.2 as JDK 1.2
436        // ignores a non-default port if host is null or "".  That is inconsistent
437        // with the spec since the result of this method is spec'ed so it can be
438        // used to construct a new URL that is equivalent to the original.
439        boolean port_needed = port >= 0 && port != getDefaultPort();
440        if (port_needed)
441          sb.append(':').append(port);
442    
443  /**      sb.append(file);
   * This methods sets the instance variables representing the various fields  
   * of the URL to the values passed in.  
   *  
   * @param url The URL in which to set the values  
   * @param protocol The protocol name  
   * @param host The host name  
   * @param port The port number  
   * @param file The file portion  
   * @param anchor The anchor portion  
   */  
 protected void  
 setURL(URL url, String protocol, String host, int port, String file,  
        String anchor)  
 {  
   url.set(protocol, host, port, file, anchor);  
 }  
444    
445  } // class URLStreamHandler      if (ref != null)
446          sb.append('#').append(ref);
447    
448        return sb.toString();
449      }
450    }

Legend:
Removed from v.1.9  
changed lines
  Added in v.1.10

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26