Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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/browser/guest_view/web_view/web_view_content_script_manager .h" | |
| 6 | |
| 7 #include "base/lazy_instance.h" | |
| 8 #include "base/memory/linked_ptr.h" | |
| 9 #include "content/public/browser/browser_context.h" | |
| 10 #include "content/public/browser/browser_thread.h" | |
| 11 #include "content/public/browser/navigation_details.h" | |
| 12 #include "content/public/browser/render_process_host.h" | |
| 13 #include "content/public/browser/web_contents.h" | |
| 14 #include "content/public/browser/web_contents_observer.h" | |
| 15 #include "extensions/browser/declarative_user_script_manager.h" | |
| 16 #include "extensions/browser/declarative_user_script_master.h" | |
| 17 #include "extensions/browser/extension_system.h" | |
| 18 #include "extensions/browser/guest_view/guest_view_manager.h" | |
| 19 #include "extensions/browser/guest_view/web_view/web_view_constants.h" | |
| 20 #include "extensions/browser/guest_view/web_view/web_view_guest.h" | |
| 21 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" | |
| 22 | |
| 23 using content::BrowserThread; | |
| 24 | |
| 25 namespace { | |
| 26 bool RemoveContentScriptsForGuest(content::BrowserContext* browser_context, | |
| 27 HostID host_id, | |
| 28 content::WebContents* embedder_web_contents, | |
| 29 content::WebContents* guest_web_contents) { | |
| 30 auto guest = extensions::WebViewGuest::FromWebContents(guest_web_contents); | |
| 31 if (!guest) | |
| 32 return false; | |
| 33 | |
| 34 extensions::WebViewContentScriptManager* manager = | |
| 35 extensions::WebViewContentScriptManager::Get(browser_context); | |
| 36 if (!manager) | |
| 37 return false; | |
| 38 | |
| 39 manager->RemoveContentScripts(embedder_web_contents, | |
| 40 guest->view_instance_id(), host_id, | |
| 41 std::vector<std::string>()); | |
| 42 return true; | |
|
Fady Samuel
2015/04/10 16:16:04
I think you should return false here too to allow
Xi Han
2015/04/10 18:27:07
Done.
| |
| 43 } | |
| 44 } | |
| 45 | |
| 46 namespace extensions { | |
| 47 | |
| 48 // This observer ensures that the content scripts added by the guest are removed | |
| 49 // when its embedder goes away. | |
| 50 class WebViewContentScriptManager::OwnerWebContentsObserver | |
| 51 : public content::WebContentsObserver { | |
| 52 public: | |
| 53 OwnerWebContentsObserver(content::WebContents* embedder_web_contents, | |
| 54 const HostID& host_id, | |
| 55 WebViewContentScriptManager* manager) | |
| 56 : WebContentsObserver(embedder_web_contents), | |
| 57 host_id_(host_id), | |
| 58 web_view_content_script_manager_(manager) {} | |
| 59 ~OwnerWebContentsObserver() override {} | |
| 60 | |
| 61 // WebContentsObserver: | |
| 62 void WebContentsDestroyed() override { | |
| 63 // If the embedder is destroyed then remove all the content scripts of the | |
| 64 // guest. | |
| 65 RemoveContentScripts(); | |
| 66 } | |
| 67 void DidNavigateMainFrame( | |
| 68 const content::LoadCommittedDetails& details, | |
| 69 const content::FrameNavigateParams& params) override { | |
| 70 // If the embedder navigates to a different page then destroy the guest. | |
| 71 if (details.is_navigation_to_different_page()) | |
| 72 RemoveContentScripts(); | |
| 73 } | |
| 74 void RenderProcessGone(base::TerminationStatus status) override { | |
| 75 // If the embedder crashes, then destroy the guest. | |
| 76 RemoveContentScripts(); | |
| 77 } | |
| 78 | |
| 79 private: | |
| 80 void RemoveContentScripts() { | |
| 81 web_view_content_script_manager_->RemoveContentScripts(web_contents(), | |
| 82 host_id_); | |
| 83 } | |
| 84 | |
| 85 HostID host_id_; | |
| 86 WebViewContentScriptManager* web_view_content_script_manager_; | |
| 87 | |
| 88 DISALLOW_COPY_AND_ASSIGN(OwnerWebContentsObserver); | |
| 89 }; | |
| 90 | |
| 91 WebViewContentScriptManager::WebViewContentScriptManager( | |
| 92 content::BrowserContext* browser_context) | |
| 93 : browser_context_(browser_context) { | |
| 94 } | |
| 95 | |
| 96 WebViewContentScriptManager::~WebViewContentScriptManager() { | |
| 97 } | |
| 98 | |
| 99 WebViewContentScriptManager* WebViewContentScriptManager::Get( | |
| 100 content::BrowserContext* browser_context) { | |
| 101 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 102 WebViewContentScriptManager* manager = | |
| 103 static_cast<WebViewContentScriptManager*>(browser_context->GetUserData( | |
| 104 webview::kWebViewContentScriptManagerKeyName)); | |
| 105 if (!manager) { | |
| 106 manager = new WebViewContentScriptManager(browser_context); | |
| 107 browser_context->SetUserData(webview::kWebViewContentScriptManagerKeyName, | |
| 108 manager); | |
| 109 } | |
| 110 return manager; | |
| 111 } | |
| 112 | |
| 113 void WebViewContentScriptManager::AddContentScripts( | |
| 114 content::WebContents* embedder_web_contents, | |
| 115 int view_instance_id, | |
| 116 const HostID& host_id, | |
| 117 const std::map<std::string, UserScript>& scripts) { | |
| 118 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 119 DCHECK(embedder_web_contents); | |
| 120 | |
| 121 DeclarativeUserScriptMaster* master = | |
| 122 ExtensionSystem::Get(browser_context_) | |
| 123 ->declarative_user_script_manager() | |
| 124 ->GetDeclarativeUserScriptMasterByID(host_id); | |
| 125 DCHECK(master); | |
| 126 | |
| 127 // We need to update WebViewRenderState in the IO thread if the guest exists. | |
| 128 std::set<int> ids_to_add; | |
| 129 | |
| 130 int embedder_process_id = | |
| 131 embedder_web_contents->GetRenderProcessHost()->GetID(); | |
| 132 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id); | |
| 133 GuestContentScriptMap::iterator iter = guest_content_script_map_.find(key); | |
| 134 | |
| 135 // Step 1: finds the entry in guest_content_script_map_ by the given |key|. | |
| 136 // If there isn't any content script added for the given guest yet, insert an | |
| 137 // empty map first. | |
| 138 if (iter == guest_content_script_map_.end()) { | |
| 139 iter = guest_content_script_map_.insert( | |
| 140 iter, std::pair<GuestMapKey, ContentScriptMap>( | |
| 141 key, std::map<std::string, UserScript>())); | |
| 142 } | |
| 143 | |
| 144 // Step 2: updates the guest_content_script_map_, and adds content scripts to | |
| 145 // the master. | |
| 146 ContentScriptMap& map = iter->second; | |
| 147 for (const std::pair<std::string, UserScript>& pair : scripts) { | |
| 148 auto map_iter = map.find(pair.first); | |
| 149 // If a content script has the same name as the new one, removes the old | |
| 150 // script first, and insert the new one. | |
| 151 if (map_iter != map.end()) { | |
| 152 master->RemoveScript(map_iter->second); | |
|
Devlin
2015/04/10 16:04:32
What happens when a WebUI has two webviews, and ad
Fady Samuel
2015/04/10 16:16:04
This API doesn't allow two webviews to share a con
Xi Han
2015/04/10 18:27:07
We will create two different user scripts for them
| |
| 153 map.erase(map_iter); | |
| 154 } | |
| 155 map.insert(pair); | |
| 156 ids_to_add.insert(pair.second.id()); | |
| 157 master->AddScript(pair.second); | |
| 158 } | |
| 159 | |
| 160 // Step 3: creates owner web contents observer for the given | |
| 161 // |embedder_web_contents| if it doesn't exist. | |
| 162 auto observers_map_iter = | |
| 163 owner_web_contents_observer_map_.find(embedder_web_contents); | |
| 164 if (observers_map_iter == owner_web_contents_observer_map_.end()) { | |
| 165 linked_ptr<OwnerWebContentsObserver> observer( | |
| 166 new OwnerWebContentsObserver(embedder_web_contents, host_id, this)); | |
| 167 owner_web_contents_observer_map_[embedder_web_contents] = observer; | |
| 168 } | |
| 169 | |
| 170 // Step 4: updates WebViewRenderState in the IO thread. | |
| 171 if (!ids_to_add.empty()) { | |
| 172 content::BrowserThread::PostTask( | |
| 173 content::BrowserThread::IO, FROM_HERE, | |
| 174 base::Bind(&WebViewRendererState::AddContentScriptIDs, | |
| 175 base::Unretained(WebViewRendererState::GetInstance()), | |
| 176 embedder_process_id, view_instance_id, ids_to_add)); | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 void WebViewContentScriptManager::RemoveContentScripts( | |
| 181 content::WebContents* embedder_web_contents, | |
| 182 int view_instance_id, | |
| 183 const HostID& host_id, | |
| 184 const std::vector<std::string>& script_name_list) { | |
| 185 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 186 | |
| 187 int embedder_process_id = | |
| 188 embedder_web_contents->GetRenderProcessHost()->GetID(); | |
| 189 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id); | |
| 190 GuestContentScriptMap::iterator script_map_iter = | |
| 191 guest_content_script_map_.find(key); | |
| 192 if (script_map_iter == guest_content_script_map_.end()) | |
| 193 return; | |
| 194 | |
| 195 DeclarativeUserScriptMaster* master = | |
| 196 ExtensionSystem::Get(browser_context_) | |
| 197 ->declarative_user_script_manager() | |
| 198 ->GetDeclarativeUserScriptMasterByID(host_id); | |
| 199 CHECK(master); | |
| 200 | |
| 201 // We need to update WebViewRenderState in the IO thread if the guest exists. | |
| 202 std::set<int> ids_to_delete; | |
| 203 | |
| 204 std::vector<std::string> names_to_delete; | |
| 205 | |
| 206 // Step 1: removed content scripts from |master| and updates | |
| 207 // |guest_content_script_map_| | |
| 208 std::map<std::string, UserScript>& map = script_map_iter->second; | |
| 209 // If the |script_name_list| is empty, all the content scripts added by the | |
| 210 // guest will be removed; otherwise, removes the scripts in the | |
| 211 // |script_name_list|. | |
| 212 if (script_name_list.empty()) { | |
| 213 for (const std::pair<std::string, UserScript>& iter : map) | |
| 214 names_to_delete.push_back(iter.first); | |
| 215 } else { | |
| 216 names_to_delete = script_name_list; | |
| 217 } | |
| 218 | |
| 219 for (const std::string& name : names_to_delete) { | |
| 220 ContentScriptMap::iterator iter = map.find(name); | |
| 221 if (iter == map.end()) | |
| 222 continue; | |
| 223 const UserScript& script = iter->second; | |
| 224 ids_to_delete.insert(script.id()); | |
| 225 master->RemoveScript(script); | |
| 226 map.erase(iter); | |
| 227 } | |
| 228 | |
| 229 // Step 2: Update WebViewRenderState in the IO thread. | |
| 230 if (!ids_to_delete.empty()) { | |
| 231 content::BrowserThread::PostTask( | |
| 232 content::BrowserThread::IO, FROM_HERE, | |
| 233 base::Bind(&WebViewRendererState::RemoveContentScriptIDs, | |
| 234 base::Unretained(WebViewRendererState::GetInstance()), | |
| 235 embedder_process_id, view_instance_id, ids_to_delete)); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 void WebViewContentScriptManager::RemoveContentScripts( | |
| 240 content::WebContents* embedder_web_contents, | |
| 241 const HostID& host_id) { | |
| 242 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 243 | |
| 244 // Step 1: removes content scripts of all the guests embedded. | |
| 245 auto guest_view_manager = | |
| 246 GuestViewManager::FromBrowserContext(browser_context_); | |
| 247 guest_view_manager->ForEachGuest( | |
| 248 embedder_web_contents, | |
| 249 base::Bind(&RemoveContentScriptsForGuest, browser_context_, host_id, | |
| 250 embedder_web_contents)); | |
| 251 | |
| 252 // Step 2: removes the observer of the given |embedder_web_contents|. | |
| 253 owner_web_contents_observer_map_.erase(embedder_web_contents); | |
| 254 } | |
| 255 | |
| 256 std::set<int> WebViewContentScriptManager::GetContentScriptIDSet( | |
| 257 int embedder_process_id, | |
| 258 int view_instance_id) { | |
| 259 std::set<int> ids; | |
| 260 | |
| 261 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id); | |
| 262 GuestContentScriptMap::const_iterator iter = | |
| 263 guest_content_script_map_.find(key); | |
| 264 if (iter == guest_content_script_map_.end()) | |
| 265 return ids; | |
| 266 const ContentScriptMap& map = iter->second; | |
| 267 for (const auto& pair : map) | |
| 268 ids.insert(pair.second.id()); | |
| 269 | |
| 270 return ids; | |
| 271 } | |
| 272 | |
| 273 } // namespace extensions | |
| OLD | NEW |