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), emulate_greasemonkey_(false), 73 match_all_frames_(false), incognito_enabled_(false) { 74 } 75 76 UserScript::~UserScript() { 77 } 78 79 void UserScript::add_url_pattern(const URLPattern& pattern) { 80 url_set_.AddPattern(pattern); 81 } 82 83 void UserScript::add_exclude_url_pattern(const URLPattern& pattern) { 84 exclude_url_set_.AddPattern(pattern); 85 } 86 87 bool UserScript::MatchesURL(const GURL& url) const { 88 if (!url_set_.is_empty()) { 89 if (!url_set_.MatchesURL(url)) 90 return false; 91 } 92 93 if (!exclude_url_set_.is_empty()) { 94 if (exclude_url_set_.MatchesURL(url)) 95 return false; 96 } 97 98 if (!globs_.empty()) { 99 if (!UrlMatchesGlobs(&globs_, url)) 100 return false; 101 } 102 103 if (!exclude_globs_.empty()) { 104 if (UrlMatchesGlobs(&exclude_globs_, url)) 105 return false; 106 } 107 108 return true; 109 } 110 111 void UserScript::File::Pickle(::Pickle* pickle) const { 112 pickle->WriteString(url_.spec()); 113 // Do not write path. It's not needed in the renderer. 114 // Do not write content. It will be serialized by other means. 115 } 116 117 void UserScript::File::Unpickle(const ::Pickle& pickle, PickleIterator* iter) { 118 // Read the url from the pickle. 119 std::string url; 120 CHECK(pickle.ReadString(iter, &url)); 121 set_url(GURL(url)); 122 } 123 124 void UserScript::Pickle(::Pickle* pickle) const { 125 // Write the simple types to the pickle. 126 pickle->WriteInt(run_location()); 127 pickle->WriteString(extension_id()); 128 pickle->WriteBool(emulate_greasemonkey()); 129 pickle->WriteBool(match_all_frames()); 130 pickle->WriteBool(is_incognito_enabled()); 131 132 PickleGlobs(pickle, globs_); 133 PickleGlobs(pickle, exclude_globs_); 134 PickleURLPatternSet(pickle, url_set_); 135 PickleURLPatternSet(pickle, exclude_url_set_); 136 PickleScripts(pickle, js_scripts_); 137 PickleScripts(pickle, css_scripts_); 138 } 139 140 void UserScript::PickleGlobs(::Pickle* pickle, 141 const std::vector<std::string>& globs) const { 142 pickle->WriteUInt64(globs.size()); 143 for (std::vector<std::string>::const_iterator glob = globs.begin(); 144 glob != globs.end(); ++glob) { 145 pickle->WriteString(*glob); 146 } 147 } 148 149 void UserScript::PickleURLPatternSet(::Pickle* pickle, 150 const URLPatternSet& pattern_list) const { 151 pickle->WriteUInt64(pattern_list.patterns().size()); 152 for (URLPatternSet::const_iterator pattern = pattern_list.begin(); 153 pattern != pattern_list.end(); ++pattern) { 154 pickle->WriteInt(pattern->valid_schemes()); 155 pickle->WriteString(pattern->GetAsString()); 156 } 157 } 158 159 void UserScript::PickleScripts(::Pickle* pickle, 160 const FileList& scripts) const { 161 pickle->WriteUInt64(scripts.size()); 162 for (FileList::const_iterator file = scripts.begin(); 163 file != scripts.end(); ++file) { 164 file->Pickle(pickle); 165 } 166 } 167 168 void UserScript::Unpickle(const ::Pickle& pickle, PickleIterator* iter) { 169 // Read the run location. 170 int run_location = 0; 171 CHECK(pickle.ReadInt(iter, &run_location)); 172 CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST); 173 run_location_ = static_cast<RunLocation>(run_location); 174 175 CHECK(pickle.ReadString(iter, &extension_id_)); 176 CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_)); 177 CHECK(pickle.ReadBool(iter, &match_all_frames_)); 178 CHECK(pickle.ReadBool(iter, &incognito_enabled_)); 179 180 UnpickleGlobs(pickle, iter, &globs_); 181 UnpickleGlobs(pickle, iter, &exclude_globs_); 182 UnpickleURLPatternSet(pickle, iter, &url_set_); 183 UnpickleURLPatternSet(pickle, iter, &exclude_url_set_); 184 UnpickleScripts(pickle, iter, &js_scripts_); 185 UnpickleScripts(pickle, iter, &css_scripts_); 186 } 187 188 void UserScript::UnpickleGlobs(const ::Pickle& pickle, PickleIterator* iter, 189 std::vector<std::string>* globs) { 190 uint64 num_globs = 0; 191 CHECK(pickle.ReadUInt64(iter, &num_globs)); 192 globs->clear(); 193 for (uint64 i = 0; i < num_globs; ++i) { 194 std::string glob; 195 CHECK(pickle.ReadString(iter, &glob)); 196 globs->push_back(glob); 197 } 198 } 199 200 void UserScript::UnpickleURLPatternSet(const ::Pickle& pickle, 201 PickleIterator* iter, 202 URLPatternSet* pattern_list) { 203 uint64 num_patterns = 0; 204 CHECK(pickle.ReadUInt64(iter, &num_patterns)); 205 206 pattern_list->ClearPatterns(); 207 for (uint64 i = 0; i < num_patterns; ++i) { 208 int valid_schemes; 209 CHECK(pickle.ReadInt(iter, &valid_schemes)); 210 211 std::string pattern_str; 212 CHECK(pickle.ReadString(iter, &pattern_str)); 213 214 URLPattern pattern(kValidUserScriptSchemes); 215 URLPattern::ParseResult result = pattern.Parse(pattern_str); 216 CHECK(URLPattern::PARSE_SUCCESS == result) << 217 URLPattern::GetParseResultString(result) << " " << pattern_str.c_str(); 218 219 pattern.SetValidSchemes(valid_schemes); 220 pattern_list->AddPattern(pattern); 221 } 222 } 223 224 void UserScript::UnpickleScripts(const ::Pickle& pickle, PickleIterator* iter, 225 FileList* scripts) { 226 uint64 num_files = 0; 227 CHECK(pickle.ReadUInt64(iter, &num_files)); 228 scripts->clear(); 229 for (uint64 i = 0; i < num_files; ++i) { 230 File file; 231 file.Unpickle(pickle, iter); 232 scripts->push_back(file); 233 } 234 } 235 236 } // namespace extensions 237