blob: 01862f6d5c2f65b525f0d570ae46b17390d9e5ae [file] [log] [blame]
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +00001/*
Narayan Kamath2c87ad32015-12-21 13:53:32 +00002 * Copyright (C) 2014 The Android Open Source Project
Yi Kong7f4b1b82016-08-11 14:02:43 +01003 * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +00004 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation. Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package java.net;
28
29import java.io.IOException;
Narayan Kamathb93dbae2016-02-01 15:54:33 +000030import java.util.Objects;
31
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000032import sun.net.util.IPAddressUtil;
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000033
34/**
Yi Kong3a6411e2016-06-14 11:25:41 +010035 * The abstract class {@code URLStreamHandler} is the common
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000036 * superclass for all stream protocol handlers. A stream protocol
37 * handler knows how to make a connection for a particular protocol
Yi Kong3a6411e2016-06-14 11:25:41 +010038 * type, such as {@code http} or {@code https}.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000039 * <p>
Yi Kong3a6411e2016-06-14 11:25:41 +010040 * In most cases, an instance of a {@code URLStreamHandler}
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000041 * subclass is not created directly by an application. Rather, the
42 * first time a protocol name is encountered when constructing a
Yi Kong3a6411e2016-06-14 11:25:41 +010043 * {@code URL}, the appropriate stream protocol handler is
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000044 * automatically loaded.
45 *
46 * @author James Gosling
47 * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
48 * @since JDK1.0
49 */
50public abstract class URLStreamHandler {
51 /**
52 * Opens a connection to the object referenced by the
Yi Kong3a6411e2016-06-14 11:25:41 +010053 * {@code URL} argument.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000054 * This method should be overridden by a subclass.
55 *
56 * <p>If for the handler's protocol (such as HTTP or JAR), there
57 * exists a public, specialized URLConnection subclass belonging
58 * to one of the following packages or one of their subpackages:
59 * java.lang, java.io, java.util, java.net, the connection
60 * returned will be of that subclass. For example, for HTTP an
61 * HttpURLConnection will be returned, and for JAR a
62 * JarURLConnection will be returned.
63 *
64 * @param u the URL that this connects to.
Yi Kong3a6411e2016-06-14 11:25:41 +010065 * @return a {@code URLConnection} object for the {@code URL}.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000066 * @exception IOException if an I/O error occurs while opening the
67 * connection.
68 */
69 abstract protected URLConnection openConnection(URL u) throws IOException;
70
71 /**
72 * Same as openConnection(URL), except that the connection will be
73 * made through the specified proxy; Protocol handlers that do not
74 * support proxying will ignore the proxy parameter and make a
75 * normal connection.
76 *
77 * Calling this method preempts the system's default ProxySelector
78 * settings.
79 *
80 * @param u the URL that this connects to.
81 * @param p the proxy through which the connection will be made.
82 * If direct connection is desired, Proxy.NO_PROXY
83 * should be specified.
Yi Kong3a6411e2016-06-14 11:25:41 +010084 * @return a {@code URLConnection} object for the {@code URL}.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000085 * @exception IOException if an I/O error occurs while opening the
86 * connection.
87 * @exception IllegalArgumentException if either u or p is null,
88 * or p has the wrong type.
89 * @exception UnsupportedOperationException if the subclass that
90 * implements the protocol doesn't support this method.
91 * @since 1.5
92 */
93 protected URLConnection openConnection(URL u, Proxy p) throws IOException {
94 throw new UnsupportedOperationException("Method not implemented.");
95 }
96
97 /**
Yi Kong3a6411e2016-06-14 11:25:41 +010098 * Parses the string representation of a {@code URL} into a
99 * {@code URL} object.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000100 * <p>
101 * If there is any inherited context, then it has already been
Yi Kong3a6411e2016-06-14 11:25:41 +0100102 * copied into the {@code URL} argument.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000103 * <p>
Yi Kong3a6411e2016-06-14 11:25:41 +0100104 * The {@code parseURL} method of {@code URLStreamHandler}
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000105 * parses the string representation as if it were an
Yi Kong3a6411e2016-06-14 11:25:41 +0100106 * {@code http} specification. Most URL protocol families have a
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000107 * similar parsing. A stream protocol handler for a protocol that has
108 * a different syntax must override this routine.
109 *
Yi Kong3a6411e2016-06-14 11:25:41 +0100110 * @param u the {@code URL} to receive the result of parsing
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000111 * the spec.
Yi Kong3a6411e2016-06-14 11:25:41 +0100112 * @param spec the {@code String} representing the URL that
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000113 * must be parsed.
114 * @param start the character index at which to begin parsing. This is
Yi Kong3a6411e2016-06-14 11:25:41 +0100115 * just past the '{@code :}' (if there is one) that
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000116 * specifies the determination of the protocol name.
117 * @param limit the character position to stop parsing at. This is the
118 * end of the string or the position of the
Yi Kong3a6411e2016-06-14 11:25:41 +0100119 * "{@code #}" character, if present. All information
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000120 * after the sharp sign indicates an anchor.
121 */
122 protected void parseURL(URL u, String spec, int start, int limit) {
123 // These fields may receive context content if this was relative URL
124 String protocol = u.getProtocol();
125 String authority = u.getAuthority();
126 String userInfo = u.getUserInfo();
127 String host = u.getHost();
128 int port = u.getPort();
129 String path = u.getPath();
130 String query = u.getQuery();
131
132 // This field has already been parsed
133 String ref = u.getRef();
134
135 boolean isRelPath = false;
136 boolean queryOnly = false;
Victor Chang8ef423c2017-09-01 13:42:16 +0100137 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100138 boolean querySet = false;
Victor Chang8ef423c2017-09-01 13:42:16 +0100139 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000140
Yi Kong7f4b1b82016-08-11 14:02:43 +0100141// FIX: should not assume query if opaque
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000142 // Strip off the query part
143 if (start < limit) {
144 int queryStart = spec.indexOf('?');
145 queryOnly = queryStart == start;
146 if ((queryStart != -1) && (queryStart < limit)) {
147 query = spec.substring(queryStart+1, limit);
148 if (limit > queryStart)
149 limit = queryStart;
150 spec = spec.substring(0, queryStart);
Victor Chang8ef423c2017-09-01 13:42:16 +0100151 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100152 querySet = true;
Victor Chang8ef423c2017-09-01 13:42:16 +0100153 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000154 }
155 }
156
157 int i = 0;
158 // Parse the authority part if any
Victor Chang8ef423c2017-09-01 13:42:16 +0100159 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100160 // boolean isUNCName = (start <= limit - 4) &&
161 // (spec.charAt(start) == '/') &&
162 // (spec.charAt(start + 1) == '/') &&
163 // (spec.charAt(start + 2) == '/') &&
164 // (spec.charAt(start + 3) == '/');
165 boolean isUNCName = false;
Victor Chang8ef423c2017-09-01 13:42:16 +0100166 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000167 if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
168 (spec.charAt(start + 1) == '/')) {
169 start += 2;
Pete Bentleyc1295562018-07-09 11:42:50 +0100170 // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991
171 /*
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000172 i = spec.indexOf('/', start);
Yi Kong7247f6a2017-01-19 11:28:29 +0100173 if (i < 0 || i > limit) {
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000174 i = spec.indexOf('?', start);
Yi Kong7247f6a2017-01-19 11:28:29 +0100175 if (i < 0 || i > limit)
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000176 i = limit;
177 }
Pete Bentleyc1295562018-07-09 11:42:50 +0100178 */
179 LOOP: for (i = start; i < limit; i++) {
180 switch (spec.charAt(i)) {
181 case '/': // Start of path
182 case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state
183 case '?': // Start of query
184 case '#': // Start of fragment
185 break LOOP;
186 }
187 }
188 // END Android-changed: Check for all hostname termination chars. http://b/110955991
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000189
190 host = authority = spec.substring(start, i);
191
192 int ind = authority.indexOf('@');
193 if (ind != -1) {
Yi Kong7247f6a2017-01-19 11:28:29 +0100194 if (ind != authority.lastIndexOf('@')) {
195 // more than one '@' in authority. This is not server based
196 userInfo = null;
197 host = null;
198 } else {
199 userInfo = authority.substring(0, ind);
200 host = authority.substring(ind+1);
201 }
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000202 } else {
203 userInfo = null;
204 }
205 if (host != null) {
206 // If the host is surrounded by [ and ] then its an IPv6
207 // literal address as specified in RFC2732
208 if (host.length()>0 && (host.charAt(0) == '[')) {
209 if ((ind = host.indexOf(']')) > 2) {
210
211 String nhost = host ;
212 host = nhost.substring(0,ind+1);
213 if (!IPAddressUtil.
214 isIPv6LiteralAddress(host.substring(1, ind))) {
215 throw new IllegalArgumentException(
216 "Invalid host: "+ host);
217 }
218
219 port = -1 ;
220 if (nhost.length() > ind+1) {
221 if (nhost.charAt(ind+1) == ':') {
222 ++ind ;
223 // port can be null according to RFC2396
224 if (nhost.length() > (ind + 1)) {
225 port = Integer.parseInt(nhost.substring(ind+1));
226 }
227 } else {
228 throw new IllegalArgumentException(
229 "Invalid authority field: " + authority);
230 }
231 }
232 } else {
233 throw new IllegalArgumentException(
234 "Invalid authority field: " + authority);
235 }
236 } else {
237 ind = host.indexOf(':');
238 port = -1;
239 if (ind >= 0) {
240 // port can be null according to RFC2396
241 if (host.length() > (ind + 1)) {
Victor Chang8ef423c2017-09-01 13:42:16 +0100242 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100243 // port = Integer.parseInt(host.substring(ind + 1));
244 char firstPortChar = host.charAt(ind+1);
245 if (firstPortChar >= '0' && firstPortChar <= '9') {
246 port = Integer.parseInt(host.substring(ind + 1));
247 } else {
248 throw new IllegalArgumentException("invalid port: " +
249 host.substring(ind + 1));
250 }
Victor Chang8ef423c2017-09-01 13:42:16 +0100251 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000252 }
253 host = host.substring(0, ind);
254 }
255 }
256 } else {
257 host = "";
258 }
259 if (port < -1)
260 throw new IllegalArgumentException("Invalid port number :" +
261 port);
262 start = i;
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100263
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000264 // If the authority is defined then the path is defined by the
265 // spec only; See RFC 2396 Section 5.2.4.
Victor Chang8ef423c2017-09-01 13:42:16 +0100266 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100267 // if (authority != null && authority.length() > 0)
268 // path = "";
269 path = null;
270 if (!querySet) {
271 query = null;
272 }
Victor Chang8ef423c2017-09-01 13:42:16 +0100273 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000274 }
275
276 if (host == null) {
277 host = "";
278 }
279
280 // Parse the file path if any
281 if (start < limit) {
Pete Bentleyc1295562018-07-09 11:42:50 +0100282 // Android-changed: Check for all hostname termination chars. http://b/110955991
283 // if (spec.charAt(start) == '/') {
284 if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') {
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000285 path = spec.substring(start, limit);
286 } else if (path != null && path.length() > 0) {
287 isRelPath = true;
288 int ind = path.lastIndexOf('/');
289 String seperator = "";
290 if (ind == -1 && authority != null)
291 seperator = "/";
292 path = path.substring(0, ind + 1) + seperator +
293 spec.substring(start, limit);
294
295 } else {
296 String seperator = (authority != null) ? "/" : "";
297 path = seperator + spec.substring(start, limit);
298 }
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000299 }
Victor Chang8ef423c2017-09-01 13:42:16 +0100300 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniake4dc89b2015-07-21 10:54:27 +0100301 //else if (queryOnly && path != null) {
302 // int ind = path.lastIndexOf('/');
303 // if (ind < 0)
304 // ind = 0;
305 // path = path.substring(0, ind) + "/";
306 //}
Victor Chang8ef423c2017-09-01 13:42:16 +0100307 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000308 if (path == null)
309 path = "";
310
Tobias Thierer6975f842017-03-01 17:51:53 +0000311 // BEGIN Android-changed
Przemyslaw Szczepaniaka53c8892015-07-21 09:39:07 +0100312 //if (isRelPath) {
313 if (true) {
Tobias Thierer6975f842017-03-01 17:51:53 +0000314 // END Android-changed
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000315 // Remove embedded /./
316 while ((i = path.indexOf("/./")) >= 0) {
317 path = path.substring(0, i) + path.substring(i + 2);
318 }
319 // Remove embedded /../ if possible
320 i = 0;
321 while ((i = path.indexOf("/../", i)) >= 0) {
Victor Chang8ef423c2017-09-01 13:42:16 +0100322 // BEGIN Android-changed: App compat
Przemyslaw Szczepaniake4dc89b2015-07-21 10:54:27 +0100323 /*
324 * Trailing /../
325 */
326 if (i == 0) {
327 path = path.substring(i + 3);
328 i = 0;
Victor Chang8ef423c2017-09-01 13:42:16 +0100329 // END Android-changed: App compat
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000330 /*
331 * A "/../" will cancel the previous segment and itself,
332 * unless that segment is a "/../" itself
333 * i.e. "/a/b/../c" becomes "/a/c"
334 * but "/../../a" should stay unchanged
335 */
Victor Chang8ef423c2017-09-01 13:42:16 +0100336 // Android-changed: App compat
337 // if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
Przemyslaw Szczepaniake4dc89b2015-07-21 10:54:27 +0100338 } else if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000339 (path.indexOf("/../", limit) != 0)) {
340 path = path.substring(0, limit) + path.substring(i + 3);
341 i = 0;
342 } else {
343 i = i + 3;
344 }
345 }
346 // Remove trailing .. if possible
347 while (path.endsWith("/..")) {
348 i = path.indexOf("/..");
349 if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
350 path = path.substring(0, limit+1);
351 } else {
352 break;
353 }
354 }
355 // Remove starting .
356 if (path.startsWith("./") && path.length() > 2)
357 path = path.substring(2);
358
359 // Remove trailing .
360 if (path.endsWith("/."))
361 path = path.substring(0, path.length() -1);
Przemyslaw Szczepaniake56459a2016-04-04 15:02:56 +0100362
Victor Chang8ef423c2017-09-01 13:42:16 +0100363 // Android-changed: App compat: Remove trailing ?
Przemyslaw Szczepaniake56459a2016-04-04 15:02:56 +0100364 if (path.endsWith("?"))
365 path = path.substring(0, path.length() -1);
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000366 }
367
368 setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
369 }
370
371 /**
372 * Returns the default port for a URL parsed by this handler. This method
373 * is meant to be overidden by handlers with default port numbers.
Yi Kong3a6411e2016-06-14 11:25:41 +0100374 * @return the default port for a {@code URL} parsed by this handler.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000375 * @since 1.3
376 */
377 protected int getDefaultPort() {
378 return -1;
379 }
380
381 /**
382 * Provides the default equals calculation. May be overidden by handlers
383 * for other protocols that have different requirements for equals().
384 * This method requires that none of its arguments is null. This is
385 * guaranteed by the fact that it is only called by java.net.URL class.
386 * @param u1 a URL object
387 * @param u2 a URL object
Yi Kong3a6411e2016-06-14 11:25:41 +0100388 * @return {@code true} if the two urls are
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000389 * considered equal, ie. they refer to the same
390 * fragment in the same file.
391 * @since 1.3
392 */
393 protected boolean equals(URL u1, URL u2) {
Victor Chang8ef423c2017-09-01 13:42:16 +0100394 // Android-changed: Avoid network I/O
Narayan Kamathb93dbae2016-02-01 15:54:33 +0000395 return Objects.equals(u1.getRef(), u2.getRef()) &&
396 Objects.equals(u1.getQuery(), u2.getQuery()) &&
397 // sameFile compares the protocol, file, port & host components of
398 // the URLs.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000399 sameFile(u1, u2);
400 }
401
402 /**
403 * Provides the default hash calculation. May be overidden by handlers for
404 * other protocols that have different requirements for hashCode
405 * calculation.
406 * @param u a URL object
Yi Kong3a6411e2016-06-14 11:25:41 +0100407 * @return an {@code int} suitable for hash table indexing
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000408 * @since 1.3
409 */
410 protected int hashCode(URL u) {
Victor Chang8ef423c2017-09-01 13:42:16 +0100411 // Android-changed: Avoid network I/O
Narayan Kamathb93dbae2016-02-01 15:54:33 +0000412 // Hash on the same set of fields that we compare in equals().
413 return Objects.hash(
414 u.getRef(),
415 u.getQuery(),
416 u.getProtocol(),
417 u.getFile(),
418 u.getHost(),
419 u.getPort());
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000420 }
421
422 /**
423 * Compare two urls to see whether they refer to the same file,
424 * i.e., having the same protocol, host, port, and path.
425 * This method requires that none of its arguments is null. This is
426 * guaranteed by the fact that it is only called indirectly
427 * by java.net.URL class.
428 * @param u1 a URL object
429 * @param u2 a URL object
430 * @return true if u1 and u2 refer to the same file
431 * @since 1.3
432 */
433 protected boolean sameFile(URL u1, URL u2) {
434 // Compare the protocols.
435 if (!((u1.getProtocol() == u2.getProtocol()) ||
436 (u1.getProtocol() != null &&
437 u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
438 return false;
439
440 // Compare the files.
441 if (!(u1.getFile() == u2.getFile() ||
442 (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
443 return false;
444
445 // Compare the ports.
446 int port1, port2;
447 port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
448 port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
449 if (port1 != port2)
450 return false;
451
452 // Compare the hosts.
453 if (!hostsEqual(u1, u2))
454 return false;
455
456 return true;
457 }
458
459 /**
460 * Get the IP address of our host. An empty host field or a DNS failure
461 * will result in a null return.
462 *
463 * @param u a URL object
Yi Kong3a6411e2016-06-14 11:25:41 +0100464 * @return an {@code InetAddress} representing the host
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000465 * IP address.
466 * @since 1.3
467 */
468 protected synchronized InetAddress getHostAddress(URL u) {
469 if (u.hostAddress != null)
470 return u.hostAddress;
471
472 String host = u.getHost();
473 if (host == null || host.equals("")) {
474 return null;
475 } else {
476 try {
477 u.hostAddress = InetAddress.getByName(host);
478 } catch (UnknownHostException ex) {
479 return null;
480 } catch (SecurityException se) {
481 return null;
482 }
483 }
484 return u.hostAddress;
485 }
486
487 /**
488 * Compares the host components of two URLs.
489 * @param u1 the URL of the first host to compare
490 * @param u2 the URL of the second host to compare
Yi Kong3a6411e2016-06-14 11:25:41 +0100491 * @return {@code true} if and only if they
492 * are equal, {@code false} otherwise.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000493 * @since 1.3
494 */
495 protected boolean hostsEqual(URL u1, URL u2) {
Tobias Thierer6975f842017-03-01 17:51:53 +0000496 // Android-changed: Don't compare the InetAddresses of the hosts.
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100497 if (u1.getHost() != null && u2.getHost() != null)
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000498 return u1.getHost().equalsIgnoreCase(u2.getHost());
499 else
500 return u1.getHost() == null && u2.getHost() == null;
501 }
502
503 /**
Yi Kong3a6411e2016-06-14 11:25:41 +0100504 * Converts a {@code URL} of a specific protocol to a
505 * {@code String}.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000506 *
507 * @param u the URL.
Yi Kong3a6411e2016-06-14 11:25:41 +0100508 * @return a string representation of the {@code URL} argument.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000509 */
510 protected String toExternalForm(URL u) {
Yi Kong3a6411e2016-06-14 11:25:41 +0100511
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000512 // pre-compute length of StringBuffer
513 int len = u.getProtocol().length() + 1;
514 if (u.getAuthority() != null && u.getAuthority().length() > 0)
515 len += 2 + u.getAuthority().length();
516 if (u.getPath() != null) {
517 len += u.getPath().length();
518 }
519 if (u.getQuery() != null) {
520 len += 1 + u.getQuery().length();
521 }
522 if (u.getRef() != null)
523 len += 1 + u.getRef().length();
524
Victor Chang8ef423c2017-09-01 13:42:16 +0100525 // BEGIN Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
526 // TODO: The variant has been removed. We can potentially revert the change
Piotr Jastrzebskif7ab2bc2015-05-06 14:00:00 +0100527 StringBuilder result = new StringBuilder(len);
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000528 result.append(u.getProtocol());
529 result.append(":");
Przemyslaw Szczepaniak06fc5c32015-07-21 17:20:27 +0100530 if (u.getAuthority() != null) {// ANDROID: && u.getAuthority().length() > 0) {
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000531 result.append("//");
Narayan Kamathfe6fe172016-02-02 11:20:29 +0000532 result.append(u.getAuthority());
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000533 }
Piotr Jastrzebskif7ab2bc2015-05-06 14:00:00 +0100534 String fileAndQuery = u.getFile();
535 if (fileAndQuery != null) {
Narayan Kamathfe6fe172016-02-02 11:20:29 +0000536 result.append(fileAndQuery);
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000537 }
Victor Chang8ef423c2017-09-01 13:42:16 +0100538 // END Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000539 if (u.getRef() != null) {
540 result.append("#");
Narayan Kamathfe6fe172016-02-02 11:20:29 +0000541 result.append(u.getRef());
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000542 }
543 return result.toString();
544 }
545
546 /**
Yi Kong3a6411e2016-06-14 11:25:41 +0100547 * Sets the fields of the {@code URL} argument to the indicated values.
548 * Only classes derived from URLStreamHandler are able
549 * to use this method to set the values of the URL fields.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000550 *
551 * @param u the URL to modify.
552 * @param protocol the protocol name.
553 * @param host the remote host value for the URL.
554 * @param port the port on the remote machine.
555 * @param authority the authority part for the URL.
556 * @param userInfo the userInfo part of the URL.
557 * @param path the path component of the URL.
558 * @param query the query part for the URL.
559 * @param ref the reference.
560 * @exception SecurityException if the protocol handler of the URL is
561 * different from this one
562 * @see java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
563 * @since 1.3
564 */
565 protected void setURL(URL u, String protocol, String host, int port,
566 String authority, String userInfo, String path,
567 String query, String ref) {
568 if (this != u.handler) {
569 throw new SecurityException("handler for url different from " +
570 "this handler");
571 }
572 // ensure that no one can reset the protocol on a given URL.
573 u.set(u.getProtocol(), host, port, authority, userInfo, path, query, ref);
574 }
575
576 /**
Yi Kong3a6411e2016-06-14 11:25:41 +0100577 * Sets the fields of the {@code URL} argument to the indicated values.
578 * Only classes derived from URLStreamHandler are able
579 * to use this method to set the values of the URL fields.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000580 *
581 * @param u the URL to modify.
582 * @param protocol the protocol name. This value is ignored since 1.2.
583 * @param host the remote host value for the URL.
584 * @param port the port on the remote machine.
585 * @param file the file.
586 * @param ref the reference.
587 * @exception SecurityException if the protocol handler of the URL is
588 * different from this one
589 * @deprecated Use setURL(URL, String, String, int, String, String, String,
590 * String);
591 */
592 @Deprecated
593 protected void setURL(URL u, String protocol, String host, int port,
594 String file, String ref) {
595 /*
596 * Only old URL handlers call this, so assume that the host
597 * field might contain "user:passwd@host". Fix as necessary.
598 */
599 String authority = null;
600 String userInfo = null;
601 if (host != null && host.length() != 0) {
602 authority = (port == -1) ? host : host + ":" + port;
603 int at = host.lastIndexOf('@');
604 if (at != -1) {
605 userInfo = host.substring(0, at);
606 host = host.substring(at+1);
607 }
608 }
609
610 /*
611 * Assume file might contain query part. Fix as necessary.
612 */
613 String path = null;
614 String query = null;
615 if (file != null) {
616 int q = file.lastIndexOf('?');
617 if (q != -1) {
618 query = file.substring(q+1);
619 path = file.substring(0, q);
620 } else
621 path = file;
622 }
623 setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
624 }
625}