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