source: trunk/gcc/libjava/java/net/URLStreamHandler.java

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 15.9 KB
Line 
1/* URLStreamHandler.java -- Abstract superclass for all protocol handlers
2 Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1902111-1307 USA.
20
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library. Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module. An independent module is a module which is not derived from
33or based on this library. If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so. If you do not wish to do so, delete this
36exception statement from your version. */
37
38
39package java.net;
40
41import java.io.IOException;
42import java.io.File;
43
44/*
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.
48 */
49
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).
71 *
72 * @author Aaron M. Renn (arenn@urbanophile.com)
73 * @author Warren Levy (warrenl@cygnus.com)
74 *
75 * @see URL
76 */
77public abstract class URLStreamHandler
78{
79 /**
80 * Creates a URLStreamHander
81 */
82 public URLStreamHandler ()
83 {
84 }
85
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.
92 *
93 * @param url The URL to get a connection object for
94 *
95 * @return A URLConnection object for the given URL
96 *
97 * @exception IOException If an error occurs
98 */
99 protected abstract URLConnection openConnection(URL u)
100 throws IOException;
101
102 /**
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
117 *
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
122 */
123 protected void parseURL(URL url, String spec, int start, int end)
124 {
125 String host = url.getHost();
126 int port = url.getPort();
127 String file = url.getFile();
128 String ref = url.getRef();
129
130 if (spec.regionMatches (start, "//", 0, 2))
131 {
132 int hostEnd;
133 int colon;
134
135 start += 2;
136 int slash = spec.indexOf('/', start);
137 if (slash >= 0)
138 hostEnd = slash;
139 else
140 hostEnd = end;
141
142 host = spec.substring (start, hostEnd);
143
144 // Look for optional port number. It is valid for the non-port
145 // part of the host name to be null (e.g. a URL "http://:80").
146 // TBD: JDK 1.2 in this case sets host to null rather than "";
147 // this is undocumented and likely an unintended side effect in 1.2
148 // so we'll be simple here and stick with "". Note that
149 // "http://" or "http:///" produce a "" host in JDK 1.2.
150 if ((colon = host.indexOf(':')) >= 0)
151 {
152 try
153 {
154 port = Integer.parseInt(host.substring(colon + 1));
155 }
156 catch (NumberFormatException e)
157 {
158 ; // Ignore invalid port values; port is already set to u's
159 // port.
160 }
161 host = host.substring(0, colon);
162 }
163 file = null;
164 start = hostEnd;
165 }
166 else if (host == null)
167 host = "";
168
169 if (file == null || file.length() == 0
170 || (start < end && spec.charAt(start) == '/'))
171 {
172 // No file context available; just spec for file.
173 // Or this is an absolute path name; ignore any file context.
174 file = spec.substring(start, end);
175 ref = null;
176 }
177 else if (start < end)
178 {
179 // Context is available, but only override it if there is a new file.
180 char sepChar = '/';
181 int lastSlash = file.lastIndexOf (sepChar);
182 if (lastSlash < 0 && File.separatorChar != sepChar
183 && url.getProtocol ().equals ("file"))
184 {
185 // On Windows, even '\' is allowed in a "file" URL.
186 sepChar = File.separatorChar;
187 lastSlash = file.lastIndexOf (sepChar);
188 }
189
190 file = file.substring(0, lastSlash)
191 + sepChar + spec.substring (start, end);
192
193 if (url.getProtocol ().equals ("file"))
194 {
195 // For "file" URLs constructed relative to a context, we
196 // need to canonicalise the file path.
197 try
198 {
199 file = new File (file).getCanonicalPath ();
200 }
201 catch (IOException e)
202 {
203 }
204 }
205
206 ref = null;
207 }
208
209 if (ref == null)
210 {
211 // Normally there should be no '#' in the file part,
212 // but we are nice.
213 int hash = file.indexOf('#');
214 if (hash != -1)
215 {
216 ref = file.substring(hash + 1, file.length());
217 file = file.substring(0, hash);
218 }
219 }
220
221 // XXX - Classpath used to call PlatformHelper.toCanonicalForm() on
222 // the file part. It seems like overhead, but supposedly there is some
223 // benefit in windows based systems (it also lowercased the string).
224
225 setURL(url, url.getProtocol(), host, port, file, ref);
226 }
227
228 private static String canonicalizeFilename(String file)
229 {
230 // XXX - GNU Classpath has an implementation that might be more appropriate
231 // for Windows based systems (gnu.java.io.PlatformHelper.toCanonicalForm)
232
233 int index;
234
235 // Replace "/./" with "/". This probably isn't very efficient in
236 // the general case, but it's probably not bad most of the time.
237 while ((index = file.indexOf("/./")) >= 0)
238 file = file.substring(0, index) + file.substring(index + 2);
239
240 // Process "/../" correctly. This probably isn't very efficient in
241 // the general case, but it's probably not bad most of the time.
242 while ((index = file.indexOf("/../")) >= 0)
243 {
244 // Strip of the previous directory - if it exists.
245 int previous = file.lastIndexOf('/', index - 1);
246 if (previous >= 0)
247 file = file.substring(0, previous) + file.substring(index + 3);
248 else
249 break;
250 }
251 return file;
252 }
253
254 /**
255 * Compares two URLs, excluding the fragment component
256 *
257 * @param url1 The first url
258 * @param url2 The second url to compare with the first
259 *
260 * @specnote Now protected
261 */
262 protected boolean sameFile(URL url1, URL url2)
263 {
264 if (url1 == url2)
265 return true;
266 // This comparison is very conservative. It assumes that any
267 // field can be null.
268 if (url1 == null || url2 == null || url1.getPort() != url2.getPort())
269 return false;
270 String s1, s2;
271 s1 = url1.getProtocol();
272 s2 = url2.getProtocol();
273 if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
274 return false;
275 s1 = url1.getHost();
276 s2 = url2.getHost();
277 if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
278 return false;
279 s1 = canonicalizeFilename(url1.getFile());
280 s2 = canonicalizeFilename(url2.getFile());
281 if (s1 != s2 && (s1 == null || ! s1.equals(s2)))
282 return false;
283 return true;
284 }
285
286 /**
287 * This methods sets the instance variables representing the various fields
288 * of the URL to the values passed in.
289 *
290 * @param u The URL to modify
291 * @param protocol The protocol to set
292 * @param host The host name to et
293 * @param port The port number to set
294 * @param file The filename 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 * @deprecated 1.2 Please use
301 * #setURL(URL,String,String,int,String,String,String,String);
302 */
303 protected void setURL(URL u, String protocol, String host, int port,
304 String file, String ref)
305 {
306 u.set(protocol, host, port, file, ref);
307 }
308
309 /**
310 * Sets the fields of the URL argument to the indicated values
311 *
312 * @param u The URL to modify
313 * @param protocol The protocol to set
314 * @param host The host name to set
315 * @param port The port number to set
316 * @param authority The authority to set
317 * @param userInfo The user information to set
318 * @param path The path/filename to set
319 * @param query The query part to set
320 * @param ref The reference
321 *
322 * @exception SecurityException If the protocol handler of the URL is
323 * different from this one
324 */
325 protected void setURL(URL u, String protocol, String host, int port,
326 String authority, String userInfo, String path,
327 String query, String ref)
328 {
329 u.set(protocol, host, port, authority, userInfo, path, query, ref);
330 }
331
332 /**
333 * Provides the default equals calculation. May be overidden by handlers for
334 * other protocols that have different requirements for equals(). This method
335 * requires that none of its arguments is null. This is guaranteed by the
336 * fact that it is only called by java.net.URL class.
337 *
338 * @param url1 An URL object
339 * @param url2 An URL object
340 */
341 protected boolean equals (URL url1, URL url2)
342 {
343 // This comparison is very conservative. It assumes that any
344 // field can be null.
345 return (url1.getPort () == url2.getPort ()
346 && ((url1.getProtocol () == null && url2.getProtocol () == null)
347 || (url1.getProtocol () != null
348 && url1.getProtocol ().equals (url2.getProtocol ())))
349 && ((url1.getUserInfo () == null && url2.getUserInfo () == null)
350 || (url1.getUserInfo () != null
351 && url1.getUserInfo ().equals(url2.getUserInfo ())))
352 && ((url1.getAuthority () == null && url2.getAuthority () == null)
353 || (url1.getAuthority () != null
354 && url1.getAuthority ().equals(url2.getAuthority ())))
355 && ((url1.getHost () == null && url2.getHost () == null)
356 || (url1.getHost () != null
357 && url1.getHost ().equals(url2.getHost ())))
358 && ((url1.getPath () == null && url2.getPath () == null)
359 || (url1.getPath () != null
360 && url1.getPath ().equals (url2.getPath ())))
361 && ((url1.getQuery () == null && url2.getQuery () == null)
362 || (url1.getQuery () != null
363 && url1.getQuery ().equals(url2.getQuery ())))
364 && ((url1.getRef () == null && url2.getRef () == null)
365 || (url1.getRef () != null
366 && url1.getRef ().equals(url2.getRef ()))));
367 }
368
369 /**
370 * Compares the host components of two URLs.
371 *
372 * @exception UnknownHostException If an unknown host is found
373 */
374 protected boolean hostsEqual (URL url1, URL url2)
375 throws UnknownHostException
376 {
377 InetAddress addr1 = InetAddress.getByName (url1.getHost ());
378 InetAddress addr2 = InetAddress.getByName (url2.getHost ());
379
380 return addr1.equals (addr2);
381 }
382
383 /**
384 * Get the IP address of our host. An empty host field or a DNS failure will
385 * result in a null return.
386 */
387 protected InetAddress getHostAddress (URL url)
388 {
389 String hostname = url.getHost ();
390
391 if (hostname == "")
392 return null;
393
394 try
395 {
396 return InetAddress.getByName (hostname);
397 }
398 catch (UnknownHostException e)
399 {
400 return null;
401 }
402 }
403
404 /**
405 * Returns the default port for a URL parsed by this handler. This method is
406 * meant to be overidden by handlers with default port numbers.
407 */
408 protected int getDefaultPort ()
409 {
410 return -1;
411 }
412
413 /**
414 * Provides the default hash calculation. May be overidden by handlers for
415 * other protocols that have different requirements for hashCode calculation.
416 */
417 protected int hashCode (URL url)
418 {
419 return url.getProtocol ().hashCode () +
420 ((url.getHost () == null) ? 0 : url.getHost ().hashCode ()) +
421 url.getFile ().hashCode() +
422 url.getPort ();
423 }
424
425 /**
426 * This method converts a URL object into a String. This method creates
427 * Strings in the mold of http URL's, so protocol handlers which use URL's
428 * that have a different syntax should override this method
429 *
430 * @param url The URL object to convert
431 */
432 protected String toExternalForm(URL u)
433 {
434 String protocol, host, file, ref;
435 int port;
436
437 protocol = u.getProtocol();
438
439 // JDK 1.2 online doc infers that host could be null because it
440 // explicitly states that file cannot be null, but is silent on host.
441 host = u.getHost();
442 if (host == null)
443 host = "";
444
445 port = u.getPort();
446 file = u.getFile();
447 ref = u.getRef();
448
449 // Guess a reasonable size for the string buffer so we have to resize
450 // at most once.
451 int size = protocol.length() + host.length() + file.length() + 24;
452 StringBuffer sb = new StringBuffer(size);
453
454 sb.append(protocol);
455 sb.append(':');
456
457 if (host.length() != 0)
458 sb.append("//").append(host);
459
460 // Note that this produces different results from JDK 1.2 as JDK 1.2
461 // ignores a non-default port if host is null or "". That is inconsistent
462 // with the spec since the result of this method is spec'ed so it can be
463 // used to construct a new URL that is equivalent to the original.
464 boolean port_needed = port > 0 && port != getDefaultPort();
465 if (port_needed)
466 sb.append(':').append(port);
467
468 sb.append(file);
469
470 if (ref != null)
471 sb.append('#').append(ref);
472
473 return sb.toString();
474 }
475}
Note: See TracBrowser for help on using the repository browser.