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