Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(924)

Side by Side Diff: chrome/browser/extensions/user_script_master.cc

Issue 18198: Add user script support to extensions. (Closed)
Patch Set: Compile fixes for linux and mac Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/user_script_master.h" 5 #include "chrome/browser/extensions/user_script_master.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/file_path.h" 9 #include "base/file_path.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/path_service.h" 12 #include "base/path_service.h"
13 #include "base/pickle.h" 13 #include "base/pickle.h"
14 #include "base/string_util.h" 14 #include "base/string_util.h"
15 #include "chrome/common/notification_service.h" 15 #include "chrome/common/notification_service.h"
16 #include "googleurl/src/gurl.h" 16 #include "chrome/common/stl_util-inl.h"
17 #include "net/base/net_util.h" 17 #include "net/base/net_util.h"
18 18
19 // Defined in extension.h. 19 // Defined in extension.h.
20 extern const char kExtensionURLScheme[]; 20 extern const char kExtensionURLScheme[];
21 extern const char kUserScriptURLScheme[]; 21 extern const char kUserScriptURLScheme[];
22 22
23 // static 23 // static
24 void UserScriptMaster::ScriptReloader::ParseMetadataHeader( 24 void UserScriptMaster::ScriptReloader::ParseMetadataHeader(
25 const StringPiece& script_text, std::vector<std::string> *includes) { 25 const StringPiece& script_text, std::vector<std::string> *includes) {
26 // http://wiki.greasespot.net/Metadata_block 26 // http://wiki.greasespot.net/Metadata_block
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 } 67 }
68 68
69 // If no @include patterns were specified, default to @include *. 69 // If no @include patterns were specified, default to @include *.
70 // This is what Greasemonkey does. 70 // This is what Greasemonkey does.
71 if (includes->size() == 0) { 71 if (includes->size() == 0) {
72 includes->push_back("*"); 72 includes->push_back("*");
73 } 73 }
74 } 74 }
75 75
76 void UserScriptMaster::ScriptReloader::StartScan( 76 void UserScriptMaster::ScriptReloader::StartScan(
77 MessageLoop* work_loop, 77 MessageLoop* work_loop, const FilePath& script_dir,
78 const FilePath& script_dir) { 78 const UserScriptList& lone_scripts) {
79 // Add a reference to ourselves to keep ourselves alive while we're running. 79 // Add a reference to ourselves to keep ourselves alive while we're running.
80 // Balanced by NotifyMaster(). 80 // Balanced by NotifyMaster().
81 AddRef(); 81 AddRef();
82 work_loop->PostTask(FROM_HERE, 82 work_loop->PostTask(FROM_HERE,
83 NewRunnableMethod(this, 83 NewRunnableMethod(this,
84 &UserScriptMaster::ScriptReloader::RunScan, 84 &UserScriptMaster::ScriptReloader::RunScan,
85 script_dir)); 85 script_dir, lone_scripts));
86 } 86 }
87 87
88 void UserScriptMaster::ScriptReloader::NotifyMaster( 88 void UserScriptMaster::ScriptReloader::NotifyMaster(
89 base::SharedMemory* memory) { 89 base::SharedMemory* memory) {
90 if (!master_) { 90 if (!master_) {
91 // The master went away, so these new scripts aren't useful anymore. 91 // The master went away, so these new scripts aren't useful anymore.
92 delete memory; 92 delete memory;
93 } else { 93 } else {
94 master_->NewScriptsAvailable(memory); 94 master_->NewScriptsAvailable(memory);
95 } 95 }
96 96
97 // Drop our self-reference. 97 // Drop our self-reference.
98 // Balances StartScan(). 98 // Balances StartScan().
99 Release(); 99 Release();
100 } 100 }
101 101
102 void UserScriptMaster::ScriptReloader::RunScan(const FilePath script_dir) { 102 void UserScriptMaster::ScriptReloader::RunScan(
103 base::SharedMemory* shared_memory = GetNewScripts(script_dir); 103 const FilePath script_dir, const UserScriptList lone_scripts) {
104 base::SharedMemory* shared_memory = GetNewScripts(script_dir, lone_scripts);
104 105
105 // Post the new scripts back to the master's message loop. 106 // Post the new scripts back to the master's message loop.
106 master_message_loop_->PostTask(FROM_HERE, 107 master_message_loop_->PostTask(FROM_HERE,
107 NewRunnableMethod(this, 108 NewRunnableMethod(this,
108 &UserScriptMaster::ScriptReloader::NotifyMaster, 109 &UserScriptMaster::ScriptReloader::NotifyMaster,
109 shared_memory)); 110 shared_memory));
110 } 111 }
111 112
112 base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts( 113 base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts(
113 const FilePath& script_dir) { 114 const FilePath& script_dir, const UserScriptList& lone_scripts) {
114 std::vector<std::wstring> scripts; 115 UserScriptList all_scripts;
115 116
116 file_util::FileEnumerator enumerator(script_dir, false, 117 // Find all the scripts in |script_dir|.
117 file_util::FileEnumerator::FILES, 118 if (!script_dir.value().empty()) {
118 FILE_PATH_LITERAL("*.user.js")); 119 file_util::FileEnumerator enumerator(script_dir, false,
119 for (FilePath file = enumerator.Next(); !file.value().empty(); 120 file_util::FileEnumerator::FILES,
120 file = enumerator.Next()) { 121 FILE_PATH_LITERAL("*.user.js"));
121 scripts.push_back(file.ToWStringHack()); 122 for (FilePath file = enumerator.Next(); !file.value().empty();
122 } 123 file = enumerator.Next()) {
123 124 all_scripts.push_back(UserScriptInfo());
124 if (scripts.empty()) 125 UserScriptInfo& info = all_scripts.back();
125 return NULL; 126 info.url = GURL(std::string(kUserScriptURLScheme) + ":/" +
126 127 net::FilePathToFileURL(file.ToWStringHack()).ExtractFileName());
127 // Pickle scripts data. 128 info.path = file;
128 Pickle pickle;
129 pickle.WriteSize(scripts.size());
130 for (std::vector<std::wstring>::iterator path = scripts.begin();
131 path != scripts.end(); ++path) {
132 std::string url(kUserScriptURLScheme);
133 url += ":/";
134 url += net::FilePathToFileURL(*path).ExtractFileName();
135
136 std::string contents;
137 // TODO(aa): Support unicode script files.
138 file_util::ReadFileToString(*path, &contents);
139
140 std::vector<std::string> includes;
141 ParseMetadataHeader(contents, &includes);
142
143 // Write scripts as 'data' so that we can read it out in the slave without
144 // allocating a new string.
145 pickle.WriteData(url.c_str(), url.length());
146 pickle.WriteData(contents.c_str(), contents.length());
147 pickle.WriteSize(includes.size());
148 for (std::vector<std::string>::iterator iter = includes.begin();
149 iter != includes.end(); ++iter) {
150 pickle.WriteString(*iter);
151 } 129 }
152 } 130 }
153 131
132 if (all_scripts.empty() && lone_scripts.empty())
133 return NULL;
134
135 // Add all the lone scripts.
136 all_scripts.insert(all_scripts.end(), lone_scripts.begin(),
137 lone_scripts.end());
138
139 // Load and pickle each script. Look for a metadata header if there are no
140 // matches specified already.
141 Pickle pickle;
142 pickle.WriteSize(all_scripts.size());
143 for (UserScriptList::iterator iter = all_scripts.begin();
144 iter != all_scripts.end(); ++iter) {
145 // TODO(aa): Support unicode script files.
146 std::string contents;
147 file_util::ReadFileToString(iter->path.ToWStringHack(), &contents);
148
149 if (iter->matches.empty()) {
150 // TODO(aa): Handle errors parsing header.
151 ParseMetadataHeader(contents, &iter->matches);
152 }
153
154 PickleScriptData(*iter, contents, &pickle);
155 }
156
154 // Create the shared memory object. 157 // Create the shared memory object.
155 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); 158 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
156 159
157 if (!shared_memory->Create(std::wstring(), // anonymous 160 if (!shared_memory->Create(std::wstring(), // anonymous
158 false, // read-only 161 false, // read-only
159 false, // open existing 162 false, // open existing
160 pickle.size())) { 163 pickle.size())) {
161 return NULL; 164 return NULL;
162 } 165 }
163 166
164 // Map into our process. 167 // Map into our process.
165 if (!shared_memory->Map(pickle.size())) 168 if (!shared_memory->Map(pickle.size()))
166 return NULL; 169 return NULL;
167 170
168 // Copy the pickle to shared memory. 171 // Copy the pickle to shared memory.
169 memcpy(shared_memory->memory(), pickle.data(), pickle.size()); 172 memcpy(shared_memory->memory(), pickle.data(), pickle.size());
170 173
171 return shared_memory.release(); 174 return shared_memory.release();
172 } 175 }
173 176
177 void UserScriptMaster::ScriptReloader::PickleScriptData(
178 const UserScriptInfo& script, const std::string& contents, Pickle* pickle) {
179 // Write scripts as 'data' so that we can read it out in the slave without
180 // allocating a new string.
181 pickle->WriteData(script.url.spec().c_str(), script.url.spec().length());
182 pickle->WriteData(contents.c_str(), contents.length());
183 pickle->WriteSize(script.matches.size());
184 for (std::vector<std::string>::const_iterator iter = script.matches.begin();
185 iter != script.matches.end(); ++iter) {
186 pickle->WriteString(*iter);
187 }
188 }
189
174 UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop, 190 UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
175 const FilePath& script_dir) 191 const FilePath& script_dir)
176 : user_script_dir_(new FilePath(script_dir)), 192 : user_script_dir_(script_dir),
177 dir_watcher_(new DirectoryWatcher),
178 worker_loop_(worker_loop), 193 worker_loop_(worker_loop),
179 pending_scan_(false) { 194 pending_scan_(false) {
180 // Watch our scripts directory for modifications. 195 if (!user_script_dir_.value().empty())
181 if (dir_watcher_->Watch(script_dir, this)) { 196 AddWatchedPath(script_dir);
182 // (Asynchronously) scan for our initial set of scripts.
183 StartScan();
184 }
185 } 197 }
186 198
187 UserScriptMaster::~UserScriptMaster() { 199 UserScriptMaster::~UserScriptMaster() {
188 if (script_reloader_) 200 if (script_reloader_)
189 script_reloader_->DisownMaster(); 201 script_reloader_->DisownMaster();
202
203 // TODO(aa): Enable this when DirectoryWatcher is implemented for linux and mac.
204 #if defined(OS_WIN)
205 STLDeleteElements(&dir_watchers_);
206 #endif
207 }
208
209 void UserScriptMaster::AddWatchedPath(const FilePath& path) {
210 // TODO(aa): Enable this when DirectoryWatcher is implemented for linux and mac.
211 #if defined(OS_WIN)
212 DirectoryWatcher* watcher = new DirectoryWatcher();
213 watcher->Watch(path, this);
214 dir_watchers_.push_back(watcher);
215 #endif
190 } 216 }
191 217
192 void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) { 218 void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) {
193 // Ensure handle is deleted or released. 219 // Ensure handle is deleted or released.
194 scoped_ptr<base::SharedMemory> handle_deleter(handle); 220 scoped_ptr<base::SharedMemory> handle_deleter(handle);
195 221
196 if (pending_scan_) { 222 if (pending_scan_) {
197 // While we were scanning, there were further changes. Don't bother 223 // While we were scanning, there were further changes. Don't bother
198 // notifying about these scripts and instead just immediately rescan. 224 // notifying about these scripts and instead just immediately rescan.
199 pending_scan_ = false; 225 pending_scan_ = false;
(...skipping 18 matching lines...) Expand all
218 return; 244 return;
219 } 245 }
220 246
221 StartScan(); 247 StartScan();
222 } 248 }
223 249
224 void UserScriptMaster::StartScan() { 250 void UserScriptMaster::StartScan() {
225 if (!script_reloader_) 251 if (!script_reloader_)
226 script_reloader_ = new ScriptReloader(this); 252 script_reloader_ = new ScriptReloader(this);
227 253
228 script_reloader_->StartScan(worker_loop_, *user_script_dir_); 254 script_reloader_->StartScan(worker_loop_, user_script_dir_, lone_scripts_);
229 } 255 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/user_script_master.h ('k') | chrome/browser/extensions/user_script_master_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698