| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/common/content_settings_pattern.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/strings/string_split.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "chrome/common/content_settings_pattern_parser.h" | |
| 13 #include "net/base/dns_util.h" | |
| 14 #include "net/base/net_util.h" | |
| 15 #include "url/gurl.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 // The component supports only one scheme for simplicity. | |
| 20 const char* non_port_non_domain_wildcard_scheme = NULL; | |
| 21 | |
| 22 std::string GetDefaultPort(const std::string& scheme) { | |
| 23 if (scheme == url::kHttpScheme) | |
| 24 return "80"; | |
| 25 if (scheme == url::kHttpsScheme) | |
| 26 return "443"; | |
| 27 return std::string(); | |
| 28 } | |
| 29 | |
| 30 // Returns true if |sub_domain| is a sub domain or equls |domain|. E.g. | |
| 31 // "mail.google.com" is a sub domain of "google.com" but "evilhost.com" is not a | |
| 32 // subdomain of "host.com". | |
| 33 bool IsSubDomainOrEqual(const std::string& sub_domain, | |
| 34 const std::string& domain) { | |
| 35 // The empty string serves as wildcard. Each domain is a subdomain of the | |
| 36 // wildcard. | |
| 37 if (domain.empty()) | |
| 38 return true; | |
| 39 const size_t match = sub_domain.rfind(domain); | |
| 40 if (match == std::string::npos || | |
| 41 (match > 0 && sub_domain[match - 1] != '.') || | |
| 42 (match + domain.length() != sub_domain.length())) { | |
| 43 return false; | |
| 44 } | |
| 45 return true; | |
| 46 } | |
| 47 | |
| 48 // Compares two domain names. | |
| 49 int CompareDomainNames(const std::string& str1, const std::string& str2) { | |
| 50 std::vector<std::string> domain_name1; | |
| 51 std::vector<std::string> domain_name2; | |
| 52 | |
| 53 base::SplitString(str1, '.', &domain_name1); | |
| 54 base::SplitString(str2, '.', &domain_name2); | |
| 55 | |
| 56 int i1 = domain_name1.size() - 1; | |
| 57 int i2 = domain_name2.size() - 1; | |
| 58 int rv; | |
| 59 while (i1 >= 0 && i2 >= 0) { | |
| 60 // domain names are stored in puny code. So it's fine to use the compare | |
| 61 // method. | |
| 62 rv = domain_name1[i1].compare(domain_name2[i2]); | |
| 63 if (rv != 0) | |
| 64 return rv; | |
| 65 --i1; | |
| 66 --i2; | |
| 67 } | |
| 68 | |
| 69 if (i1 > i2) | |
| 70 return 1; | |
| 71 | |
| 72 if (i1 < i2) | |
| 73 return -1; | |
| 74 | |
| 75 // The domain names are identical. | |
| 76 return 0; | |
| 77 } | |
| 78 | |
| 79 typedef ContentSettingsPattern::BuilderInterface BuilderInterface; | |
| 80 | |
| 81 } // namespace | |
| 82 | |
| 83 // //////////////////////////////////////////////////////////////////////////// | |
| 84 // ContentSettingsPattern::Builder | |
| 85 // | |
| 86 class ContentSettingsPattern::Builder : | |
| 87 public ContentSettingsPattern::BuilderInterface { | |
| 88 public: | |
| 89 explicit Builder(bool use_legacy_validate); | |
| 90 virtual ~Builder(); | |
| 91 | |
| 92 // BuilderInterface: | |
| 93 virtual BuilderInterface* WithPort(const std::string& port) OVERRIDE; | |
| 94 virtual BuilderInterface* WithPortWildcard() OVERRIDE; | |
| 95 virtual BuilderInterface* WithHost(const std::string& host) OVERRIDE; | |
| 96 virtual BuilderInterface* WithDomainWildcard() OVERRIDE; | |
| 97 virtual BuilderInterface* WithScheme(const std::string& scheme) OVERRIDE; | |
| 98 virtual BuilderInterface* WithSchemeWildcard() OVERRIDE; | |
| 99 virtual BuilderInterface* WithPath(const std::string& path) OVERRIDE; | |
| 100 virtual BuilderInterface* WithPathWildcard() OVERRIDE; | |
| 101 virtual BuilderInterface* Invalid() OVERRIDE; | |
| 102 virtual ContentSettingsPattern Build() OVERRIDE; | |
| 103 | |
| 104 private: | |
| 105 // Canonicalizes the pattern parts so that they are ASCII only, either | |
| 106 // in original (if it was already ASCII) or punycode form. Returns true if | |
| 107 // the canonicalization was successful. | |
| 108 static bool Canonicalize(PatternParts* parts); | |
| 109 | |
| 110 // Returns true when the pattern |parts| represent a valid pattern. | |
| 111 static bool Validate(const PatternParts& parts); | |
| 112 | |
| 113 static bool LegacyValidate(const PatternParts& parts); | |
| 114 | |
| 115 bool is_valid_; | |
| 116 | |
| 117 bool use_legacy_validate_; | |
| 118 | |
| 119 PatternParts parts_; | |
| 120 | |
| 121 DISALLOW_COPY_AND_ASSIGN(Builder); | |
| 122 }; | |
| 123 | |
| 124 ContentSettingsPattern::Builder::Builder(bool use_legacy_validate) | |
| 125 : is_valid_(true), | |
| 126 use_legacy_validate_(use_legacy_validate) {} | |
| 127 | |
| 128 ContentSettingsPattern::Builder::~Builder() {} | |
| 129 | |
| 130 BuilderInterface* ContentSettingsPattern::Builder::WithPort( | |
| 131 const std::string& port) { | |
| 132 parts_.port = port; | |
| 133 parts_.is_port_wildcard = false; | |
| 134 return this; | |
| 135 } | |
| 136 | |
| 137 BuilderInterface* ContentSettingsPattern::Builder::WithPortWildcard() { | |
| 138 parts_.port = ""; | |
| 139 parts_.is_port_wildcard = true; | |
| 140 return this; | |
| 141 } | |
| 142 | |
| 143 BuilderInterface* ContentSettingsPattern::Builder::WithHost( | |
| 144 const std::string& host) { | |
| 145 parts_.host = host; | |
| 146 return this; | |
| 147 } | |
| 148 | |
| 149 BuilderInterface* ContentSettingsPattern::Builder::WithDomainWildcard() { | |
| 150 parts_.has_domain_wildcard = true; | |
| 151 return this; | |
| 152 } | |
| 153 | |
| 154 BuilderInterface* ContentSettingsPattern::Builder::WithScheme( | |
| 155 const std::string& scheme) { | |
| 156 parts_.scheme = scheme; | |
| 157 parts_.is_scheme_wildcard = false; | |
| 158 return this; | |
| 159 } | |
| 160 | |
| 161 BuilderInterface* ContentSettingsPattern::Builder::WithSchemeWildcard() { | |
| 162 parts_.scheme = ""; | |
| 163 parts_.is_scheme_wildcard = true; | |
| 164 return this; | |
| 165 } | |
| 166 | |
| 167 BuilderInterface* ContentSettingsPattern::Builder::WithPath( | |
| 168 const std::string& path) { | |
| 169 parts_.path = path; | |
| 170 parts_.is_path_wildcard = false; | |
| 171 return this; | |
| 172 } | |
| 173 | |
| 174 BuilderInterface* ContentSettingsPattern::Builder::WithPathWildcard() { | |
| 175 parts_.path = ""; | |
| 176 parts_.is_path_wildcard = true; | |
| 177 return this; | |
| 178 } | |
| 179 | |
| 180 BuilderInterface* ContentSettingsPattern::Builder::Invalid() { | |
| 181 is_valid_ = false; | |
| 182 return this; | |
| 183 } | |
| 184 | |
| 185 ContentSettingsPattern ContentSettingsPattern::Builder::Build() { | |
| 186 if (!is_valid_) | |
| 187 return ContentSettingsPattern(); | |
| 188 if (!Canonicalize(&parts_)) | |
| 189 return ContentSettingsPattern(); | |
| 190 if (use_legacy_validate_) { | |
| 191 is_valid_ = LegacyValidate(parts_); | |
| 192 } else { | |
| 193 is_valid_ = Validate(parts_); | |
| 194 } | |
| 195 if (!is_valid_) | |
| 196 return ContentSettingsPattern(); | |
| 197 | |
| 198 // A pattern is invalid if canonicalization is not idempotent. | |
| 199 // This check is here because it should be checked no matter | |
| 200 // use_legacy_validate_ is. | |
| 201 PatternParts parts(parts_); | |
| 202 if (!Canonicalize(&parts)) | |
| 203 return ContentSettingsPattern(); | |
| 204 if (ContentSettingsPattern(parts_, true) != | |
| 205 ContentSettingsPattern(parts, true)) { | |
| 206 return ContentSettingsPattern(); | |
| 207 } | |
| 208 | |
| 209 return ContentSettingsPattern(parts_, is_valid_); | |
| 210 } | |
| 211 | |
| 212 // static | |
| 213 bool ContentSettingsPattern::Builder::Canonicalize(PatternParts* parts) { | |
| 214 // Canonicalize the scheme part. | |
| 215 const std::string scheme(base::StringToLowerASCII(parts->scheme)); | |
| 216 parts->scheme = scheme; | |
| 217 | |
| 218 if (parts->scheme == std::string(url::kFileScheme) && | |
| 219 !parts->is_path_wildcard) { | |
| 220 GURL url(std::string(url::kFileScheme) + | |
| 221 std::string(url::kStandardSchemeSeparator) + parts->path); | |
| 222 parts->path = url.path(); | |
| 223 } | |
| 224 | |
| 225 // Canonicalize the host part. | |
| 226 const std::string host(parts->host); | |
| 227 url::CanonHostInfo host_info; | |
| 228 std::string canonicalized_host(net::CanonicalizeHost(host, &host_info)); | |
| 229 if (host_info.IsIPAddress() && parts->has_domain_wildcard) | |
| 230 return false; | |
| 231 canonicalized_host = net::TrimEndingDot(canonicalized_host); | |
| 232 | |
| 233 parts->host = ""; | |
| 234 if ((host.find('*') == std::string::npos) && | |
| 235 !canonicalized_host.empty()) { | |
| 236 // Valid host. | |
| 237 parts->host += canonicalized_host; | |
| 238 } | |
| 239 return true; | |
| 240 } | |
| 241 | |
| 242 // static | |
| 243 bool ContentSettingsPattern::Builder::Validate(const PatternParts& parts) { | |
| 244 // Sanity checks first: {scheme, port} wildcards imply empty {scheme, port}. | |
| 245 if ((parts.is_scheme_wildcard && !parts.scheme.empty()) || | |
| 246 (parts.is_port_wildcard && !parts.port.empty())) { | |
| 247 NOTREACHED(); | |
| 248 return false; | |
| 249 } | |
| 250 | |
| 251 // file:// URL patterns have an empty host and port. | |
| 252 if (parts.scheme == std::string(url::kFileScheme)) { | |
| 253 if (parts.has_domain_wildcard || !parts.host.empty() || !parts.port.empty()) | |
| 254 return false; | |
| 255 if (parts.is_path_wildcard) | |
| 256 return parts.path.empty(); | |
| 257 return (!parts.path.empty() && | |
| 258 parts.path != "/" && | |
| 259 parts.path.find("*") == std::string::npos); | |
| 260 } | |
| 261 | |
| 262 // If the pattern is for an extension URL test if it is valid. | |
| 263 if (IsNonWildcardDomainNonPortScheme(parts.scheme) && | |
| 264 parts.port.empty() && | |
| 265 !parts.is_port_wildcard) { | |
| 266 return true; | |
| 267 } | |
| 268 | |
| 269 // Non-file patterns are invalid if either the scheme, host or port part is | |
| 270 // empty. | |
| 271 if ((parts.scheme.empty() && !parts.is_scheme_wildcard) || | |
| 272 (parts.host.empty() && !parts.has_domain_wildcard) || | |
| 273 (parts.port.empty() && !parts.is_port_wildcard)) { | |
| 274 return false; | |
| 275 } | |
| 276 | |
| 277 if (parts.host.find("*") != std::string::npos) | |
| 278 return false; | |
| 279 | |
| 280 // Test if the scheme is supported or a wildcard. | |
| 281 if (!parts.is_scheme_wildcard && | |
| 282 parts.scheme != std::string(url::kHttpScheme) && | |
| 283 parts.scheme != std::string(url::kHttpsScheme)) { | |
| 284 return false; | |
| 285 } | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 // static | |
| 290 bool ContentSettingsPattern::Builder::LegacyValidate( | |
| 291 const PatternParts& parts) { | |
| 292 // If the pattern is for a "file-pattern" test if it is valid. | |
| 293 if (parts.scheme == std::string(url::kFileScheme) && | |
| 294 !parts.is_scheme_wildcard && | |
| 295 parts.host.empty() && | |
| 296 parts.port.empty()) | |
| 297 return true; | |
| 298 | |
| 299 // If the pattern is for an extension URL test if it is valid. | |
| 300 if (IsNonWildcardDomainNonPortScheme(parts.scheme) && | |
| 301 !parts.is_scheme_wildcard && | |
| 302 !parts.host.empty() && | |
| 303 !parts.has_domain_wildcard && | |
| 304 parts.port.empty() && | |
| 305 !parts.is_port_wildcard) | |
| 306 return true; | |
| 307 | |
| 308 // Non-file patterns are invalid if either the scheme, host or port part is | |
| 309 // empty. | |
| 310 if ((!parts.is_scheme_wildcard) || | |
| 311 (parts.host.empty() && !parts.has_domain_wildcard) || | |
| 312 (!parts.is_port_wildcard)) | |
| 313 return false; | |
| 314 | |
| 315 // Test if the scheme is supported or a wildcard. | |
| 316 if (!parts.is_scheme_wildcard && | |
| 317 parts.scheme != std::string(url::kHttpScheme) && | |
| 318 parts.scheme != std::string(url::kHttpsScheme)) { | |
| 319 return false; | |
| 320 } | |
| 321 return true; | |
| 322 } | |
| 323 | |
| 324 // //////////////////////////////////////////////////////////////////////////// | |
| 325 // ContentSettingsPattern::PatternParts | |
| 326 // | |
| 327 ContentSettingsPattern::PatternParts::PatternParts() | |
| 328 : is_scheme_wildcard(false), | |
| 329 has_domain_wildcard(false), | |
| 330 is_port_wildcard(false), | |
| 331 is_path_wildcard(false) {} | |
| 332 | |
| 333 ContentSettingsPattern::PatternParts::~PatternParts() {} | |
| 334 | |
| 335 // //////////////////////////////////////////////////////////////////////////// | |
| 336 // ContentSettingsPattern | |
| 337 // | |
| 338 | |
| 339 // The version of the pattern format implemented. Version 1 includes the | |
| 340 // following patterns: | |
| 341 // - [*.]domain.tld (matches domain.tld and all sub-domains) | |
| 342 // - host (matches an exact hostname) | |
| 343 // - a.b.c.d (matches an exact IPv4 ip) | |
| 344 // - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip) | |
| 345 // - file:///tmp/test.html (a complete URL without a host) | |
| 346 // Version 2 adds a resource identifier for plugins. | |
| 347 // TODO(jochen): update once this feature is no longer behind a flag. | |
| 348 const int ContentSettingsPattern::kContentSettingsPatternVersion = 1; | |
| 349 | |
| 350 // static | |
| 351 BuilderInterface* ContentSettingsPattern::CreateBuilder( | |
| 352 bool validate) { | |
| 353 return new Builder(validate); | |
| 354 } | |
| 355 | |
| 356 // static | |
| 357 ContentSettingsPattern ContentSettingsPattern::Wildcard() { | |
| 358 scoped_ptr<ContentSettingsPattern::BuilderInterface> builder( | |
| 359 ContentSettingsPattern::CreateBuilder(true)); | |
| 360 builder->WithSchemeWildcard()->WithDomainWildcard()->WithPortWildcard()-> | |
| 361 WithPathWildcard(); | |
| 362 return builder->Build(); | |
| 363 } | |
| 364 | |
| 365 // static | |
| 366 ContentSettingsPattern ContentSettingsPattern::FromURL( | |
| 367 const GURL& url) { | |
| 368 scoped_ptr<ContentSettingsPattern::BuilderInterface> builder( | |
| 369 ContentSettingsPattern::CreateBuilder(false)); | |
| 370 | |
| 371 const GURL* local_url = &url; | |
| 372 if (url.SchemeIsFileSystem() && url.inner_url()) { | |
| 373 local_url = url.inner_url(); | |
| 374 } | |
| 375 if (local_url->SchemeIsFile()) { | |
| 376 builder->WithScheme(local_url->scheme())->WithPath(local_url->path()); | |
| 377 } else { | |
| 378 // Please keep the order of the ifs below as URLs with an IP as host can | |
| 379 // also have a "http" scheme. | |
| 380 if (local_url->HostIsIPAddress()) { | |
| 381 builder->WithScheme(local_url->scheme())->WithHost(local_url->host()); | |
| 382 } else if (local_url->SchemeIs(url::kHttpScheme)) { | |
| 383 builder->WithSchemeWildcard()->WithDomainWildcard()->WithHost( | |
| 384 local_url->host()); | |
| 385 } else if (local_url->SchemeIs(url::kHttpsScheme)) { | |
| 386 builder->WithScheme(local_url->scheme())->WithDomainWildcard()->WithHost( | |
| 387 local_url->host()); | |
| 388 } else { | |
| 389 // Unsupported scheme | |
| 390 } | |
| 391 if (local_url->port().empty()) { | |
| 392 if (local_url->SchemeIs(url::kHttpsScheme)) | |
| 393 builder->WithPort(GetDefaultPort(url::kHttpsScheme)); | |
| 394 else | |
| 395 builder->WithPortWildcard(); | |
| 396 } else { | |
| 397 builder->WithPort(local_url->port()); | |
| 398 } | |
| 399 } | |
| 400 return builder->Build(); | |
| 401 } | |
| 402 | |
| 403 // static | |
| 404 ContentSettingsPattern ContentSettingsPattern::FromURLNoWildcard( | |
| 405 const GURL& url) { | |
| 406 scoped_ptr<ContentSettingsPattern::BuilderInterface> builder( | |
| 407 ContentSettingsPattern::CreateBuilder(false)); | |
| 408 | |
| 409 const GURL* local_url = &url; | |
| 410 if (url.SchemeIsFileSystem() && url.inner_url()) { | |
| 411 local_url = url.inner_url(); | |
| 412 } | |
| 413 if (local_url->SchemeIsFile()) { | |
| 414 builder->WithScheme(local_url->scheme())->WithPath(local_url->path()); | |
| 415 } else { | |
| 416 builder->WithScheme(local_url->scheme())->WithHost(local_url->host()); | |
| 417 if (local_url->port().empty()) { | |
| 418 builder->WithPort(GetDefaultPort(local_url->scheme())); | |
| 419 } else { | |
| 420 builder->WithPort(local_url->port()); | |
| 421 } | |
| 422 } | |
| 423 return builder->Build(); | |
| 424 } | |
| 425 | |
| 426 // static | |
| 427 ContentSettingsPattern ContentSettingsPattern::FromString( | |
| 428 const std::string& pattern_spec) { | |
| 429 scoped_ptr<ContentSettingsPattern::BuilderInterface> builder( | |
| 430 ContentSettingsPattern::CreateBuilder(false)); | |
| 431 content_settings::PatternParser::Parse(pattern_spec, | |
| 432 builder.get()); | |
| 433 return builder->Build(); | |
| 434 } | |
| 435 | |
| 436 // static | |
| 437 void ContentSettingsPattern::SetNonWildcardDomainNonPortScheme( | |
| 438 const char* scheme) { | |
| 439 DCHECK(scheme); | |
| 440 DCHECK(!non_port_non_domain_wildcard_scheme || | |
| 441 non_port_non_domain_wildcard_scheme == scheme); | |
| 442 non_port_non_domain_wildcard_scheme = scheme; | |
| 443 } | |
| 444 | |
| 445 // static | |
| 446 bool ContentSettingsPattern::IsNonWildcardDomainNonPortScheme( | |
| 447 const std::string& scheme) { | |
| 448 DCHECK(non_port_non_domain_wildcard_scheme); | |
| 449 return scheme == non_port_non_domain_wildcard_scheme; | |
| 450 } | |
| 451 | |
| 452 ContentSettingsPattern::ContentSettingsPattern() | |
| 453 : is_valid_(false) { | |
| 454 } | |
| 455 | |
| 456 ContentSettingsPattern::ContentSettingsPattern( | |
| 457 const PatternParts& parts, | |
| 458 bool valid) | |
| 459 : parts_(parts), | |
| 460 is_valid_(valid) { | |
| 461 } | |
| 462 | |
| 463 bool ContentSettingsPattern::Matches( | |
| 464 const GURL& url) const { | |
| 465 // An invalid pattern matches nothing. | |
| 466 if (!is_valid_) | |
| 467 return false; | |
| 468 | |
| 469 const GURL* local_url = &url; | |
| 470 if (url.SchemeIsFileSystem() && url.inner_url()) { | |
| 471 local_url = url.inner_url(); | |
| 472 } | |
| 473 | |
| 474 // Match the scheme part. | |
| 475 const std::string scheme(local_url->scheme()); | |
| 476 if (!parts_.is_scheme_wildcard && | |
| 477 parts_.scheme != scheme) { | |
| 478 return false; | |
| 479 } | |
| 480 | |
| 481 // File URLs have no host. Matches if the pattern has the path wildcard set, | |
| 482 // or if the path in the URL is identical to the one in the pattern. | |
| 483 // For filesystem:file URLs, the path used is the filesystem type, so all | |
| 484 // filesystem:file:///temporary/... are equivalent. | |
| 485 // TODO(markusheintz): Content settings should be defined for all files on | |
| 486 // a machine. Unless there is a good use case for supporting paths for file | |
| 487 // patterns, stop supporting path for file patterns. | |
| 488 if (!parts_.is_scheme_wildcard && scheme == url::kFileScheme) | |
| 489 return parts_.is_path_wildcard || | |
| 490 parts_.path == std::string(local_url->path()); | |
| 491 | |
| 492 // Match the host part. | |
| 493 const std::string host(net::TrimEndingDot(local_url->host())); | |
| 494 if (!parts_.has_domain_wildcard) { | |
| 495 if (parts_.host != host) | |
| 496 return false; | |
| 497 } else { | |
| 498 if (!IsSubDomainOrEqual(host, parts_.host)) | |
| 499 return false; | |
| 500 } | |
| 501 | |
| 502 // Ignore the port if the scheme doesn't support it. | |
| 503 if (IsNonWildcardDomainNonPortScheme(parts_.scheme)) | |
| 504 return true; | |
| 505 | |
| 506 // Match the port part. | |
| 507 std::string port(local_url->port()); | |
| 508 | |
| 509 // Use the default port if the port string is empty. GURL returns an empty | |
| 510 // string if no port at all was specified or if the default port was | |
| 511 // specified. | |
| 512 if (port.empty()) { | |
| 513 port = GetDefaultPort(scheme); | |
| 514 } | |
| 515 | |
| 516 if (!parts_.is_port_wildcard && | |
| 517 parts_.port != port ) { | |
| 518 return false; | |
| 519 } | |
| 520 | |
| 521 return true; | |
| 522 } | |
| 523 | |
| 524 bool ContentSettingsPattern::MatchesAllHosts() const { | |
| 525 return parts_.has_domain_wildcard && parts_.host.empty(); | |
| 526 } | |
| 527 | |
| 528 std::string ContentSettingsPattern::ToString() const { | |
| 529 if (IsValid()) | |
| 530 return content_settings::PatternParser::ToString(parts_); | |
| 531 else | |
| 532 return std::string(); | |
| 533 } | |
| 534 | |
| 535 ContentSettingsPattern::Relation ContentSettingsPattern::Compare( | |
| 536 const ContentSettingsPattern& other) const { | |
| 537 // Two invalid patterns are identical in the way they behave. They don't match | |
| 538 // anything and are represented as an empty string. So it's fair to treat them | |
| 539 // as identical. | |
| 540 if ((this == &other) || | |
| 541 (!is_valid_ && !other.is_valid_)) | |
| 542 return IDENTITY; | |
| 543 | |
| 544 if (!is_valid_ && other.is_valid_) | |
| 545 return DISJOINT_ORDER_POST; | |
| 546 if (is_valid_ && !other.is_valid_) | |
| 547 return DISJOINT_ORDER_PRE; | |
| 548 | |
| 549 // If either host, port or scheme are disjoint return immediately. | |
| 550 Relation host_relation = CompareHost(parts_, other.parts_); | |
| 551 if (host_relation == DISJOINT_ORDER_PRE || | |
| 552 host_relation == DISJOINT_ORDER_POST) | |
| 553 return host_relation; | |
| 554 | |
| 555 Relation port_relation = ComparePort(parts_, other.parts_); | |
| 556 if (port_relation == DISJOINT_ORDER_PRE || | |
| 557 port_relation == DISJOINT_ORDER_POST) | |
| 558 return port_relation; | |
| 559 | |
| 560 Relation scheme_relation = CompareScheme(parts_, other.parts_); | |
| 561 if (scheme_relation == DISJOINT_ORDER_PRE || | |
| 562 scheme_relation == DISJOINT_ORDER_POST) | |
| 563 return scheme_relation; | |
| 564 | |
| 565 if (host_relation != IDENTITY) | |
| 566 return host_relation; | |
| 567 if (port_relation != IDENTITY) | |
| 568 return port_relation; | |
| 569 return scheme_relation; | |
| 570 } | |
| 571 | |
| 572 bool ContentSettingsPattern::operator==( | |
| 573 const ContentSettingsPattern& other) const { | |
| 574 return Compare(other) == IDENTITY; | |
| 575 } | |
| 576 | |
| 577 bool ContentSettingsPattern::operator!=( | |
| 578 const ContentSettingsPattern& other) const { | |
| 579 return !(*this == other); | |
| 580 } | |
| 581 | |
| 582 bool ContentSettingsPattern::operator<( | |
| 583 const ContentSettingsPattern& other) const { | |
| 584 return Compare(other) < 0; | |
| 585 } | |
| 586 | |
| 587 bool ContentSettingsPattern::operator>( | |
| 588 const ContentSettingsPattern& other) const { | |
| 589 return Compare(other) > 0; | |
| 590 } | |
| 591 | |
| 592 // static | |
| 593 ContentSettingsPattern::Relation ContentSettingsPattern::CompareScheme( | |
| 594 const ContentSettingsPattern::PatternParts& parts, | |
| 595 const ContentSettingsPattern::PatternParts& other_parts) { | |
| 596 if (parts.is_scheme_wildcard && !other_parts.is_scheme_wildcard) | |
| 597 return ContentSettingsPattern::SUCCESSOR; | |
| 598 if (!parts.is_scheme_wildcard && other_parts.is_scheme_wildcard) | |
| 599 return ContentSettingsPattern::PREDECESSOR; | |
| 600 | |
| 601 int result = parts.scheme.compare(other_parts.scheme); | |
| 602 if (result == 0) | |
| 603 return ContentSettingsPattern::IDENTITY; | |
| 604 if (result > 0) | |
| 605 return ContentSettingsPattern::DISJOINT_ORDER_PRE; | |
| 606 return ContentSettingsPattern::DISJOINT_ORDER_POST; | |
| 607 } | |
| 608 | |
| 609 // static | |
| 610 ContentSettingsPattern::Relation ContentSettingsPattern::CompareHost( | |
| 611 const ContentSettingsPattern::PatternParts& parts, | |
| 612 const ContentSettingsPattern::PatternParts& other_parts) { | |
| 613 if (!parts.has_domain_wildcard && !other_parts.has_domain_wildcard) { | |
| 614 // Case 1: No host starts with a wild card | |
| 615 int result = CompareDomainNames(parts.host, other_parts.host); | |
| 616 if (result == 0) | |
| 617 return ContentSettingsPattern::IDENTITY; | |
| 618 if (result < 0) | |
| 619 return ContentSettingsPattern::DISJOINT_ORDER_PRE; | |
| 620 return ContentSettingsPattern::DISJOINT_ORDER_POST; | |
| 621 } else if (parts.has_domain_wildcard && !other_parts.has_domain_wildcard) { | |
| 622 // Case 2: |host| starts with a domain wildcard and |other_host| does not | |
| 623 // start with a domain wildcard. | |
| 624 // Examples: | |
| 625 // "this" host: [*.]google.com | |
| 626 // "other" host: google.com | |
| 627 // | |
| 628 // [*.]google.com | |
| 629 // mail.google.com | |
| 630 // | |
| 631 // [*.]mail.google.com | |
| 632 // google.com | |
| 633 // | |
| 634 // [*.]youtube.com | |
| 635 // google.de | |
| 636 // | |
| 637 // [*.]youtube.com | |
| 638 // mail.google.com | |
| 639 // | |
| 640 // * | |
| 641 // google.de | |
| 642 if (IsSubDomainOrEqual(other_parts.host, parts.host)) { | |
| 643 return ContentSettingsPattern::SUCCESSOR; | |
| 644 } else { | |
| 645 if (CompareDomainNames(parts.host, other_parts.host) < 0) | |
| 646 return ContentSettingsPattern::DISJOINT_ORDER_PRE; | |
| 647 return ContentSettingsPattern::DISJOINT_ORDER_POST; | |
| 648 } | |
| 649 } else if (!parts.has_domain_wildcard && other_parts.has_domain_wildcard) { | |
| 650 // Case 3: |host| starts NOT with a domain wildcard and |other_host| starts | |
| 651 // with a domain wildcard. | |
| 652 if (IsSubDomainOrEqual(parts.host, other_parts.host)) { | |
| 653 return ContentSettingsPattern::PREDECESSOR; | |
| 654 } else { | |
| 655 if (CompareDomainNames(parts.host, other_parts.host) < 0) | |
| 656 return ContentSettingsPattern::DISJOINT_ORDER_PRE; | |
| 657 return ContentSettingsPattern::DISJOINT_ORDER_POST; | |
| 658 } | |
| 659 } else if (parts.has_domain_wildcard && other_parts.has_domain_wildcard) { | |
| 660 // Case 4: |host| and |other_host| both start with a domain wildcard. | |
| 661 // Examples: | |
| 662 // [*.]google.com | |
| 663 // [*.]google.com | |
| 664 // | |
| 665 // [*.]google.com | |
| 666 // [*.]mail.google.com | |
| 667 // | |
| 668 // [*.]youtube.com | |
| 669 // [*.]google.de | |
| 670 // | |
| 671 // [*.]youtube.com | |
| 672 // [*.]mail.google.com | |
| 673 // | |
| 674 // [*.]youtube.com | |
| 675 // * | |
| 676 // | |
| 677 // * | |
| 678 // [*.]youtube.com | |
| 679 if (parts.host == other_parts.host) { | |
| 680 return ContentSettingsPattern::IDENTITY; | |
| 681 } else if (IsSubDomainOrEqual(other_parts.host, parts.host)) { | |
| 682 return ContentSettingsPattern::SUCCESSOR; | |
| 683 } else if (IsSubDomainOrEqual(parts.host, other_parts.host)) { | |
| 684 return ContentSettingsPattern::PREDECESSOR; | |
| 685 } else { | |
| 686 if (CompareDomainNames(parts.host, other_parts.host) < 0) | |
| 687 return ContentSettingsPattern::DISJOINT_ORDER_PRE; | |
| 688 return ContentSettingsPattern::DISJOINT_ORDER_POST; | |
| 689 } | |
| 690 } | |
| 691 | |
| 692 NOTREACHED(); | |
| 693 return ContentSettingsPattern::IDENTITY; | |
| 694 } | |
| 695 | |
| 696 // static | |
| 697 ContentSettingsPattern::Relation ContentSettingsPattern::ComparePort( | |
| 698 const ContentSettingsPattern::PatternParts& parts, | |
| 699 const ContentSettingsPattern::PatternParts& other_parts) { | |
| 700 if (parts.is_port_wildcard && !other_parts.is_port_wildcard) | |
| 701 return ContentSettingsPattern::SUCCESSOR; | |
| 702 if (!parts.is_port_wildcard && other_parts.is_port_wildcard) | |
| 703 return ContentSettingsPattern::PREDECESSOR; | |
| 704 | |
| 705 int result = parts.port.compare(other_parts.port); | |
| 706 if (result == 0) | |
| 707 return ContentSettingsPattern::IDENTITY; | |
| 708 if (result > 0) | |
| 709 return ContentSettingsPattern::DISJOINT_ORDER_PRE; | |
| 710 return ContentSettingsPattern::DISJOINT_ORDER_POST; | |
| 711 } | |
| OLD | NEW |