Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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/renderer/user_script_injection_list.h" | |
| 6 | |
| 7 #include "content/public/common/url_constants.h" | |
| 8 #include "content/public/renderer/render_thread.h" | |
| 9 #include "extensions/common/extension.h" | |
| 10 #include "extensions/common/extension_messages.h" | |
| 11 #include "extensions/common/extension_set.h" | |
| 12 #include "extensions/common/permissions/permissions_data.h" | |
| 13 #include "extensions/renderer/extensions_renderer_client.h" | |
| 14 #include "extensions/renderer/script_context.h" | |
| 15 #include "extensions/renderer/user_script_injection.h" | |
| 16 #include "third_party/WebKit/public/web/WebDocument.h" | |
| 17 #include "third_party/WebKit/public/web/WebFrame.h" | |
| 18 #include "url/gurl.h" | |
| 19 | |
| 20 namespace extensions { | |
| 21 | |
| 22 // static | |
| 23 GURL UserScriptInjectionList::GetDocumentUrlForFrame(blink::WebFrame* frame) { | |
| 24 GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame); | |
| 25 if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) { | |
| 26 data_source_url = GURL(content::kViewSourceScheme + std::string(":") + | |
| 27 data_source_url.spec()); | |
| 28 } | |
| 29 | |
| 30 return data_source_url; | |
| 31 } | |
| 32 | |
| 33 UserScriptInjectionList::UserScriptInjectionList() { | |
| 34 content::RenderThread::Get()->AddObserver(this); | |
| 35 } | |
| 36 | |
| 37 UserScriptInjectionList::~UserScriptInjectionList() { | |
| 38 } | |
| 39 | |
| 40 void UserScriptInjectionList::AddObserver(Observer* observer) { | |
| 41 observers_.AddObserver(observer); | |
| 42 } | |
| 43 | |
| 44 void UserScriptInjectionList::RemoveObserver(Observer* observer) { | |
| 45 observers_.RemoveObserver(observer); | |
| 46 } | |
| 47 | |
| 48 void UserScriptInjectionList::GetActiveExtensionIds( | |
| 49 std::set<std::string>* ids) const { | |
| 50 for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin(); | |
| 51 iter != scripts_.end(); | |
| 52 ++iter) { | |
| 53 DCHECK(!(*iter)->extension_id().empty()); | |
| 54 ids->insert((*iter)->extension_id()); | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 void UserScriptInjectionList::GetInjections( | |
| 59 ScopedVector<ScriptInjection>* injections, | |
| 60 blink::WebFrame* web_frame, | |
| 61 int tab_id, | |
| 62 UserScript::RunLocation run_location, | |
| 63 const GURL& document_url, | |
| 64 const ExtensionSet* extensions) { | |
| 65 for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin(); | |
| 66 iter != scripts_.end(); | |
| 67 ++iter) { | |
| 68 const Extension* extension = extensions->GetByID((*iter)->extension_id()); | |
| 69 if (!extension) | |
| 70 continue; | |
| 71 scoped_ptr<ScriptInjection> injection = GetInjectionForScript( | |
| 72 *iter, web_frame, tab_id, run_location, document_url, extension); | |
| 73 if (injection.get()) | |
| 74 injections->push_back(injection.release()); | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 bool UserScriptInjectionList::OnControlMessageReceived( | |
| 79 const IPC::Message& message) { | |
| 80 bool handled = true; | |
| 81 IPC_BEGIN_MESSAGE_MAP(UserScriptInjectionList, message) | |
| 82 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts) | |
| 83 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 84 IPC_END_MESSAGE_MAP() | |
| 85 return handled; | |
| 86 } | |
| 87 | |
| 88 void UserScriptInjectionList::OnUpdateUserScripts( | |
| 89 base::SharedMemoryHandle shared_memory, | |
| 90 const std::set<std::string>& changed_extensions) { | |
| 91 if (!base::SharedMemory::IsHandleValid(shared_memory)) { | |
| 92 NOTREACHED() << "Bad scripts handle"; | |
| 93 return; | |
| 94 } | |
| 95 | |
| 96 for (std::set<std::string>::const_iterator iter = changed_extensions.begin(); | |
| 97 iter != changed_extensions.end(); | |
| 98 ++iter) { | |
| 99 if (!Extension::IdIsValid(*iter)) { | |
| 100 NOTREACHED() << "Invalid extension id: " << *iter; | |
| 101 return; | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 if (UpdateScripts(shared_memory)) { | |
| 106 FOR_EACH_OBSERVER(Observer, | |
| 107 observers_, | |
| 108 OnUserScriptsUpdated(changed_extensions, scripts_.get())); | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 bool UserScriptInjectionList::UpdateScripts( | |
| 113 base::SharedMemoryHandle shared_memory) { | |
| 114 bool only_inject_incognito = | |
| 115 ExtensionsRendererClient::Get()->IsIncognitoProcess(); | |
| 116 | |
| 117 // Create the shared memory object (read only). | |
| 118 shared_memory_.reset(new base::SharedMemory(shared_memory, true)); | |
| 119 if (!shared_memory_.get()) | |
| 120 return false; | |
| 121 | |
| 122 // First get the size of the memory block. | |
| 123 if (!shared_memory_->Map(sizeof(Pickle::Header))) | |
| 124 return false; | |
| 125 Pickle::Header* pickle_header = | |
| 126 reinterpret_cast<Pickle::Header*>(shared_memory_->memory()); | |
| 127 | |
| 128 // Now map in the rest of the block. | |
| 129 int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size; | |
| 130 shared_memory_->Unmap(); | |
| 131 if (!shared_memory_->Map(pickle_size)) | |
| 132 return false; | |
| 133 | |
| 134 // Unpickle scripts. | |
| 135 uint64 num_scripts = 0; | |
| 136 Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size); | |
| 137 PickleIterator iter(pickle); | |
| 138 CHECK(pickle.ReadUInt64(&iter, &num_scripts)); | |
| 139 | |
| 140 scripts_.clear(); | |
| 141 scripts_.reserve(num_scripts); | |
| 142 for (uint64 i = 0; i < num_scripts; ++i) { | |
| 143 scoped_ptr<UserScript> script(new UserScript()); | |
| 144 script->Unpickle(pickle, &iter); | |
| 145 | |
| 146 // Note that this is a pointer into shared memory. We don't own it. It gets | |
| 147 // cleared up when the last renderer or browser process drops their | |
| 148 // reference to the shared memory. | |
| 149 for (size_t j = 0; j < script->js_scripts().size(); ++j) { | |
| 150 const char* body = NULL; | |
| 151 int body_length = 0; | |
| 152 CHECK(pickle.ReadData(&iter, &body, &body_length)); | |
| 153 script->js_scripts()[j].set_external_content( | |
| 154 base::StringPiece(body, body_length)); | |
| 155 } | |
| 156 for (size_t j = 0; j < script->css_scripts().size(); ++j) { | |
| 157 const char* body = NULL; | |
| 158 int body_length = 0; | |
| 159 CHECK(pickle.ReadData(&iter, &body, &body_length)); | |
| 160 script->css_scripts()[j].set_external_content( | |
| 161 base::StringPiece(body, body_length)); | |
| 162 } | |
| 163 | |
| 164 if (only_inject_incognito && !script->is_incognito_enabled()) | |
| 165 continue; // This script shouldn't run in an incognito tab. | |
| 166 | |
| 167 scripts_.push_back(script.release()); | |
| 168 } | |
| 169 | |
| 170 return true; | |
| 171 } | |
|
not at google - send to devlin
2014/06/15 23:53:38
blank line
Devlin
2014/06/16 18:11:17
Done.
| |
| 172 scoped_ptr<ScriptInjection> UserScriptInjectionList::GetInjectionForScript( | |
| 173 UserScript* script, | |
| 174 blink::WebFrame* web_frame, | |
| 175 int tab_id, | |
| 176 UserScript::RunLocation run_location, | |
| 177 const GURL& document_url, | |
| 178 const Extension* extension) { | |
| 179 scoped_ptr<ScriptInjection> injection; | |
| 180 if (web_frame->parent() && !script->match_all_frames()) | |
| 181 return injection.Pass(); // Only match subframes if the script declared it. | |
| 182 | |
| 183 // Content scripts are not tab-specific. | |
| 184 static const int kNoTabId = -1; | |
| 185 // We don't have a process id in this context. | |
| 186 static const int kNoProcessId = -1; | |
| 187 | |
| 188 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( | |
| 189 web_frame, document_url, script->match_about_blank()); | |
| 190 | |
| 191 if (!script->MatchesURL(effective_document_url)) | |
| 192 return injection.Pass(); | |
| 193 | |
| 194 if (!extension->permissions_data()->CanRunContentScriptOnPage( | |
| 195 extension, | |
| 196 effective_document_url, | |
| 197 web_frame->top()->document().url(), | |
| 198 kNoTabId, | |
| 199 kNoProcessId, | |
|
not at google - send to devlin
2014/06/15 23:53:38
inling -1 with those comments "Content scripts are
Devlin
2014/06/16 18:11:17
Done.
| |
| 200 NULL /* ignore error */)) { | |
| 201 return injection.Pass(); | |
| 202 } | |
| 203 | |
| 204 bool inject_css = !script->css_scripts().empty() && | |
| 205 run_location == UserScript::DOCUMENT_START; | |
| 206 bool inject_js = | |
| 207 !script->js_scripts().empty() && script->run_location() == run_location; | |
|
not at google - send to devlin
2014/06/15 23:53:38
this mixing of UserScriptInjection getting its pro
Devlin
2014/06/16 18:11:17
Caching script id is done because when we need to
| |
| 208 if (inject_css || inject_js) { | |
| 209 injection.reset(new UserScriptInjection(web_frame, | |
| 210 extension->id(), | |
| 211 run_location, | |
| 212 tab_id, | |
| 213 this, | |
| 214 script, | |
| 215 inject_js, | |
| 216 inject_css)); | |
| 217 } | |
| 218 return injection.Pass(); | |
| 219 } | |
| 220 | |
| 221 } // namespace extensions | |
| OLD | NEW |