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.
5 #include "extensions/browser/web_ui_user_script_loader.h"
8 #include "base/strings/string_util.h"
9 #include "content/public/browser/browser_context.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h"
16 void SerializeOnFileThread(
17 scoped_ptr
<extensions::UserScriptList
> user_scripts
,
18 extensions::UserScriptLoader::LoadScriptsCallback callback
) {
19 scoped_ptr
<base::SharedMemory
> memory
=
20 extensions::UserScriptLoader::Serialize(*user_scripts
);
21 content::BrowserThread::PostTask(
22 content::BrowserThread::UI
, FROM_HERE
,
23 base::Bind(callback
, base::Passed(&user_scripts
), base::Passed(&memory
)));
28 struct WebUIUserScriptLoader::UserScriptRenderInfo
{
29 int render_process_id
;
32 UserScriptRenderInfo() : render_process_id(-1), render_view_id(-1) {}
34 UserScriptRenderInfo(int render_process_id
, int render_view_id
)
35 : render_process_id(render_process_id
), render_view_id(render_view_id
) {}
38 WebUIUserScriptLoader::WebUIUserScriptLoader(
39 content::BrowserContext
* browser_context
,
40 const HostID
& host_id
)
41 : UserScriptLoader(browser_context
, host_id
), complete_fetchers_(0) {
45 WebUIUserScriptLoader::~WebUIUserScriptLoader() {
48 void WebUIUserScriptLoader::AddScripts(
49 const std::set
<extensions::UserScript
>& scripts
,
50 int render_process_id
,
52 UserScriptRenderInfo
info(render_process_id
, render_view_id
);
53 for (const extensions::UserScript
& script
: scripts
) {
54 script_render_info_map_
.insert(
55 std::pair
<int, UserScriptRenderInfo
>(script
.id(), info
));
58 extensions::UserScriptLoader::AddScripts(scripts
);
61 void WebUIUserScriptLoader::LoadScripts(
62 scoped_ptr
<extensions::UserScriptList
> user_scripts
,
63 const std::set
<HostID
>& changed_hosts
,
64 const std::set
<int>& added_script_ids
,
65 LoadScriptsCallback callback
) {
66 user_scripts_cache_
.swap(user_scripts
);
67 scripts_loaded_callback_
= callback
;
69 // The total number of the tasks is used to trace whether all the fetches
70 // are complete. Therefore, we store all the fetcher pointers in |fetchers_|
71 // before we get theis number. Once we get the total number, start each
73 DCHECK_EQ(0u, complete_fetchers_
);
75 for (extensions::UserScript
& script
: *user_scripts_cache_
) {
76 if (added_script_ids
.count(script
.id()) == 0)
79 auto iter
= script_render_info_map_
.find(script
.id());
80 DCHECK(iter
!= script_render_info_map_
.end());
81 int render_process_id
= iter
->second
.render_process_id
;
82 int render_view_id
= iter
->second
.render_view_id
;
84 content::BrowserContext
* browser_context
=
85 content::RenderProcessHost::FromID(render_process_id
)
86 ->GetBrowserContext();
88 CreateWebUIURLFetchers(&script
.js_scripts(), browser_context
,
89 render_process_id
, render_view_id
);
90 CreateWebUIURLFetchers(&script
.css_scripts(), browser_context
,
91 render_process_id
, render_view_id
);
93 script_render_info_map_
.erase(script
.id());
96 // If no fetch is needed, call OnWebUIURLFetchComplete directly.
97 if (fetchers_
.empty()) {
98 OnWebUIURLFetchComplete();
101 for (auto fetcher
: fetchers_
)
105 void WebUIUserScriptLoader::CreateWebUIURLFetchers(
106 extensions::UserScript::FileList
* script_files
,
107 content::BrowserContext
* browser_context
,
108 int render_process_id
,
109 int render_view_id
) {
110 for (extensions::UserScript::File
& file
: *script_files
) {
111 if (file
.GetContent().empty()) {
112 // The WebUIUserScriptLoader owns these WebUIURLFetchers. Once the
113 // loader is destroyed, all the fetchers will be destroyed. Therefore,
114 // we are sure it is safe to use base::Unretained(this) here.
115 scoped_ptr
<WebUIURLFetcher
> fetcher(new WebUIURLFetcher(
116 browser_context
, render_process_id
, render_view_id
, file
.url(),
117 base::Bind(&WebUIUserScriptLoader::OnSingleWebUIURLFetchComplete
,
118 base::Unretained(this), &file
)));
119 fetchers_
.push_back(fetcher
.Pass());
124 void WebUIUserScriptLoader::OnSingleWebUIURLFetchComplete(
125 extensions::UserScript::File
* script_file
,
127 const std::string
& data
) {
129 // Remove BOM from the content.
130 std::string::size_type index
= data
.find(base::kUtf8ByteOrderMark
);
132 script_file
->set_content(data
.substr(strlen(base::kUtf8ByteOrderMark
)));
134 script_file
->set_content(data
);
137 ++complete_fetchers_
;
138 if (complete_fetchers_
== fetchers_
.size()) {
139 complete_fetchers_
= 0;
140 OnWebUIURLFetchComplete();
145 void WebUIUserScriptLoader::OnWebUIURLFetchComplete() {
146 content::BrowserThread::PostTask(
147 content::BrowserThread::FILE, FROM_HERE
,
148 base::Bind(&SerializeOnFileThread
, base::Passed(&user_scripts_cache_
),
149 scripts_loaded_callback_
));
150 scripts_loaded_callback_
.Reset();