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