Home | History | Annotate | Download | only in common
      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
      3 // found in the LICENSE file.
      4 
      5 #include "extensions/common/user_script.h"
      6 
      7 #include "base/atomic_sequence_num.h"
      8 #include "base/command_line.h"
      9 #include "base/pickle.h"
     10 #include "base/strings/string_util.h"
     11 #include "extensions/common/switches.h"
     12 
     13 namespace {
     14 
     15 // This cannot be a plain int or int64 because we need to generate unique IDs
     16 // from multiple threads.
     17 base::StaticAtomicSequenceNumber g_user_script_id_generator;
     18 
     19 bool UrlMatchesGlobs(const std::vector<std::string>* globs,
     20                      const GURL& url) {
     21   for (std::vector<std::string>::const_iterator glob = globs->begin();
     22        glob != globs->end(); ++glob) {
     23     if (MatchPattern(url.spec(), *glob))
     24       return true;
     25   }
     26 
     27   return false;
     28 }
     29 
     30 }  // namespace
     31 
     32 namespace extensions {
     33 
     34 // The bitmask for valid user script injectable schemes used by URLPattern.
     35 enum {
     36   kValidUserScriptSchemes = URLPattern::SCHEME_CHROMEUI |
     37                             URLPattern::SCHEME_HTTP |
     38                             URLPattern::SCHEME_HTTPS |
     39                             URLPattern::SCHEME_FILE |
     40                             URLPattern::SCHEME_FTP
     41 };
     42 
     43 // static
     44 const char UserScript::kFileExtension[] = ".user.js";
     45 
     46 
     47 // static
     48 int UserScript::GenerateUserScriptID() {
     49    return g_user_script_id_generator.GetNext();
     50 }
     51 
     52 bool UserScript::IsURLUserScript(const GURL& url,
     53                                  const std::string& mime_type) {
     54   return EndsWith(url.ExtractFileName(), kFileExtension, false) &&
     55       mime_type != "text/html";
     56 }
     57 
     58 // static
     59 int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
     60   if (canExecuteScriptEverywhere)
     61     return URLPattern::SCHEME_ALL;
     62   int valid_schemes = kValidUserScriptSchemes;
     63   if (!CommandLine::ForCurrentProcess()->HasSwitch(
     64       switches::kExtensionsOnChromeURLs)) {
     65     valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
     66   }
     67   return valid_schemes;
     68 }
     69 
     70 UserScript::File::File(const base::FilePath& extension_root,
     71                        const base::FilePath& relative_path,
     72                        const GURL& url)
     73     : extension_root_(extension_root),
     74       relative_path_(relative_path),
     75       url_(url) {
     76 }
     77 
     78 UserScript::File::File() {}
     79 
     80 UserScript::File::~File() {}
     81 
     82 UserScript::UserScript()
     83     : run_location_(DOCUMENT_IDLE),
     84       user_script_id_(-1),
     85       emulate_greasemonkey_(false),
     86       match_all_frames_(false),
     87       match_about_blank_(false),
     88       incognito_enabled_(false) {}
     89 
     90 UserScript::~UserScript() {
     91 }
     92 
     93 void UserScript::add_url_pattern(const URLPattern& pattern) {
     94   url_set_.AddPattern(pattern);
     95 }
     96 
     97 void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
     98   exclude_url_set_.AddPattern(pattern);
     99 }
    100 
    101 bool UserScript::MatchesURL(const GURL& url) const {
    102   if (!url_set_.is_empty()) {
    103     if (!url_set_.MatchesURL(url))
    104       return false;
    105   }
    106 
    107   if (!exclude_url_set_.is_empty()) {
    108     if (exclude_url_set_.MatchesURL(url))
    109       return false;
    110   }
    111 
    112   if (!globs_.empty()) {
    113     if (!UrlMatchesGlobs(&globs_, url))
    114       return false;
    115   }
    116 
    117   if (!exclude_globs_.empty()) {
    118     if (UrlMatchesGlobs(&exclude_globs_, url))
    119       return false;
    120   }
    121 
    122   return true;
    123 }
    124 
    125 void UserScript::File::Pickle(::Pickle* pickle) const {
    126   pickle->WriteString(url_.spec());
    127   // Do not write path. It's not needed in the renderer.
    128   // Do not write content. It will be serialized by other means.
    129 }
    130 
    131 void UserScript::File::Unpickle(const ::Pickle& pickle, PickleIterator* iter) {
    132   // Read the url from the pickle.
    133   std::string url;
    134   CHECK(pickle.ReadString(iter, &url));
    135   set_url(GURL(url));
    136 }
    137 
    138 void UserScript::Pickle(::Pickle* pickle) const {
    139   // Write the simple types to the pickle.
    140   pickle->WriteInt(run_location());
    141   pickle->WriteString(extension_id());
    142   pickle->WriteInt(user_script_id_);
    143   pickle->WriteBool(emulate_greasemonkey());
    144   pickle->WriteBool(match_all_frames());
    145   pickle->WriteBool(match_about_blank());
    146   pickle->WriteBool(is_incognito_enabled());
    147 
    148   PickleGlobs(pickle, globs_);
    149   PickleGlobs(pickle, exclude_globs_);
    150   PickleURLPatternSet(pickle, url_set_);
    151   PickleURLPatternSet(pickle, exclude_url_set_);
    152   PickleScripts(pickle, js_scripts_);
    153   PickleScripts(pickle, css_scripts_);
    154 }
    155 
    156 void UserScript::PickleGlobs(::Pickle* pickle,
    157                              const std::vector<std::string>& globs) const {
    158   pickle->WriteUInt64(globs.size());
    159   for (std::vector<std::string>::const_iterator glob = globs.begin();
    160        glob != globs.end(); ++glob) {
    161     pickle->WriteString(*glob);
    162   }
    163 }
    164 
    165 void UserScript::PickleURLPatternSet(::Pickle* pickle,
    166                                      const URLPatternSet& pattern_list) const {
    167   pickle->WriteUInt64(pattern_list.patterns().size());
    168   for (URLPatternSet::const_iterator pattern = pattern_list.begin();
    169        pattern != pattern_list.end(); ++pattern) {
    170     pickle->WriteInt(pattern->valid_schemes());
    171     pickle->WriteString(pattern->GetAsString());
    172   }
    173 }
    174 
    175 void UserScript::PickleScripts(::Pickle* pickle,
    176                                const FileList& scripts) const {
    177   pickle->WriteUInt64(scripts.size());
    178   for (FileList::const_iterator file = scripts.begin();
    179        file != scripts.end(); ++file) {
    180     file->Pickle(pickle);
    181   }
    182 }
    183 
    184 void UserScript::Unpickle(const ::Pickle& pickle, PickleIterator* iter) {
    185   // Read the run location.
    186   int run_location = 0;
    187   CHECK(pickle.ReadInt(iter, &run_location));
    188   CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
    189   run_location_ = static_cast<RunLocation>(run_location);
    190 
    191   CHECK(pickle.ReadString(iter, &extension_id_));
    192   CHECK(pickle.ReadInt(iter, &user_script_id_));
    193   CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_));
    194   CHECK(pickle.ReadBool(iter, &match_all_frames_));
    195   CHECK(pickle.ReadBool(iter, &match_about_blank_));
    196   CHECK(pickle.ReadBool(iter, &incognito_enabled_));
    197 
    198   UnpickleGlobs(pickle, iter, &globs_);
    199   UnpickleGlobs(pickle, iter, &exclude_globs_);
    200   UnpickleURLPatternSet(pickle, iter, &url_set_);
    201   UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
    202   UnpickleScripts(pickle, iter, &js_scripts_);
    203   UnpickleScripts(pickle, iter, &css_scripts_);
    204 }
    205 
    206 void UserScript::UnpickleGlobs(const ::Pickle& pickle, PickleIterator* iter,
    207                                std::vector<std::string>* globs) {
    208   uint64 num_globs = 0;
    209   CHECK(pickle.ReadUInt64(iter, &num_globs));
    210   globs->clear();
    211   for (uint64 i = 0; i < num_globs; ++i) {
    212     std::string glob;
    213     CHECK(pickle.ReadString(iter, &glob));
    214     globs->push_back(glob);
    215   }
    216 }
    217 
    218 void UserScript::UnpickleURLPatternSet(const ::Pickle& pickle,
    219                                        PickleIterator* iter,
    220                                        URLPatternSet* pattern_list) {
    221   uint64 num_patterns = 0;
    222   CHECK(pickle.ReadUInt64(iter, &num_patterns));
    223 
    224   pattern_list->ClearPatterns();
    225   for (uint64 i = 0; i < num_patterns; ++i) {
    226     int valid_schemes;
    227     CHECK(pickle.ReadInt(iter, &valid_schemes));
    228 
    229     std::string pattern_str;
    230     CHECK(pickle.ReadString(iter, &pattern_str));
    231 
    232     URLPattern pattern(kValidUserScriptSchemes);
    233     URLPattern::ParseResult result = pattern.Parse(pattern_str);
    234     CHECK(URLPattern::PARSE_SUCCESS == result) <<
    235         URLPattern::GetParseResultString(result) << " " << pattern_str.c_str();
    236 
    237     pattern.SetValidSchemes(valid_schemes);
    238     pattern_list->AddPattern(pattern);
    239   }
    240 }
    241 
    242 void UserScript::UnpickleScripts(const ::Pickle& pickle, PickleIterator* iter,
    243                                  FileList* scripts) {
    244   uint64 num_files = 0;
    245   CHECK(pickle.ReadUInt64(iter, &num_files));
    246   scripts->clear();
    247   for (uint64 i = 0; i < num_files; ++i) {
    248     File file;
    249     file.Unpickle(pickle, iter);
    250     scripts->push_back(file);
    251   }
    252 }
    253 
    254 bool operator<(const UserScript& script1, const UserScript& script2) {
    255   // The only kind of script that should be compared is the kind that has its
    256   // IDs initialized to a meaningful value.
    257   DCHECK(script1.id() != -1 && script2.id() != -1);
    258   return script1.id() < script2.id();
    259 }
    260 
    261 }  // namespace extensions
    262