Home | History | Annotate | Download | only in common
      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_parser.h"
      6 
      7 #include "base/strings/string_util.h"
      8 #include "chrome/common/url_constants.h"
      9 #include "extensions/common/constants.h"
     10 #include "net/base/net_util.h"
     11 #include "url/gurl.h"
     12 #include "url/url_canon.h"
     13 
     14 namespace {
     15 
     16 const char* kUrlPathSeparator = "/";
     17 const char* kUrlPortSeparator = ":";
     18 
     19 class Component {
     20  public:
     21   Component() : start(0), len(0) {}
     22   Component(size_t s, size_t l) : start(s), len(l) {}
     23 
     24   bool IsNonEmpty() {
     25     return len > 0;
     26   }
     27 
     28   size_t start;
     29   size_t len;
     30 };
     31 
     32 }  // namespace
     33 
     34 namespace content_settings {
     35 
     36 const char* PatternParser::kDomainWildcard = "[*.]";
     37 
     38 const size_t PatternParser::kDomainWildcardLength = 4;
     39 
     40 const char* PatternParser::kSchemeWildcard = "*";
     41 
     42 const char* PatternParser::kHostWildcard = "*";
     43 
     44 const char* PatternParser::kPortWildcard = "*";
     45 
     46 const char* PatternParser::kPathWildcard = "*";
     47 
     48 // static
     49 void PatternParser::Parse(const std::string& pattern_spec,
     50                           ContentSettingsPattern::BuilderInterface* builder) {
     51   if (pattern_spec == "*") {
     52     builder->WithSchemeWildcard();
     53     builder->WithDomainWildcard();
     54     builder->WithPortWildcard();
     55     return;
     56   }
     57 
     58   // Initialize components for the individual patterns parts to empty
     59   // sub-strings.
     60   Component scheme_component;
     61   Component host_component;
     62   Component port_component;
     63   Component path_component;
     64 
     65   size_t start = 0;
     66   size_t current_pos = 0;
     67 
     68   if (pattern_spec.empty())
     69     return;
     70 
     71   // Test if a scheme pattern is in the spec.
     72   current_pos = pattern_spec.find(
     73       std::string(content::kStandardSchemeSeparator), start);
     74   if (current_pos != std::string::npos) {
     75     scheme_component = Component(start, current_pos);
     76     start = current_pos + strlen(content::kStandardSchemeSeparator);
     77     current_pos = start;
     78   } else {
     79     current_pos = start;
     80   }
     81 
     82   if (start >= pattern_spec.size())
     83     return;  // Bad pattern spec.
     84 
     85   // Jump to the end of domain wildcards or an IPv6 addresses. IPv6 addresses
     86   // contain ':'. So first move to the end of an IPv6 address befor searching
     87   // for the ':' that separates the port form the host.
     88   if (pattern_spec[current_pos] == '[')
     89     current_pos = pattern_spec.find("]", start);
     90 
     91   if (current_pos == std::string::npos)
     92     return;  // Bad pattern spec.
     93 
     94   current_pos = pattern_spec.find(std::string(kUrlPortSeparator), current_pos);
     95   if (current_pos == std::string::npos) {
     96     // No port spec found
     97     current_pos = pattern_spec.find(std::string(kUrlPathSeparator), start);
     98     if (current_pos == std::string::npos) {
     99       current_pos = pattern_spec.size();
    100       host_component = Component(start, current_pos - start);
    101     } else {
    102       // Pattern has a path spec.
    103       host_component = Component(start, current_pos - start);
    104     }
    105     start = current_pos;
    106   } else {
    107     // Port spec found.
    108     host_component = Component(start, current_pos - start);
    109     start = current_pos + 1;
    110     if (start < pattern_spec.size()) {
    111       current_pos = pattern_spec.find(std::string(kUrlPathSeparator), start);
    112       if (current_pos == std::string::npos) {
    113         current_pos = pattern_spec.size();
    114       }
    115       port_component = Component(start, current_pos - start);
    116       start = current_pos;
    117     }
    118   }
    119 
    120   current_pos = pattern_spec.size();
    121   if (start < current_pos) {
    122     // Pattern has a path spec.
    123     path_component = Component(start, current_pos - start);
    124   }
    125 
    126   // Set pattern parts.
    127   std::string scheme;
    128   if (scheme_component.IsNonEmpty()) {
    129     scheme = pattern_spec.substr(scheme_component.start, scheme_component.len);
    130     if (scheme == kSchemeWildcard) {
    131       builder->WithSchemeWildcard();
    132     } else {
    133       builder->WithScheme(scheme);
    134     }
    135   } else {
    136     builder->WithSchemeWildcard();
    137   }
    138 
    139   if (host_component.IsNonEmpty()) {
    140     std::string host = pattern_spec.substr(host_component.start,
    141                                            host_component.len);
    142     if (host == kHostWildcard) {
    143       builder->WithDomainWildcard();
    144     } else if (StartsWithASCII(host, kDomainWildcard, true)) {
    145       host = host.substr(kDomainWildcardLength);
    146       builder->WithDomainWildcard();
    147       builder->WithHost(host);
    148     } else {
    149       // If the host contains a wildcard symbol then it is invalid.
    150       if (host.find(kHostWildcard) != std::string::npos) {
    151         builder->Invalid();
    152         return;
    153       }
    154       builder->WithHost(host);
    155     }
    156   }
    157 
    158   if (port_component.IsNonEmpty()) {
    159     const std::string port = pattern_spec.substr(port_component.start,
    160                                                  port_component.len);
    161     if (port == kPortWildcard) {
    162       builder->WithPortWildcard();
    163     } else {
    164       // Check if the port string represents a valid port.
    165       for (size_t i = 0; i < port.size(); ++i) {
    166         if (!IsAsciiDigit(port[i])) {
    167           builder->Invalid();
    168           return;
    169         }
    170       }
    171       // TODO(markusheintz): Check port range.
    172       builder->WithPort(port);
    173     }
    174   } else {
    175     if (scheme != std::string(extensions::kExtensionScheme) &&
    176         scheme != std::string(chrome::kFileScheme))
    177       builder->WithPortWildcard();
    178   }
    179 
    180   if (path_component.IsNonEmpty()) {
    181     const std::string path = pattern_spec.substr(path_component.start,
    182                                                  path_component.len);
    183     if (path.substr(1) == kPathWildcard)
    184       builder->WithPathWildcard();
    185     else
    186       builder->WithPath(path);
    187   }
    188 }
    189 
    190 // static
    191 std::string PatternParser::ToString(
    192     const ContentSettingsPattern::PatternParts& parts) {
    193   // Return the most compact form to support legacy code and legacy pattern
    194   // strings.
    195   if (parts.is_scheme_wildcard &&
    196       parts.has_domain_wildcard &&
    197       parts.host.empty() &&
    198       parts.is_port_wildcard)
    199     return "*";
    200 
    201   std::string str;
    202   if (!parts.is_scheme_wildcard)
    203     str += parts.scheme + content::kStandardSchemeSeparator;
    204 
    205   if (parts.scheme == chrome::kFileScheme) {
    206     if (parts.is_path_wildcard)
    207       return str + kUrlPathSeparator + kPathWildcard;
    208     else
    209       return str + parts.path;
    210   }
    211 
    212   if (parts.has_domain_wildcard) {
    213     if (parts.host.empty())
    214       str += kHostWildcard;
    215     else
    216       str += kDomainWildcard;
    217   }
    218   str += parts.host;
    219 
    220   if (parts.scheme == std::string(extensions::kExtensionScheme)) {
    221     str += parts.path.empty() ? std::string(kUrlPathSeparator) : parts.path;
    222     return str;
    223   }
    224 
    225   if (!parts.is_port_wildcard) {
    226     str += std::string(kUrlPortSeparator) + parts.port;
    227   }
    228 
    229   return str;
    230 }
    231 
    232 }  // namespace content_settings
    233