URLStreamHandler.java revision 8fd0225a5c3918fe0cd4680258388985c25533e5
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.net;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
21e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilsonimport libcore.base.Objects;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.util.URLUtil;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The abstract class {@code URLStreamHandler} is the base for all classes which
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * can handle the communication with a URL object over a particular protocol
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * type.
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class URLStreamHandler {
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Establishes a new connection to the resource specified by the URL {@code
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * u}. Since different protocols also have unique ways of connecting, it
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * must be overwritten by the subclass.
34f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param u
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL to the resource where a connection has to be opened.
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the opened URLConnection to the specified resource.
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an I/O error occurs during opening the connection.
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract URLConnection openConnection(URL u) throws IOException;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Establishes a new connection to the resource specified by the URL {@code
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * u} using the given {@code proxy}. Since different protocols also have
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * unique ways of connecting, it must be overwritten by the subclass.
47f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param u
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL to the resource where a connection has to be opened.
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param proxy
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the proxy that is used to make the connection.
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the opened URLConnection to the specified resource.
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an I/O error occurs during opening the connection.
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any argument is {@code null} or the type of proxy is
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             wrong.
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnsupportedOperationException
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the protocol handler doesn't support this method.
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
61b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    protected URLConnection openConnection(URL u, Proxy proxy) throws IOException {
62b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        throw new UnsupportedOperationException();
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the clear text URL in {@code str} into a URL object. URL strings
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * generally have the following format:
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * http://www.company.com/java/file1.java#reference
70f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * <p>
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The string is parsed in HTTP format. If the protocol has a different URL
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * format this method must be overridden.
73f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param u
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL to fill in the parsed clear text URL parts.
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param str
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL string that is to be parsed.
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param start
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the string position from where to begin parsing.
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param end
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the string position to stop parsing.
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #toExternalForm
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see URL
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void parseURL(URL u, String str, int start, int end) {
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // For compatibility, refer to Harmony-2941
87f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (str.startsWith("//", start)
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && str.indexOf('/', start + 2) == -1
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && end <= Integer.MIN_VALUE + 1) {
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new StringIndexOutOfBoundsException(end - 2 - start);
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (end < start) {
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (this != u.strmHandler) {
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new SecurityException();
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
98f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        String parseString = "";
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (start < end) {
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parseString = str.substring(start, end);
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        end -= start;
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int fileIdx = 0;
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Default is to use info from context
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String host = u.getHost();
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int port = u.getPort();
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String ref = u.getRef();
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String file = u.getPath();
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String query = u.getQuery();
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String authority = u.getAuthority();
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String userInfo = u.getUserInfo();
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int refIdx = parseString.indexOf('#', 0);
115f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (parseString.startsWith("//")) {
1168fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            int hostIdx = 2;
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            port = -1;
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            fileIdx = parseString.indexOf('/', hostIdx);
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int questionMarkIndex = parseString.indexOf('?', hostIdx);
1208fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            if (questionMarkIndex != -1 && (fileIdx == -1 || fileIdx > questionMarkIndex)) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                fileIdx = questionMarkIndex;
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (fileIdx == -1) {
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                fileIdx = end;
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Use default
126f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                file = "";
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int hostEnd = fileIdx;
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (refIdx != -1 && refIdx < fileIdx) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                hostEnd = refIdx;
1318fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                fileIdx = refIdx;
1328fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                file = "";
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int userIdx = parseString.lastIndexOf('@', hostEnd);
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            authority = parseString.substring(hostIdx, hostEnd);
1368fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            if (userIdx != -1) {
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                userInfo = parseString.substring(hostIdx, userIdx);
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                hostIdx = userIdx + 1;
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1418fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            int endOfIPv6Addr = parseString.indexOf(']', hostIdx);
1428fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            if (endOfIPv6Addr >= hostEnd) {
1438fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                endOfIPv6Addr = -1;
1448fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            }
1458fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson
1468fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            // the port separator must be immediately after an IPv6 address "http://[::1]:80/"
1478fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            int portIdx = -1;
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (endOfIPv6Addr != -1) {
1498fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                int maybeColon = endOfIPv6Addr + 1;
1508fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                if (maybeColon < hostEnd && parseString.charAt(maybeColon) == ':') {
1518fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                    portIdx = maybeColon;
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
1538fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            } else {
1548fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson                portIdx = parseString.indexOf(':', hostIdx);
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1578fd0225a5c3918fe0cd4680258388985c25533e5Jesse Wilson            if (portIdx == -1 || portIdx > hostEnd) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                host = parseString.substring(hostIdx, hostEnd);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                host = parseString.substring(hostIdx, portIdx);
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String portString = parseString.substring(portIdx + 1, hostEnd);
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (portString.length() == 0) {
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    port = -1;
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    port = Integer.parseInt(portString);
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (refIdx > -1) {
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ref = parseString.substring(refIdx + 1, end);
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int fileEnd = (refIdx == -1 ? end : refIdx);
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int queryIdx = parseString.lastIndexOf('?', fileEnd);
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean canonicalize = false;
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (queryIdx > -1) {
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            query = parseString.substring(queryIdx + 1, fileEnd);
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (queryIdx == 0 && file != null) {
18080a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes                if (file.isEmpty()) {
181f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    file = "/";
182f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                } else if (file.startsWith("/")) {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    canonicalize = true;
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int last = file.lastIndexOf('/') + 1;
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                file = file.substring(0, last);
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            fileEnd = queryIdx;
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Don't inherit query unless only the ref is changed
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (refIdx != 0) {
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            query = null;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fileIdx > -1) {
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (fileIdx < end && parseString.charAt(fileIdx) == '/') {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                file = parseString.substring(fileIdx, fileEnd);
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (fileEnd > fileIdx) {
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (file == null) {
200f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    file = "";
20180a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes                } else if (file.isEmpty()) {
202f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    file = "/";
203f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                } else if (file.startsWith("/")) {
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    canonicalize = true;
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int last = file.lastIndexOf('/') + 1;
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (last == 0) {
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    file = parseString.substring(fileIdx, fileEnd);
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    file = file.substring(0, last)
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            + parseString.substring(fileIdx, fileEnd);
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (file == null) {
216f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            file = "";
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (host == null) {
220f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            host = "";
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (canonicalize) {
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // modify file if there's any relative referencing
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            file = URLUtil.canonicalizePath(file);
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        setURL(u, u.getProtocol(), host, port, authority, userInfo, file,
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                query, ref);
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the fields of the URL {@code u} to the values of the supplied
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * arguments.
235f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param u
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the non-null URL object to be set.
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param protocol
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the protocol.
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param host
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the host name.
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param port
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the port number.
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param file
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the file component.
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param ref
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the reference.
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @deprecated use setURL(URL, String String, int, String, String, String,
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             String, String) instead.
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Deprecated
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void setURL(URL u, String protocol, String host, int port,
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String file, String ref) {
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (this != u.strmHandler) {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new SecurityException();
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        u.set(protocol, host, port, file, ref);
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the fields of the URL {@code u} to the values of the supplied
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * arguments.
263f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param u
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the non-null URL object to be set.
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param protocol
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the protocol.
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param host
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the host name.
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param port
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the port number.
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param authority
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the authority.
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param userInfo
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the user info.
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param file
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the file component.
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param query
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the query.
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param ref
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the reference.
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void setURL(URL u, String protocol, String host, int port,
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String authority, String userInfo, String file, String query,
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String ref) {
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (this != u.strmHandler) {
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new SecurityException();
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        u.set(protocol, host, port, authority, userInfo, file, query, ref);
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the clear text representation of a given URL using HTTP format.
294f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL object to be converted.
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the clear text representation of the specified URL.
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #parseURL
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see URL#toExternalForm()
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected String toExternalForm(URL url) {
302a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        StringBuilder answer = new StringBuilder();
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        answer.append(url.getProtocol());
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        answer.append(':');
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String authority = url.getAuthority();
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (authority != null && authority.length() > 0) {
307f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            answer.append("//");
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            answer.append(url.getAuthority());
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String file = url.getFile();
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String ref = url.getRef();
313a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        if (file != null) {
314a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson            answer.append(file);
315a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson        }
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (ref != null) {
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            answer.append('#');
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            answer.append(ref);
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return answer.toString();
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares two URL objects whether they represent the same URL. Two URLs
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * are equal if they have the same file, host, port, protocol, query, and
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * reference components.
327f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url1
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the first URL to compare.
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url2
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the second URL to compare.
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if the URLs are the same, {@code false} otherwise.
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #hashCode
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean equals(URL url1, URL url2) {
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!sameFile(url1, url2)) {
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
339e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson        return Objects.equal(url1.getRef(), url2.getRef())
340e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson                && Objects.equal(url1.getQuery(), url2.getQuery());
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the default port of the protocol used by the handled URL. The
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * current implementation returns always {@code -1}.
346f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the appropriate default port number of the protocol.
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int getDefaultPort() {
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return -1;
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the host address of the given URL.
355f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL object where to read the host address from.
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the host address of the specified URL.
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected InetAddress getHostAddress(URL url) {
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String host = url.getHost();
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (host == null || host.length() == 0) {
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return InetAddress.getByName(host);
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (UnknownHostException e) {
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the hashcode value for the given URL object.
374f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the URL to determine the hashcode.
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the hashcode of the given URL.
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int hashCode(URL url) {
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return toExternalForm(url).hashCode();
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares two URL objects whether they refer to the same host.
385f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
38667db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson     * @param a the first URL to be compared.
38767db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson     * @param b the second URL to be compared.
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if both URLs refer to the same host, {@code false}
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
39167db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson    protected boolean hostsEqual(URL a, URL b) {
39267db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        /*
39367db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * URLs with the same case-insensitive host name have equal hosts
39467db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         */
39567db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        String aHost = getHost(a);
39667db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        String bHost = getHost(b);
39767db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        if (aHost != null && aHost.equalsIgnoreCase(bHost)) {
39867db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson            return true;
39967db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        }
40067db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson
40167db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        /*
40267db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * Call out to DNS to resolve the host addresses. If this succeeds for
40367db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * both addresses and both addresses yield the same InetAddress, report
40467db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * equality.
40567db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         *
40667db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * Although it's consistent with historical behavior of the RI, this
40767db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * approach is fundamentally broken. In particular, acting upon this
40867db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * result is bogus because a single server may serve content for many
40967db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         * unrelated host names.
41067db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson         */
41167db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        InetAddress aResolved = getHostAddress(a);
41267db542e53c47a28e3f96beb7c9e46330483dc40Jesse Wilson        return aResolved != null && aResolved.equals(getHostAddress(b));
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares two URL objects whether they refer to the same file. In the
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * comparison included are the URL components protocol, host, port and file.
418f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url1
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the first URL to be compared.
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param url2
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the second URL to be compared.
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if both URLs refer to the same file, {@code false}
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean sameFile(URL url1, URL url2) {
427e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson        return Objects.equal(url1.getProtocol(), url2.getProtocol())
428e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson                && Objects.equal(url1.getFile(), url2.getFile())
429e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson                && hostsEqual(url1, url2)
430e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson                && url1.getEffectivePort() == url2.getEffectivePort();
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If the URL host is empty while protocal is file, the host is regarded as
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * localhost.
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static String getHost(URL url) {
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String host = url.getHost();
43980a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes        if ("file".equals(url.getProtocol()) && host.isEmpty()) {
440f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            host = "localhost";
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return host;
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
445