// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser; import android.text.TextUtils; import org.chromium.base.CollectionUtil; import java.net.URI; import java.net.URISyntaxException; import java.util.HashSet; /** * Utilities for working with URIs (and URLs). These methods may be used in security-sensitive * contexts (after all, origins are the security boundary on the web), and so the correctness bar * must be high. */ public class UrlUtilities { /** * URI schemes that ContentView can handle. */ private static final HashSet ACCEPTED_SCHEMES = CollectionUtil.newHashSet( "about", "data", "file", "http", "https", "inline", "javascript"); /** * URI schemes that Chrome can download. */ private static final HashSet DOWNLOADABLE_SCHEMES = CollectionUtil.newHashSet( "data", "filesystem", "http", "https"); /** * @param uri A URI. * * @return True if the URI's scheme is one that ContentView can handle. */ public static boolean isAcceptedScheme(URI uri) { return ACCEPTED_SCHEMES.contains(uri.getScheme()); } /** * @param uri A URI. * * @return True if the URI's scheme is one that ContentView can handle. */ public static boolean isAcceptedScheme(String uri) { try { return isAcceptedScheme(new URI(uri)); } catch (URISyntaxException e) { return false; } } /** * @param uri A URI. * * @return True if the URI's scheme is one that Chrome can download. */ public static boolean isDownloadableScheme(URI uri) { return DOWNLOADABLE_SCHEMES.contains(uri.getScheme()); } /** * @param uri A URI. * * @return True if the URI's scheme is one that Chrome can download. */ public static boolean isDownloadableScheme(String uri) { try { return isDownloadableScheme(new URI(uri)); } catch (URISyntaxException e) { return false; } } /** * @param uri A URI to repair. * * @return A String representation of a URI that will be valid for loading in a ContentView. */ public static String fixUrl(String uri) { if (uri == null) return null; try { String fixedUri = uri.trim(); if (fixedUri.indexOf("://") == 0) { return "http" + fixedUri; } if (fixedUri.indexOf(":") == -1) { return "http://" + fixedUri; } URI parsed = new URI(fixedUri); if (parsed.getScheme() == null) { parsed = new URI( "http", null, // userInfo parsed.getHost(), parsed.getPort(), parsed.getRawPath(), parsed.getRawQuery(), parsed.getRawFragment()); } return parsed.toString(); } catch (URISyntaxException e) { // Can't do anything. return uri; } } /** * Refer to UrlFixerUpper::FixupURL. * * Compare to {@link #fixUrl(String)}, This fixes URL more aggressively including Chrome * specific cases. For example, "about:" becomes "chrome://version/". However, this is not a * superset of {@link #fixUrl(String)} either. For example, this function doesn't do anything * with "://mail.google.com:/", while the other one prepends "http". Also, for * "//mail.google.com:/", this function prepends "file" while the other one prepends "http". */ public static String fixupUrl(String uri) { return nativeFixupUrl(uri, null); } /** * Builds a String that strips down the URL to the its scheme, host, and port. * @param uri URI to break down. * @param showScheme Whether or not to show the scheme. If the URL can't be parsed, this value * is ignored. * @return Stripped-down String containing the essential bits of the URL, or the original URL if * it fails to parse it. */ public static String getOriginForDisplay(URI uri, boolean showScheme) { String scheme = uri.getScheme(); String host = uri.getHost(); int port = uri.getPort(); String displayUrl; if (TextUtils.isEmpty(scheme) || TextUtils.isEmpty(host)) { displayUrl = uri.toString(); } else { if (showScheme) { scheme += "://"; } else { scheme = ""; } if (port == -1 || (port == 80 && "http".equals(scheme)) || (port == 443 && "https".equals(scheme))) { displayUrl = scheme + host; } else { displayUrl = scheme + host + ":" + port; } } return displayUrl; } /** * Determines whether or not the given URLs belong to the same broad domain or host. * "Broad domain" is defined as the TLD + 1 or the host. * * For example, the TLD + 1 for http://news.google.com would be "google.com" and would be shared * with other Google properties like http://finance.google.com. * * If {@code includePrivateRegistries} is marked as true, then private domain registries (like * appspot.com) are considered "effective TLDs" -- all subdomains of appspot.com would be * considered distinct (effective TLD = ".appspot.com" + 1). * This means that http://chromiumreview.appspot.com and http://example.appspot.com would not * belong to the same host. * If {@code includePrivateRegistries} is false, all subdomains of appspot.com * would be considered to be the same domain (TLD = ".com" + 1). * * @param primaryUrl First URL * @param secondaryUrl Second URL * @param includePrivateRegistries Whether or not to consider private registries. * @return True iff the two URIs belong to the same domain or host. */ public static boolean sameDomainOrHost(String primaryUrl, String secondaryUrl, boolean includePrivateRegistries) { return nativeSameDomainOrHost(primaryUrl, secondaryUrl, includePrivateRegistries); } /** * This function works by calling net::registry_controlled_domains::GetDomainAndRegistry * * @param uri A URI * @param includePrivateRegistries Whether or not to consider private registries. * * @return The registered, organization-identifying host and all its registry information, but * no subdomains, from the given URI. Returns an empty string if the URI is invalid, has no host * (e.g. a file: URI), has multiple trailing dots, is an IP address, has only one subcomponent * (i.e. no dots other than leading/trailing ones), or is itself a recognized registry * identifier. */ public static String getDomainAndRegistry(String uri, boolean includePrivateRegistries) { return nativeGetDomainAndRegistry(uri, includePrivateRegistries); } /** * @param url A URL. * @return Whether a given URL is one of [...]google.TLD or [...]youtube.TLD URLs. */ public static boolean isGooglePropertyUrl(String url) { if (TextUtils.isEmpty(url)) return false; return nativeIsGooglePropertyUrl(url); } private static native boolean nativeSameDomainOrHost(String primaryUrl, String secondaryUrl, boolean includePrivateRegistries); private static native String nativeGetDomainAndRegistry(String url, boolean includePrivateRegistries); public static native boolean nativeIsGoogleSearchUrl(String url); public static native boolean nativeIsGoogleHomePageUrl(String url); public static native String nativeFixupUrl(String url, String desiredTld); private static native boolean nativeIsGooglePropertyUrl(String url); }