1 // Copyright (c) 2011 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 "chrome/common/extensions/user_script.h"
6
7 #include "base/pickle.h"
8 #include "base/string_util.h"
9
10 namespace {
11
UrlMatchesPatterns(const UserScript::PatternList * patterns,const GURL & url)12 bool UrlMatchesPatterns(const UserScript::PatternList* patterns,
13 const GURL& url) {
14 for (UserScript::PatternList::const_iterator pattern = patterns->begin();
15 pattern != patterns->end(); ++pattern) {
16 if (pattern->MatchesUrl(url))
17 return true;
18 }
19
20 return false;
21 }
22
UrlMatchesGlobs(const std::vector<std::string> * globs,const GURL & url)23 bool UrlMatchesGlobs(const std::vector<std::string>* globs,
24 const GURL& url) {
25 for (std::vector<std::string>::const_iterator glob = globs->begin();
26 glob != globs->end(); ++glob) {
27 if (MatchPattern(url.spec(), *glob))
28 return true;
29 }
30
31 return false;
32 }
33
34 } // namespace
35
36 // static
37 const char UserScript::kFileExtension[] = ".user.js";
38
39 // static
40 const int UserScript::kValidUserScriptSchemes =
41 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
42 URLPattern::SCHEME_FILE | URLPattern::SCHEME_FTP;
43
IsURLUserScript(const GURL & url,const std::string & mime_type)44 bool UserScript::IsURLUserScript(const GURL& url,
45 const std::string& mime_type) {
46 return EndsWith(url.ExtractFileName(), kFileExtension, false) &&
47 mime_type != "text/html";
48 }
49
File(const FilePath & extension_root,const FilePath & relative_path,const GURL & url)50 UserScript::File::File(const FilePath& extension_root,
51 const FilePath& relative_path,
52 const GURL& url)
53 : extension_root_(extension_root),
54 relative_path_(relative_path),
55 url_(url) {
56 }
57
File()58 UserScript::File::File() {}
59
~File()60 UserScript::File::~File() {}
61
UserScript()62 UserScript::UserScript()
63 : run_location_(DOCUMENT_IDLE), emulate_greasemonkey_(false),
64 match_all_frames_(false), incognito_enabled_(false) {
65 }
66
~UserScript()67 UserScript::~UserScript() {
68 }
69
add_url_pattern(const URLPattern & pattern)70 void UserScript::add_url_pattern(const URLPattern& pattern) {
71 url_patterns_.push_back(pattern);
72 }
73
MatchesUrl(const GURL & url) const74 bool UserScript::MatchesUrl(const GURL& url) const {
75 if (!url_patterns_.empty()) {
76 if (!UrlMatchesPatterns(&url_patterns_, url))
77 return false;
78 }
79
80 if (!globs_.empty()) {
81 if (!UrlMatchesGlobs(&globs_, url))
82 return false;
83 }
84
85 if (!exclude_globs_.empty()) {
86 if (UrlMatchesGlobs(&exclude_globs_, url))
87 return false;
88 }
89
90 return true;
91 }
92
Pickle(::Pickle * pickle) const93 void UserScript::File::Pickle(::Pickle* pickle) const {
94 pickle->WriteString(url_.spec());
95 // Do not write path. It's not needed in the renderer.
96 // Do not write content. It will be serialized by other means.
97 }
98
Unpickle(const::Pickle & pickle,void ** iter)99 void UserScript::File::Unpickle(const ::Pickle& pickle, void** iter) {
100 // Read url.
101 std::string url;
102 CHECK(pickle.ReadString(iter, &url));
103 set_url(GURL(url));
104 }
105
Pickle(::Pickle * pickle) const106 void UserScript::Pickle(::Pickle* pickle) const {
107 // Write simple types.
108 pickle->WriteInt(run_location());
109 pickle->WriteString(extension_id());
110 pickle->WriteBool(emulate_greasemonkey());
111 pickle->WriteBool(match_all_frames());
112 pickle->WriteBool(is_incognito_enabled());
113
114 // Write globs.
115 std::vector<std::string>::const_iterator glob;
116 pickle->WriteSize(globs_.size());
117 for (glob = globs_.begin(); glob != globs_.end(); ++glob) {
118 pickle->WriteString(*glob);
119 }
120 pickle->WriteSize(exclude_globs_.size());
121 for (glob = exclude_globs_.begin(); glob != exclude_globs_.end(); ++glob) {
122 pickle->WriteString(*glob);
123 }
124
125 // Write url patterns.
126 pickle->WriteSize(url_patterns_.size());
127 for (PatternList::const_iterator pattern = url_patterns_.begin();
128 pattern != url_patterns_.end(); ++pattern) {
129 pickle->WriteInt(pattern->valid_schemes());
130 pickle->WriteString(pattern->GetAsString());
131 }
132
133 // Write js scripts.
134 pickle->WriteSize(js_scripts_.size());
135 for (FileList::const_iterator file = js_scripts_.begin();
136 file != js_scripts_.end(); ++file) {
137 file->Pickle(pickle);
138 }
139
140 // Write css scripts.
141 pickle->WriteSize(css_scripts_.size());
142 for (FileList::const_iterator file = css_scripts_.begin();
143 file != css_scripts_.end(); ++file) {
144 file->Pickle(pickle);
145 }
146 }
147
Unpickle(const::Pickle & pickle,void ** iter)148 void UserScript::Unpickle(const ::Pickle& pickle, void** iter) {
149 // Read the run location.
150 int run_location = 0;
151 CHECK(pickle.ReadInt(iter, &run_location));
152 CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
153 run_location_ = static_cast<RunLocation>(run_location);
154
155 CHECK(pickle.ReadString(iter, &extension_id_));
156 CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_));
157 CHECK(pickle.ReadBool(iter, &match_all_frames_));
158 CHECK(pickle.ReadBool(iter, &incognito_enabled_));
159
160 // Read globs.
161 size_t num_globs = 0;
162 CHECK(pickle.ReadSize(iter, &num_globs));
163 globs_.clear();
164 for (size_t i = 0; i < num_globs; ++i) {
165 std::string glob;
166 CHECK(pickle.ReadString(iter, &glob));
167 globs_.push_back(glob);
168 }
169
170 CHECK(pickle.ReadSize(iter, &num_globs));
171 exclude_globs_.clear();
172 for (size_t i = 0; i < num_globs; ++i) {
173 std::string glob;
174 CHECK(pickle.ReadString(iter, &glob));
175 exclude_globs_.push_back(glob);
176 }
177
178 // Read url patterns.
179 size_t num_patterns = 0;
180 CHECK(pickle.ReadSize(iter, &num_patterns));
181
182 url_patterns_.clear();
183 for (size_t i = 0; i < num_patterns; ++i) {
184 int valid_schemes;
185 CHECK(pickle.ReadInt(iter, &valid_schemes));
186 std::string pattern_str;
187 URLPattern pattern(valid_schemes);
188 CHECK(pickle.ReadString(iter, &pattern_str));
189
190 // We remove the file scheme if it's not actually allowed (see Extension::
191 // LoadUserScriptHelper), but we need it temporarily while loading the
192 // pattern so that it's valid.
193 bool had_file_scheme = (valid_schemes & URLPattern::SCHEME_FILE) != 0;
194 if (!had_file_scheme)
195 pattern.set_valid_schemes(valid_schemes | URLPattern::SCHEME_FILE);
196 CHECK(URLPattern::PARSE_SUCCESS ==
197 pattern.Parse(pattern_str, URLPattern::PARSE_LENIENT));
198 if (!had_file_scheme)
199 pattern.set_valid_schemes(valid_schemes);
200
201 url_patterns_.push_back(pattern);
202 }
203
204 // Read js scripts.
205 size_t num_js_files = 0;
206 CHECK(pickle.ReadSize(iter, &num_js_files));
207 js_scripts_.clear();
208 for (size_t i = 0; i < num_js_files; ++i) {
209 File file;
210 file.Unpickle(pickle, iter);
211 js_scripts_.push_back(file);
212 }
213
214 // Read css scripts.
215 size_t num_css_files = 0;
216 CHECK(pickle.ReadSize(iter, &num_css_files));
217 css_scripts_.clear();
218 for (size_t i = 0; i < num_css_files; ++i) {
219 File file;
220 file.Unpickle(pickle, iter);
221 css_scripts_.push_back(file);
222 }
223 }
224