1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/user_script_slave.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/perftimer.h"
#include "base/pickle.h"
#include "base/shared_memory.h"
#include "chrome/common/resource_bundle.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/webframe.h"
#include "grit/renderer_resources.h"
// These two strings are injected before and after the Greasemonkey API and
// user script to wrap it in an anonymous scope.
static const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
static const char kUserScriptTail[] = "\n})(window);";
UserScriptSlave::UserScriptSlave()
: shared_memory_(NULL),
script_deleter_(&scripts_),
user_script_start_line_(0) {
// TODO: Only windows supports resources and only windows supports user
// scrips, so only load the Greasemonkey API on windows. Fix this when
// better cross platofrm support is available.
#if defined(OS_WIN)
api_js_ = ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_GREASEMONKEY_API_JS);
#endif
// Count the number of lines that will be injected before the user script.
StringPiece::size_type pos = 0;
while ((pos = api_js_.find('\n', pos)) != StringPiece::npos) {
user_script_start_line_++;
pos++;
}
// NOTE: There is actually one extra line in the injected script because the
// function header includes a newline as well. But WebKit expects the
// numbering to be one-based, not zero-based, so actually *not* accounting for
// this extra line ends us up with the right offset.
}
bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
scripts_.clear();
script_contents_.clear();
// Create the shared memory object (read only).
shared_memory_.reset(new base::SharedMemory(shared_memory, true));
if (!shared_memory_.get())
return false;
// First get the size of the memory block.
if (!shared_memory_->Map(sizeof(Pickle::Header)))
return false;
Pickle::Header* pickle_header =
reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
// Now map in the rest of the block.
int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
shared_memory_->Unmap();
if (!shared_memory_->Map(pickle_size))
return false;
// Unpickle scripts.
void* iter = NULL;
size_t num_scripts = 0;
Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()),
pickle_size);
pickle.ReadSize(&iter, &num_scripts);
for (size_t i = 0; i < num_scripts; ++i) {
UserScript* script = new UserScript();
script->Unpickle(pickle, &iter);
// Note that this is a pointer into shared memory. We don't own it. It gets
// cleared up when the last renderer or browser process drops their
// reference to the shared memory.
const char* body = NULL;
int body_length = 0;
CHECK(pickle.ReadData(&iter, &body, &body_length));
scripts_.push_back(script);
script_contents_[script] = StringPiece(body, body_length);
}
return true;
}
bool UserScriptSlave::InjectScripts(WebFrame* frame,
UserScript::RunLocation location) {
PerfTimer timer;
int num_matched = 0;
for (std::vector<UserScript*>::iterator script = scripts_.begin();
script != scripts_.end(); ++script) {
if ((*script)->MatchesUrl(frame->GetURL()) &&
(*script)->run_location() == location) {
std::string inject(kUserScriptHead);
inject.append(api_js_.as_string());
inject.append(script_contents_[*script].as_string());
inject.append(kUserScriptTail);
frame->ExecuteJavaScript(inject,
GURL((*script)->url().spec()),
-user_script_start_line_);
++num_matched;
}
}
if (location == UserScript::DOCUMENT_START) {
HISTOGRAM_COUNTS_100("UserScripts:DocStart:Count", num_matched);
HISTOGRAM_TIMES("UserScripts:DocStart:Time", timer.Elapsed());
} else {
HISTOGRAM_COUNTS_100("UserScripts:DocEnd:Count", num_matched);
HISTOGRAM_TIMES("UserScripts:DocEnd:Time", timer.Elapsed());
}
LOG(INFO) << "Injected " << num_matched << " scripts into " <<
frame->GetURL().spec();
return true;
}
|