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 13namespace { 14 15// This cannot be a plain int or int64 because we need to generate unique IDs 16// from multiple threads. 17base::StaticAtomicSequenceNumber g_user_script_id_generator; 18 19bool 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 32namespace extensions { 33 34// The bitmask for valid user script injectable schemes used by URLPattern. 35enum { 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 44const char UserScript::kFileExtension[] = ".user.js"; 45 46 47// static 48int UserScript::GenerateUserScriptID() { 49 return g_user_script_id_generator.GetNext(); 50} 51 52bool 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 59int 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 70UserScript::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 78UserScript::File::File() {} 79 80UserScript::File::~File() {} 81 82UserScript::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 90UserScript::~UserScript() { 91} 92 93void UserScript::add_url_pattern(const URLPattern& pattern) { 94 url_set_.AddPattern(pattern); 95} 96 97void UserScript::add_exclude_url_pattern(const URLPattern& pattern) { 98 exclude_url_set_.AddPattern(pattern); 99} 100 101bool 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 125void 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 131void 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 138void 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 156void 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 165void 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 175void 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 184void 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 206void 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 218void 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 242void 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 254bool 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