diff options
Diffstat (limited to 'chrome/renderer/greasemonkey_slave.cc')
-rw-r--r-- | chrome/renderer/greasemonkey_slave.cc | 117 |
1 files changed, 109 insertions, 8 deletions
diff --git a/chrome/renderer/greasemonkey_slave.cc b/chrome/renderer/greasemonkey_slave.cc index cba48d1..5a4072a 100644 --- a/chrome/renderer/greasemonkey_slave.cc +++ b/chrome/renderer/greasemonkey_slave.cc @@ -7,7 +7,109 @@ #include "base/logging.h" #include "base/pickle.h" #include "base/shared_memory.h" +#include "googleurl/src/gurl.h" + +// GreasemonkeyScript + +void GreasemonkeyScript::Parse(const StringPiece& script_text) { + ParseMetadata(script_text); + + // TODO(aa): Set body to just the part after the metadata block? This would + // significantly cut down on the size of the injected script in some cases. + // Would require remembering the line number the body begins at, for correct + // error line number reporting. + body_ = script_text; +} + +bool GreasemonkeyScript::MatchesUrl(const GURL& url) { + for (std::vector<std::string>::iterator pattern = include_patterns_.begin(); + pattern != include_patterns_.end(); ++pattern) { + if (MatchPattern(url.spec(), *pattern)) { + return true; + } + } + + return false; +} + +void GreasemonkeyScript::ParseMetadata(const StringPiece& script_text) { + // http://wiki.greasespot.net/Metadata_block + StringPiece line; + size_t line_start = 0; + size_t line_end = 0; + bool in_metadata = false; + + static const StringPiece kUserScriptBegin("// ==UserScript=="); + static const StringPiece kUserScriptEng("// ==/UserScript=="); + static const StringPiece kIncludeDeclaration("// @include "); + + while (line_start < script_text.length()) { + line_end = script_text.find('\n', line_start); + + // Handle the case where there is no trailing newline in the file. + if (line_end == std::string::npos) { + line_end = script_text.length() - 1; + } + + line.set(script_text.data() + line_start, line_end - line_start); + + if (!in_metadata) { + if (line.starts_with(kUserScriptBegin)) { + in_metadata = true; + } + } else { + if (line.starts_with(kUserScriptEng)) { + break; + } + + if (line.starts_with(kIncludeDeclaration)) { + std::string pattern(line.data() + kIncludeDeclaration.length(), + line.length() - kIncludeDeclaration.length()); + std::string pattern_trimmed; + TrimWhitespace(pattern, TRIM_ALL, &pattern_trimmed); + AddInclude(pattern_trimmed); + } + + // TODO(aa): Handle more types of metadata. + } + + line_start = line_end + 1; + } + + // If no @include patterns were specified, default to @include *. + // This is what Greasemonkey for Firefox does. + if (include_patterns_.size() == 0) { + AddInclude("*"); + } +} + +void GreasemonkeyScript::AddInclude(const std::string &glob_pattern) { + include_patterns_.push_back(EscapeGlob(glob_pattern)); +} + +std::string GreasemonkeyScript::EscapeGlob(const std::string& input_pattern) { + std::string output_pattern; + + for (size_t i = 0; i < input_pattern.length(); ++i) { + switch (input_pattern[i]) { + // These characters have special meaning to the MatchPattern() function, + // so we escape them. + case '\\': + case '?': + output_pattern += '\\'; + // fall through + + default: + output_pattern += input_pattern[i]; + } + } + + return output_pattern; +} + + +// GreasemonkeySlave GreasemonkeySlave::GreasemonkeySlave() : shared_memory_(NULL) { } @@ -47,22 +149,21 @@ bool GreasemonkeySlave::UpdateScripts(SharedMemoryHandle shared_memory) { pickle.ReadData(&iter, &url, &url_length); pickle.ReadData(&iter, &body, &body_length); - GreasemonkeyScript script(StringPiece(url, url_length)); - if (script.Parse(StringPiece(body, body_length))) { - scripts_.push_back(script); - } + scripts_.push_back(GreasemonkeyScript(StringPiece(url, url_length))); + GreasemonkeyScript& script = scripts_.back(); + script.Parse(StringPiece(body, body_length)); } return true; } bool GreasemonkeySlave::InjectScripts(WebFrame* frame) { - // TODO(aa): Check script patterns here - for (std::vector<GreasemonkeyScript>::iterator script = scripts_.begin(); script != scripts_.end(); ++script) { - frame->ExecuteJavaScript(script->GetBody().as_string(), - script->GetURL().as_string()); + if (script->MatchesUrl(frame->GetURL())) { + frame->ExecuteJavaScript(script->GetBody().as_string(), + script->GetURL().as_string()); + } } return true; |