• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "components/content_settings/core/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 "components/content_settings/core/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 
GetDefaultPort(const std::string & scheme)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".
IsSubDomainOrEqual(const std::string & sub_domain,const std::string & domain)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.
CompareDomainNames(const std::string & str1,const std::string & str2)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 = static_cast<int>(domain_name1.size()) - 1;
57   int i2 = static_cast<int>(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 
Builder(bool use_legacy_validate)124 ContentSettingsPattern::Builder::Builder(bool use_legacy_validate)
125     : is_valid_(true),
126       use_legacy_validate_(use_legacy_validate) {}
127 
~Builder()128 ContentSettingsPattern::Builder::~Builder() {}
129 
WithPort(const std::string & port)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 
WithPortWildcard()137 BuilderInterface* ContentSettingsPattern::Builder::WithPortWildcard() {
138   parts_.port = "";
139   parts_.is_port_wildcard = true;
140   return this;
141 }
142 
WithHost(const std::string & host)143 BuilderInterface* ContentSettingsPattern::Builder::WithHost(
144     const std::string& host) {
145   parts_.host = host;
146   return this;
147 }
148 
WithDomainWildcard()149 BuilderInterface* ContentSettingsPattern::Builder::WithDomainWildcard() {
150   parts_.has_domain_wildcard = true;
151   return this;
152 }
153 
WithScheme(const std::string & scheme)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 
WithSchemeWildcard()161 BuilderInterface* ContentSettingsPattern::Builder::WithSchemeWildcard() {
162   parts_.scheme = "";
163   parts_.is_scheme_wildcard = true;
164   return this;
165 }
166 
WithPath(const std::string & path)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 
WithPathWildcard()174 BuilderInterface* ContentSettingsPattern::Builder::WithPathWildcard() {
175   parts_.path = "";
176   parts_.is_path_wildcard = true;
177   return this;
178 }
179 
Invalid()180 BuilderInterface* ContentSettingsPattern::Builder::Invalid() {
181   is_valid_ = false;
182   return this;
183 }
184 
Build()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
Canonicalize(PatternParts * parts)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
Validate(const PatternParts & parts)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
LegacyValidate(const PatternParts & parts)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 //
PatternParts()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 
~PatternParts()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
CreateBuilder(bool validate)351 BuilderInterface* ContentSettingsPattern::CreateBuilder(
352     bool validate) {
353   return new Builder(validate);
354 }
355 
356 // static
Wildcard()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
FromURL(const GURL & url)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
FromURLNoWildcard(const GURL & url)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
FromString(const std::string & pattern_spec)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
SetNonWildcardDomainNonPortScheme(const char * scheme)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
IsNonWildcardDomainNonPortScheme(const std::string & scheme)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 
ContentSettingsPattern()452 ContentSettingsPattern::ContentSettingsPattern()
453   : is_valid_(false) {
454 }
455 
ContentSettingsPattern(const PatternParts & parts,bool valid)456 ContentSettingsPattern::ContentSettingsPattern(
457     const PatternParts& parts,
458     bool valid)
459     : parts_(parts),
460       is_valid_(valid) {
461 }
462 
Matches(const GURL & url) const463 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 
MatchesAllHosts() const524 bool ContentSettingsPattern::MatchesAllHosts() const {
525   return parts_.has_domain_wildcard && parts_.host.empty();
526 }
527 
ToString() const528 std::string ContentSettingsPattern::ToString() const {
529   if (IsValid())
530     return content_settings::PatternParser::ToString(parts_);
531   else
532     return std::string();
533 }
534 
Compare(const ContentSettingsPattern & other) const535 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 
operator ==(const ContentSettingsPattern & other) const572 bool ContentSettingsPattern::operator==(
573     const ContentSettingsPattern& other) const {
574   return Compare(other) == IDENTITY;
575 }
576 
operator !=(const ContentSettingsPattern & other) const577 bool ContentSettingsPattern::operator!=(
578     const ContentSettingsPattern& other) const {
579   return !(*this == other);
580 }
581 
operator <(const ContentSettingsPattern & other) const582 bool ContentSettingsPattern::operator<(
583     const ContentSettingsPattern& other) const {
584   return Compare(other) < 0;
585 }
586 
operator >(const ContentSettingsPattern & other) const587 bool ContentSettingsPattern::operator>(
588     const ContentSettingsPattern& other) const {
589   return Compare(other) > 0;
590 }
591 
592 // static
CompareScheme(const ContentSettingsPattern::PatternParts & parts,const ContentSettingsPattern::PatternParts & other_parts)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
CompareHost(const ContentSettingsPattern::PatternParts & parts,const ContentSettingsPattern::PatternParts & other_parts)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
ComparePort(const ContentSettingsPattern::PatternParts & parts,const ContentSettingsPattern::PatternParts & other_parts)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 }
712