Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser; | 5 package org.chromium.chrome.browser; |
| 6 | 6 |
| 7 import android.text.TextUtils; | 7 import android.text.TextUtils; |
| 8 | 8 |
| 9 import org.chromium.base.CollectionUtil; | 9 import org.chromium.base.CollectionUtil; |
| 10 | 10 |
| 11 import java.net.URI; | 11 import java.net.URI; |
| 12 import java.net.URISyntaxException; | 12 import java.net.URISyntaxException; |
| 13 import java.util.HashSet; | 13 import java.util.HashSet; |
| 14 import java.util.regex.Matcher; | |
| 15 import java.util.regex.Pattern; | |
| 14 | 16 |
| 15 /** | 17 /** |
| 16 * Utilities for working with URIs (and URLs). These methods may be used in secu rity-sensitive | 18 * Utilities for working with URIs (and URLs). These methods may be used in secu rity-sensitive |
| 17 * contexts (after all, origins are the security boundary on the web), and so th e correctness bar | 19 * contexts (after all, origins are the security boundary on the web), and so th e correctness bar |
| 18 * must be high. | 20 * must be high. |
| 19 */ | 21 */ |
| 20 public class UrlUtilities { | 22 public class UrlUtilities { |
| 21 /** | 23 /** |
| 22 * URI schemes that ContentView can handle. | 24 * URI schemes that ContentView can handle. |
| 23 */ | 25 */ |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 * no subdomains, from the given URI. Returns an empty string if the URI is invalid, has no host | 202 * no subdomains, from the given URI. Returns an empty string if the URI is invalid, has no host |
| 201 * (e.g. a file: URI), has multiple trailing dots, is an IP address, has onl y one subcomponent | 203 * (e.g. a file: URI), has multiple trailing dots, is an IP address, has onl y one subcomponent |
| 202 * (i.e. no dots other than leading/trailing ones), or is itself a recognize d registry | 204 * (i.e. no dots other than leading/trailing ones), or is itself a recognize d registry |
| 203 * identifier. | 205 * identifier. |
| 204 */ | 206 */ |
| 205 public static String getDomainAndRegistry(String uri, boolean includePrivate Registries) { | 207 public static String getDomainAndRegistry(String uri, boolean includePrivate Registries) { |
| 206 if (TextUtils.isEmpty(uri)) return uri; | 208 if (TextUtils.isEmpty(uri)) return uri; |
| 207 return nativeGetDomainAndRegistry(uri, includePrivateRegistries); | 209 return nativeGetDomainAndRegistry(uri, includePrivateRegistries); |
| 208 } | 210 } |
| 209 | 211 |
| 212 // Patterns used in validateIntentUrl. | |
| 213 private static final Pattern DNS_HOSTNAME_PATTERN = | |
| 214 Pattern.compile("^[\\w\\.-]*$"); | |
| 215 private static final Pattern JAVA_PACKAGE_NAME_PATTERN = | |
| 216 Pattern.compile("^[\\w\\.-]*$"); | |
| 217 private static final Pattern URL_SCHEME_PATTERN = | |
| 218 Pattern.compile("^[a-zA-Z]+$"); | |
| 219 | |
| 220 /** | |
| 221 * @param url An Android intent:// URL to validate. | |
| 222 * | |
| 223 * @throws URISyntaxException if url is not a valid Android intent:// | |
| 224 * URL, as specified at | |
| 225 * https://developer.chrome.com/multidevice/android/intents#syntax. | |
| 226 */ | |
| 227 public static boolean validateIntentUrl(String url) { | |
| 228 URI parsed = null; | |
| 229 try { | |
| 230 parsed = new URI(url); | |
| 231 } catch (URISyntaxException e) { | |
| 232 return false; | |
| 233 } | |
| 234 | |
| 235 if (!parsed.getScheme().equals("intent")) return false; | |
| 236 | |
| 237 Matcher m = DNS_HOSTNAME_PATTERN.matcher(parsed.getHost()); | |
| 238 if (!m.matches()) return false; | |
| 239 | |
| 240 if (!parsed.getPath().isEmpty() && !parsed.getPath().equals("/")) { | |
| 241 return false; | |
| 242 } | |
| 243 | |
| 244 String[] parts = parsed.getFragment().split(";"); | |
| 245 if (parts.length < 3 | |
| 246 || !parts[0].equals("Intent") | |
| 247 || !parts[parts.length - 1].equals("end")) { | |
| 248 return false; | |
| 249 } | |
| 250 | |
| 251 boolean seenPackage = false; | |
| 252 boolean seenAction = false; | |
| 253 boolean seenCategory = false; | |
| 254 boolean seenComponent = false; | |
| 255 boolean seenScheme = false; | |
| 256 | |
| 257 for (int i = 1; i < parts.length - 1; ++i) { | |
| 258 // This is OK *only* because no valid package, action, category, | |
| 259 // component, or scheme contains "=". | |
| 260 String[] pair = parts[i].split("="); | |
| 261 if (2 != pair.length) return false; | |
|
Yaron
2015/04/24 20:38:17
I think this breaks "extras". see below
| |
| 262 | |
| 263 m = JAVA_PACKAGE_NAME_PATTERN.matcher(pair[1]); | |
| 264 if (pair[0].equals("package")) { | |
| 265 if (seenPackage || !m.matches()) return false; | |
| 266 seenPackage = true; | |
| 267 } else if (pair[0].equals("action")) { | |
| 268 if (seenAction || !m.matches()) return false; | |
| 269 seenAction = true; | |
| 270 } else if (pair[0].equals("category")) { | |
| 271 if (seenCategory || !m.matches()) return false; | |
| 272 seenCategory = true; | |
| 273 } else if (pair[0].equals("component")) { | |
| 274 if (seenComponent || !m.matches()) return false; | |
| 275 seenComponent = true; | |
| 276 } else if (pair[0].equals("scheme")) { | |
| 277 if (seenScheme) return false; | |
| 278 Matcher schemeMatcher = URL_SCHEME_PATTERN.matcher(pair[1]); | |
| 279 if (!schemeMatcher.matches()) return false; | |
| 280 seenScheme = true; | |
| 281 } else { | |
| 282 // Assume we are seeing an Intent Extra. Require that the | |
| 283 // key be a valid Java package name, and that the value also | |
| 284 // fit that rather restrictive pattern. The latter | |
| 285 // requirement may have to be relaxed in the future, but | |
| 286 // beware: Here Lurks Madness. | |
|
Yaron
2015/04/24 20:38:17
I guess this is a deliberate "fail closed" but I w
| |
| 287 Matcher keyMatcher = JAVA_PACKAGE_NAME_PATTERN.matcher(pair[0]); | |
| 288 if (!m.matches() || !keyMatcher.matches()) return false; | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 return true; | |
| 293 } | |
| 294 | |
| 210 private static native boolean nativeSameDomainOrHost(String primaryUrl, Stri ng secondaryUrl, | 295 private static native boolean nativeSameDomainOrHost(String primaryUrl, Stri ng secondaryUrl, |
| 211 boolean includePrivateRegistries); | 296 boolean includePrivateRegistries); |
| 212 private static native String nativeGetDomainAndRegistry(String url, | 297 private static native String nativeGetDomainAndRegistry(String url, |
| 213 boolean includePrivateRegistries); | 298 boolean includePrivateRegistries); |
| 214 public static native boolean nativeIsGoogleSearchUrl(String url); | 299 public static native boolean nativeIsGoogleSearchUrl(String url); |
| 215 public static native boolean nativeIsGoogleHomePageUrl(String url); | 300 public static native boolean nativeIsGoogleHomePageUrl(String url); |
| 216 private static native String nativeFixupUrl(String url, String desiredTld); | 301 private static native String nativeFixupUrl(String url, String desiredTld); |
| 217 } | 302 } |
| OLD | NEW |