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;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
228f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilsonimport java.io.ObjectInputStream;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ObjectOutputStream;
248f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilsonimport java.io.Serializable;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Hashtable;
268f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilsonimport java.util.jar.JarFile;
275aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilsonimport libcore.net.url.FileHandler;
285aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilsonimport libcore.net.url.FtpHandler;
295aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilsonimport libcore.net.url.JarHandler;
305292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilsonimport libcore.net.url.UrlUtils;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
338f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * A Uniform Resource Locator that identifies the location of an Internet
348f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * resource as specified by <a href="http://www.ietf.org/rfc/rfc1738.txt">RFC
358f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * 1738</a>.
368f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *
378f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <h3>Parts of a URL</h3>
388f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * A URL is composed of many parts. This class can both parse URL strings into
398f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * parts and compose URL strings from parts. For example, consider the parts of
408f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * this URL:
418f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * {@code http://username:password@host:8080/directory/file?query#ref}:
428f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <table>
438f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><th>Component</th><th>Example value</th><th>Also known as</th></tr>
448f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getProtocol() Protocol}</td><td>{@code http}</td><td>scheme</td></tr>
458f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getAuthority() Authority}</td><td>{@code username:password@host:8080}</td><td></td></tr>
468f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getUserInfo() User Info}</td><td>{@code username:password}</td><td></td></tr>
478f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getHost() Host}</td><td>{@code host}</td><td></td></tr>
488f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getPort() Port}</td><td>{@code 8080}</td><td></td></tr>
498f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getFile() File}</td><td>{@code /directory/file?query}</td><td></td></tr>
508f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getPath() Path}</td><td>{@code /directory/file}</td><td></td></tr>
518f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getQuery() Query}</td><td>{@code query}</td><td></td></tr>
528f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <tr><td>{@link #getRef() Ref}</td><td>{@code ref}</td><td>fragment</td></tr>
538f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * </table>
548f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *
558f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <h3>Supported Protocols</h3>
568f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * This class may be used to construct URLs with the following protocols:
578f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <ul>
588f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <li><strong>file</strong>: read files from the local filesystem.
598f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <li><strong>ftp</strong>: <a href="http://www.ietf.org/rfc/rfc959.txt">File
608f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *     Transfer Protocol</a>
618f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <li><strong>http</strong>: <a href="http://www.ietf.org/rfc/rfc2616.txt">Hypertext
628f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *     Transfer Protocol</a>
638f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <li><strong>https</strong>: <a href="http://www.ietf.org/rfc/rfc2818.txt">HTTP
648f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *     over TLS</a>
658f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <li><strong>jar</strong>: read {@link JarFile Jar files} from the
668f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *     filesystem</li>
678f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * </ul>
688f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * In general, attempts to create URLs with any other protocol will fail with a
698f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * {@link MalformedURLException}. Applications may install handlers for other
708f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * schemes using {@link #setURLStreamHandlerFactory} or with the {@code
718f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * java.protocol.handler.pkgs} system property.
728f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson *
738f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson * <p>The {@link URI} class can be used to manipulate URLs of any protocol.
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
758f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilsonpublic final class URL implements Serializable {
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final long serialVersionUID = -7627629688361524110L;
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
788f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private static URLStreamHandlerFactory streamHandlerFactory;
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
808f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    /** Cache of protocols to their handlers */
818f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private static final Hashtable<String, URLStreamHandler> streamHandlers
828f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            = new Hashtable<String, URLStreamHandler>();
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
848f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private String protocol;
858f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private String authority;
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String host;
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int port = -1;
888f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private String file;
898f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private String ref;
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
918f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private transient String userInfo;
928f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private transient String path;
938f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private transient String query;
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
958f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    transient URLStreamHandler streamHandler;
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
988f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * The cached hash code, or 0 if it hasn't been computed yet. Unlike the RI,
998f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * this implementation's hashCode is transient because the hash code is
1008f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * unspecified and may vary between VMs or versions.
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1028f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private transient int hashCode;
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1058f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Sets the stream handler factory for this VM.
106f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1078f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws Error if a URLStreamHandlerFactory has already been installed
1088f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     for the current VM.
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1108f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory factory) {
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (streamHandlerFactory != null) {
112b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new Error("Factory already set");
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
114c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        streamHandlers.clear();
1158f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        streamHandlerFactory = factory;
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1198f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Creates a new URL instance by parsing {@code spec}.
120f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1218f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if {@code spec} could not be parsed as a
1228f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     URL.
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URL(String spec) throws MalformedURLException {
1258f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        this((URL) null, spec, null);
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1298f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Creates a new URL by resolving {@code spec} relative to {@code context}.
130f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1318f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param context the URL to which {@code spec} is relative, or null for
1328f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     no context in which case {@code spec} must be an absolute URL.
1338f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if {@code spec} could not be parsed as a
1348f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     URL or has an unsupported protocol.
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URL(URL context, String spec) throws MalformedURLException {
1378f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        this(context, spec, null);
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1418f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Creates a new URL by resolving {@code spec} relative to {@code context}.
142f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1438f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param context the URL to which {@code spec} is relative, or null for
1448f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     no context in which case {@code spec} must be an absolute URL.
1458f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param handler the stream handler for this URL, or null for the
1468f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     protocol's default stream handler.
1478f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if the given string {@code spec} could not
1488f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     be parsed as a URL or an invalid protocol has been found.
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
150ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes    public URL(URL context, String spec, URLStreamHandler handler) throws MalformedURLException {
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (spec == null) {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new MalformedURLException();
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1545292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        if (handler != null) {
1555292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            streamHandler = handler;
1565292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        }
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        spec = spec.trim();
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1595292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        protocol = UrlUtils.getSchemePrefix(spec);
1605292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        int schemeSpecificPartStart = protocol != null ? (protocol.length() + 1) : 0;
1615292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson
1625292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        // If the context URL has a different protocol, discard it because we can't use it.
1635292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        if (protocol != null && context != null && !protocol.equals(context.protocol)) {
1645292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            context = null;
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1675292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        // Inherit from the context URL if it exists.
1685292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        if (context != null) {
1695292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            set(context.protocol, context.getHost(), context.getPort(), context.getAuthority(),
1705292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson                    context.getUserInfo(), context.getPath(), context.getQuery(),
1715292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson                    context.getRef());
1728f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            if (streamHandler == null) {
1738f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson                streamHandler = context.streamHandler;
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1755292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        } else if (protocol == null) {
1765292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            throw new MalformedURLException("Protocol not found: " + spec);
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1798f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (streamHandler == null) {
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setupStreamHandler();
1818f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            if (streamHandler == null) {
182b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new MalformedURLException("Unknown protocol: " + protocol);
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1865292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        // Parse the URL. If the handler throws any exception, throw MalformedURLException instead.
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
1885292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            streamHandler.parseURL(this, spec, schemeSpecificPartStart, spec.length());
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new MalformedURLException(e.toString());
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1958f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Creates a new URL of the given component parts. The URL uses the
1968f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * protocol's default port.
197f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1988f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if the combination of all arguments do not
1998f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     represent a valid URL or if the protocol is invalid.
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2018f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public URL(String protocol, String host, String file) throws MalformedURLException {
2028f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        this(protocol, host, -1, file, null);
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2068f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Creates a new URL of the given component parts. The URL uses the
2078f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * protocol's default port.
208f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
2098f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param host the host name or IP address of the new URL.
2108f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param port the port, or {@code -1} for the protocol's default port.
2118f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param file the name of the resource.
2128f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if the combination of all arguments do not
2138f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     represent a valid URL or if the protocol is invalid.
2148f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     */
2158f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public URL(String protocol, String host, int port, String file) throws MalformedURLException {
2168f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        this(protocol, host, port, file, null);
2178f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    }
2188f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson
2198f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    /**
2208f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Creates a new URL of the given component parts. The URL uses the
2218f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * protocol's default port.
222f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
2238f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param host the host name or IP address of the new URL.
2248f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param port the port, or {@code -1} for the protocol's default port.
2258f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param file the name of the resource.
2268f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param handler the stream handler for this URL, or null for the
2278f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     protocol's default stream handler.
2288f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if the combination of all arguments do not
2298f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     represent a valid URL or if the protocol is invalid.
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URL(String protocol, String host, int port, String file,
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            URLStreamHandler handler) throws MalformedURLException {
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (port < -1) {
2345292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            throw new MalformedURLException("port < -1: " + port);
2355292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        }
2365292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        if (protocol == null) {
2375292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            throw new NullPointerException("protocol == null");
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2405292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        // Wrap IPv6 addresses in square brackets if they aren't already.
2418f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (host != null && host.contains(":") && host.charAt(0) != '[') {
242f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            host = "[" + host + "]";
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
245f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.protocol = protocol;
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.host = host;
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.port = port;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
249c68609e723a5daa20888abdb640799d4353fd590Jesse Wilson        file = UrlUtils.authoritySafePath(host, file);
2505292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Set the fields from the arguments. Handle the case where the
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // passed in "file" includes both a file and a reference part.
253c68609e723a5daa20888abdb640799d4353fd590Jesse Wilson        int hash = file.indexOf("#");
254c68609e723a5daa20888abdb640799d4353fd590Jesse Wilson        if (hash != -1) {
255c68609e723a5daa20888abdb640799d4353fd590Jesse Wilson            this.file = file.substring(0, hash);
256c68609e723a5daa20888abdb640799d4353fd590Jesse Wilson            this.ref = file.substring(hash + 1);
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.file = file;
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        fixURL(false);
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Set the stream handler for the URL either to the handler
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // argument if it was specified, or to the default for the
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // receiver's protocol if the handler was null.
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (handler == null) {
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setupStreamHandler();
2678f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            if (streamHandler == null) {
268b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new MalformedURLException("Unknown protocol: " + protocol);
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
2718f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            streamHandler = handler;
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    void fixURL(boolean fixHost) {
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index;
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (host != null && host.length() > 0) {
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            authority = host;
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (port != -1) {
280f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                authority = authority + ":" + port;
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fixHost) {
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (host != null && (index = host.lastIndexOf('@')) > -1) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                userInfo = host.substring(0, index);
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                host = host.substring(index + 1);
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                userInfo = null;
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (file != null && (index = file.indexOf('?')) > -1) {
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            query = file.substring(index + 1);
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            path = file.substring(0, index);
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            query = null;
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            path = file;
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the properties of this URL using the provided arguments. Only a
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code URLStreamHandler} can use this method to set fields of the
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * existing URL instance. A URL is generally constant.
3048f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     */
3058f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    protected void set(String protocol, String host, int port, String file, String ref) {
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (this.protocol == null) {
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.protocol = protocol;
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.host = host;
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.file = file;
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.port = port;
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.ref = ref;
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        hashCode = 0;
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        fixURL(true);
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
3187e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * Returns true if this URL equals {@code o}. URLs are equal if they have
3197e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * the same protocol, host, port, file, and reference.
320f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
3217e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <h3>Network I/O Warning</h3>
3227e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <p>Some implementations of URL.equals() resolve host names over the
3237e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * network. This is problematic:
3247e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <ul>
3257e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <li><strong>The network may be slow.</strong> Many classes, including
3267e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * core collections like {@link java.util.Map Map} and {@link java.util.Set
3277e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * Set} expect that {@code equals} and {@code hashCode} will return quickly.
3287e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * By violating this assumption, this method posed potential performance
3297e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * problems.
3307e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <li><strong>Equal IP addresses do not imply equal content.</strong>
3317e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * Virtual hosting permits unrelated sites to share an IP address. This
3327e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * method could report two otherwise unrelated URLs to be equal because
3337e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * they're hosted on the same server.</li>
3347e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <li><strong>The network many not be available.</strong> Two URLs could be
3357e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * equal when a network is available and unequal otherwise.</li>
3367e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * <li><strong>The network may change.</strong> The IP address for a given
3377e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * host name varies by network and over time. This is problematic for mobile
3387e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * devices. Two URLs could be equal on some networks and unequal on
3397e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * others.</li>
3407e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * </ul>
34164785533018893463bbab2e34959879bac446c8dJesse Wilson     * <p>This problem is fixed in Android 4.0 (Ice Cream Sandwich). In that
34264785533018893463bbab2e34959879bac446c8dJesse Wilson     * release, URLs are only equal if their host names are equal (ignoring
3437e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson     * case).
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
3457e00db4156e50ce5f20fefb820dca339299134d3Jesse Wilson    @Override public boolean equals(Object o) {
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (o == null) {
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (this == o) {
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (this.getClass() != o.getClass()) {
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
3558f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return streamHandler.equals(this, (URL) o);
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
3598f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns true if this URL refers to the same resource as {@code otherURL}.
3608f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * All URL components except the reference field are compared.
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean sameFile(URL otherURL) {
3638f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return streamHandler.sameFile(this, otherURL);
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3668f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    @Override public int hashCode() {
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (hashCode == 0) {
3688f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            hashCode = streamHandler.hashCode(this);
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return hashCode;
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the receiver's stream handler to one which is appropriate for its
3758f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * protocol.
3768f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *
3778f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * <p>Note that this will overwrite any existing stream handler with the new
3788f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * one. Senders must check if the streamHandler is null before calling the
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method if they do not want this behavior (a speed optimization).
3808f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *
3818f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws MalformedURLException if no reasonable handler is available.
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    void setupStreamHandler() {
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Check for a cached (previously looked up) handler for
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // the requested protocol.
3868f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        streamHandler = streamHandlers.get(protocol);
3878f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (streamHandler != null) {
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If there is a stream handler factory, then attempt to
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // use it to create the handler.
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (streamHandlerFactory != null) {
3948f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            streamHandler = streamHandlerFactory.createURLStreamHandler(protocol);
3958f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            if (streamHandler != null) {
3968f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson                streamHandlers.put(protocol, streamHandler);
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Check if there is a list of packages which can provide handlers.
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If so, then walk this list looking for an applicable one.
403ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        String packageList = System.getProperty("java.protocol.handler.pkgs");
404cf216b0bb538b3e555af205f4fad8064331b9265Jesse Wilson        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
405cf216b0bb538b3e555af205f4fad8064331b9265Jesse Wilson        if (packageList != null && contextClassLoader != null) {
406118abc3050371812703e4fabf03f4399d01fb28cElliott Hughes            for (String packageName : packageList.split("\\|")) {
407118abc3050371812703e4fabf03f4399d01fb28cElliott Hughes                String className = packageName + "." + protocol + ".Handler";
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
409cf216b0bb538b3e555af205f4fad8064331b9265Jesse Wilson                    Class<?> c = contextClassLoader.loadClass(className);
4108f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson                    streamHandler = (URLStreamHandler) c.newInstance();
4118f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson                    if (streamHandler != null) {
4128f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson                        streamHandlers.put(protocol, streamHandler);
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return;
4155aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilson                } catch (IllegalAccessException ignored) {
4165aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilson                } catch (InstantiationException ignored) {
4175aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilson                } catch (ClassNotFoundException ignored) {
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
421c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson
422c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        // Fall back to a built-in stream handler if the user didn't supply one
423c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        if (protocol.equals("file")) {
4248f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            streamHandler = new FileHandler();
425c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        } else if (protocol.equals("ftp")) {
4268f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            streamHandler = new FtpHandler();
427c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        } else if (protocol.equals("http")) {
4282503556d17b28c7b4e6e514540a77df1627857d0jwilson            try {
4292503556d17b28c7b4e6e514540a77df1627857d0jwilson                String name = "com.android.okhttp.HttpHandler";
4302503556d17b28c7b4e6e514540a77df1627857d0jwilson                streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
4312503556d17b28c7b4e6e514540a77df1627857d0jwilson            } catch (Exception e) {
4322503556d17b28c7b4e6e514540a77df1627857d0jwilson                throw new AssertionError(e);
4332503556d17b28c7b4e6e514540a77df1627857d0jwilson            }
434c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        } else if (protocol.equals("https")) {
4352503556d17b28c7b4e6e514540a77df1627857d0jwilson            try {
4362503556d17b28c7b4e6e514540a77df1627857d0jwilson                String name = "com.android.okhttp.HttpsHandler";
4372503556d17b28c7b4e6e514540a77df1627857d0jwilson                streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
4382503556d17b28c7b4e6e514540a77df1627857d0jwilson            } catch (Exception e) {
4392503556d17b28c7b4e6e514540a77df1627857d0jwilson                throw new AssertionError(e);
4402503556d17b28c7b4e6e514540a77df1627857d0jwilson            }
441c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        } else if (protocol.equals("jar")) {
4428f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            streamHandler = new JarHandler();
443c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        }
4448f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (streamHandler != null) {
4458f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            streamHandlers.put(protocol, streamHandler);
446c2ebff3511f9df4d8cca2b82630c2d760af9d204Jesse Wilson        }
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4508f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns the content of the resource which is referred by this URL. By
4515292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * default this returns an {@code InputStream}, or null if the content type
4528f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * of the response is unknown.
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Object getContent() throws IOException {
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return openConnection().getContent();
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4598f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Equivalent to {@code openConnection().getContent(types)}.
4608f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     */
4618f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    @SuppressWarnings("unchecked") // Param not generic in spec
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Object getContent(Class[] types) throws IOException {
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return openConnection().getContent(types);
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4678f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Equivalent to {@code openConnection().getInputStream(types)}.
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
4698f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public final InputStream openStream() throws IOException {
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return openConnection().getInputStream();
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
4748f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns a new connection to the resource referred to by this URL.
475f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
4768f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws IOException if an error occurs while opening the connection.
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URLConnection openConnection() throws IOException {
4798f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return streamHandler.openConnection(this);
4808f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    }
4818f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson
4828f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    /**
4838f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns a new connection to the resource referred to by this URL.
4848f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *
4858f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @param proxy the proxy through which the connection will be established.
4868f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws IOException if an I/O error occurs while opening the connection.
4878f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws IllegalArgumentException if the argument proxy is null or of is
4888f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     an invalid type.
4898f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws UnsupportedOperationException if the protocol handler does not
4908f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     *     support opening connections through proxies.
4918f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     */
4928f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public URLConnection openConnection(Proxy proxy) throws IOException {
4938f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (proxy == null) {
4948f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            throw new IllegalArgumentException("proxy == null");
4958f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        }
4968f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return streamHandler.openConnection(this, proxy);
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
5008f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns the URI equivalent to this URL.
501f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
5028f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @throws URISyntaxException if this URL cannot be converted into a URI.
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URI toURI() throws URISyntaxException {
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new URI(toExternalForm());
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
509d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson     * Encodes this URL to the equivalent URI after escaping characters that are
510d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson     * not permitted by URI.
511d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson     *
512d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson     * @hide
513d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson     */
514d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson    public URI toURILenient() throws URISyntaxException {
5158f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (streamHandler == null) {
516d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson            throw new IllegalStateException(protocol);
517d1b5e5da828434388e486a388710d21e4306dae0Jesse Wilson        }
5188f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return new URI(streamHandler.toExternalForm(this, true));
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a string containing a concise, human-readable representation of
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this URL. The returned string is the same as the result of the method
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code toExternalForm()}.
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5268f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    @Override public String toString() {
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return toExternalForm();
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a string containing a concise, human-readable representation of
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this URL.
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String toExternalForm() {
5358f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        if (streamHandler == null) {
536f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            return "unknown protocol(" + protocol + ")://" + host + file;
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
5388f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return streamHandler.toExternalForm(this);
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5418f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    private void readObject(ObjectInputStream stream) throws IOException {
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            stream.defaultReadObject();
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (host != null && authority == null) {
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                fixURL(true);
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (authority != null) {
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int index;
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if ((index = authority.lastIndexOf('@')) > -1) {
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    userInfo = authority.substring(0, index);
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (file != null && (index = file.indexOf('?')) > -1) {
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    query = file.substring(index + 1);
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    path = file.substring(0, index);
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    path = file;
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setupStreamHandler();
5598f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            if (streamHandler == null) {
560b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes                throw new IOException("Unknown protocol: " + protocol);
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
5628f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            hashCode = 0; // necessary until http://b/4471249 is fixed
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ClassNotFoundException e) {
5648f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            throw new IOException(e);
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void writeObject(ObjectOutputStream s) throws IOException {
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        s.defaultWriteObject();
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5728f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    /** @hide */
5738f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public int getEffectivePort() {
5748f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return URI.getEffectivePort(protocol, port);
5758f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    }
5768f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
5788f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns the protocol of this URL like "http" or "file". This is also
5798f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * known as the scheme. The returned string is lower case.
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5818f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getProtocol() {
5828f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return protocol;
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
5865292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * Returns the authority part of this URL, or null if this URL has no
5875292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * authority.
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5898f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getAuthority() {
5908f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return authority;
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
5945292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * Returns the user info of this URL, or null if this URL has no user info.
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5968f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getUserInfo() {
5978f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return userInfo;
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6008f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    /**
6018f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns the host name or IP address of this URL.
6028f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     */
6038f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getHost() {
6048f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return host;
605c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson    }
606c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6085292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * Returns the port number of this URL or {@code -1} if this URL has no
6098f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * explicit port.
610f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
6118f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * <p>If this URL has no explicit port, connections opened using this URL
6128f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * will use its {@link #getDefaultPort() default port}.
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6148f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public int getPort() {
6158f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return port;
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6198f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns the default port number of the protocol used by this URL. If no
6208f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * default port is defined by the protocol or the {@code URLStreamHandler},
6218f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * {@code -1} will be returned.
622f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
6238f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * @see URLStreamHandler#getDefaultPort
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6258f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public int getDefaultPort() {
6268f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return streamHandler.getDefaultPort();
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6305292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * Returns the file of this URL.
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6328f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getFile() {
6338f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return file;
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6378f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     * Returns the path part of this URL.
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getPath() {
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return path;
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6445292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * Returns the query part of this URL, or null if this URL has no query.
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6468f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getQuery() {
6478f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return query;
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6515292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * Returns the value of the reference part of this URL, or null if this URL
6525292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson     * has no reference part. This is also known as the fragment.
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6548f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    public String getRef() {
6558f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson        return ref;
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the properties of this URL using the provided arguments. Only a
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code URLStreamHandler} can use this method to set fields of the
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * existing URL instance. A URL is generally constant.
6628f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson     */
6638f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson    protected void set(String protocol, String host, int port, String authority, String userInfo,
6648f99aa098c6a06b8be788abbca1c1d1060342709Jesse Wilson            String path, String query, String ref) {
6655292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        String file = path;
66680a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes        if (query != null && !query.isEmpty()) {
6675292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson            file += "?" + query;
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
6695292410e4ebf7fb5149eefd2f52fcb94c46690a6Jesse Wilson        set(protocol, host, port, file, ref);
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.authority = authority;
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.userInfo = userInfo;
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.path = path;
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.query = query;
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
676