Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: content/browser/loader/loader_io_thread_notifier.cc

Issue 2180933002: Add experimental code behind a flag for Content Size Policy (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase on dependent PS Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/loader/loader_io_thread_notifier.h" 5 #include "content/browser/loader/loader_io_thread_notifier.h"
6 6
7 #include "content/browser/frame_host/render_frame_host_impl.h" 7 #include "content/browser/frame_host/render_frame_host_impl.h"
8 #include "content/browser/loader/global_routing_id.h" 8 #include "content/browser/loader/content_size_resource_handler.h"
9 #include "content/browser/loader/resource_dispatcher_host_impl.h" 9 #include "content/browser/loader/resource_dispatcher_host_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigation_handle.h"
13 #include "content/public/common/content_switches.h"
14 #include "url/origin.h"
11 15
12 namespace content { 16 namespace content {
13 17
14 namespace { 18 namespace {
15 19
16 void NotifyRenderFrameDeletedOnIO(const GlobalFrameRoutingId& id) { 20 void NotifyRenderFrameDeletedOnIO(const GlobalFrameRoutingId& id) {
17 ResourceDispatcherHostImpl* rdhi = ResourceDispatcherHostImpl::Get(); 21 ResourceDispatcherHostImpl* rdhi = ResourceDispatcherHostImpl::Get();
18 if (rdhi) 22 if (rdhi)
19 rdhi->OnRenderFrameDeleted(id); 23 rdhi->OnRenderFrameDeleted(id);
20 } 24 }
21 25
26 class ContentSizeNavigationThrottle : public NavigationThrottle {
27 public:
28 ContentSizeNavigationThrottle(NavigationHandle* handle,
29 LoaderIOThreadNotifier* notifier)
30 : NavigationThrottle(handle), notifier_(notifier) {}
31 ~ContentSizeNavigationThrottle() override {}
32
33 // NavigationThrottle:
34 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
35 return notifier_->WillProcessNavigationResponse(navigation_handle());
36 }
37
38 private:
39 LoaderIOThreadNotifier* notifier_;
40
41 DISALLOW_COPY_AND_ASSIGN(ContentSizeNavigationThrottle);
42 };
43
22 } // namespace 44 } // namespace
23 45
24 LoaderIOThreadNotifier::LoaderIOThreadNotifier(WebContents* web_contents) 46 LoaderIOThreadNotifier::LoaderIOThreadNotifier(WebContents* web_contents)
25 : WebContentsObserver(web_contents) {} 47 : WebContentsObserver(web_contents) {}
26 48
27 LoaderIOThreadNotifier::~LoaderIOThreadNotifier() {} 49 LoaderIOThreadNotifier::~LoaderIOThreadNotifier() {}
28 50
29 void LoaderIOThreadNotifier::RenderFrameDeleted( 51 void LoaderIOThreadNotifier::RenderFrameDeleted(
30 RenderFrameHost* render_frame_host) { 52 RenderFrameHost* render_frame_host) {
31 BrowserThread::PostTask( 53 BrowserThread::PostTask(
32 BrowserThread::IO, FROM_HERE, 54 BrowserThread::IO, FROM_HERE,
33 base::Bind(&NotifyRenderFrameDeletedOnIO, 55 base::Bind(&NotifyRenderFrameDeletedOnIO,
34 static_cast<RenderFrameHostImpl*>(render_frame_host) 56 static_cast<RenderFrameHostImpl*>(render_frame_host)
35 ->GetGlobalFrameRoutingId())); 57 ->GetGlobalFrameRoutingId()));
36 } 58 }
37 59
60 // static
61 NavigationThrottle* LoaderIOThreadNotifier::MaybeCreateThrottle(
62 NavigationHandle* handle) {
63 if (handle->IsInMainFrame())
mmenke 2016/08/02 18:02:11 A main frame navigation is a navigation "in" a mai
Charlie Harrison 2016/08/02 18:35:36 Right. Now that you mention it, this is confusingl
64 return nullptr;
65 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
66 switches::kContentSizePolicy)) {
67 return nullptr;
68 }
69
70 LoaderIOThreadNotifier* notifier =
71 static_cast<WebContentsImpl*>(handle->GetWebContents())
72 ->loader_io_thread_notifier();
73 return new ContentSizeNavigationThrottle(handle, notifier);
74 }
75
76 // TODO(csharrison): This should be moved to ReadyToCommitNavigation once that
77 // is available. This callback is incorrect for transfer navigations.
78 NavigationThrottle::ThrottleCheckResult
79 LoaderIOThreadNotifier::WillProcessNavigationResponse(
80 NavigationHandle* navigation_handle) {
mmenke 2016/08/02 18:02:11 Do we really need a NavigationThrottle for this?
Charlie Harrison 2016/08/02 18:35:36 So, actually I think I will remove the throttle. I
81 const GURL& url = navigation_handle->GetURL();
82 // Only consider http/s or about:blank urls for blocking.
mmenke 2016/08/02 18:02:11 Why do we care about about:blank? Is there a spec
Charlie Harrison 2016/08/02 18:35:36 No spec yet :( The only reason I added about:blan
83 if (!url.SchemeIsHTTPOrHTTPS() &&
84 url.spec().compare(url::kAboutBlankURL) != 0) {
85 return NavigationThrottle::PROCEED;
86 }
87
88 if (web_contents()->GetLastCommittedURL().SchemeIs("chrome"))
89 return NavigationThrottle::PROCEED;
90
91 // TODO(csharrison): Navigations to about:blank are not counted as
92 // same-origin.
93 if (url::Origin(web_contents()->GetLastCommittedURL())
94 .IsSameOriginWith(url::Origin(url))) {
95 return NavigationThrottle::PROCEED;
96 }
97
98 std::string policy_string =
99 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
100 switches::kContentSizePolicy);
mmenke 2016/08/05 17:18:17 Why are we getting this as a command line string..
Charlie Harrison 2016/08/08 14:04:38 Yes. We wanted to land an experiment that just app
101 int content_size = 0;
102 base::StringToInt(policy_string, &content_size);
mmenke 2016/08/05 17:16:27 Should we be using int64_t here, or even uint64_t?
mmenke 2016/08/05 17:18:17 Oh, and I don't think anyone will be setting a lim
Charlie Harrison 2016/08/08 14:04:38 Yeah why not. Changing it to uint64_t sgtm. I had
103
104 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
105 navigation_handle->GetRenderFrameHost());
106 FrameSize* frame_size = AddNewFrame(rfh->frame_tree_node(), content_size);
107 if (frame_size->content_left < INT_MAX) {
108 BrowserThread::PostTask(
109 BrowserThread::IO, FROM_HERE,
110 base::Bind(&LoaderIOThreadNotifier::NotifyFrameHasLimit,
111 rfh->GetGlobalFrameRoutingId(), frame_size->content_left));
112 }
113 return frame_size->content_left <= 0 ? NavigationThrottle::CANCEL
114 : NavigationThrottle::PROCEED;
115 }
116
117 void LoaderIOThreadNotifier::RenderFrameCreated(
118 RenderFrameHost* render_frame_host) {
mmenke 2016/08/05 17:16:27 This doesn't do anything.
Charlie Harrison 2016/08/08 14:04:38 Sorry about that. Removed.
119 }
120
121 // static
122 // This method iterates through all LoaderIOThreadNotifiers, and calls
123 // UpdateDataAccounting on them with updates from the IO thread.
124 void LoaderIOThreadNotifier::UpdateGlobalDataAccounting(
125 std::unique_ptr<std::map<GlobalFrameRoutingId, int>> updates) {
126 DCHECK_CURRENTLY_ON(BrowserThread::UI);
127 DCHECK(updates);
128 std::map<LoaderIOThreadNotifier*, std::map<GlobalFrameRoutingId, int>>
129 per_notifier_map;
130 for (const auto& it : *updates) {
131 RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(
132 it.first.child_id, it.first.frame_routing_id);
133 WebContents* contents = WebContents::FromRenderFrameHost(rfh);
mmenke 2016/08/02 18:02:11 By creating and killing iframes, and then re-reque
Charlie Harrison 2016/08/02 18:35:37 No, because we count bytes for resources loaded fr
134 if (!contents)
135 continue;
136 LoaderIOThreadNotifier* notifier =
137 static_cast<WebContentsImpl*>(contents)->loader_io_thread_notifier();
138 per_notifier_map[notifier][it.first] = it.second;
mmenke 2016/08/02 18:02:11 +=? We can have multiple notifications for the sa
Charlie Harrison 2016/08/02 18:35:37 Acknowledged. Think you're right.
Charlie Harrison 2016/08/08 14:04:39 Done.
139 }
140 for (const auto& it : per_notifier_map) {
141 it.first->UpdateDataAccounting(it.second);
142 }
143 }
144
145 LoaderIOThreadNotifier::FrameSize* LoaderIOThreadNotifier::AddNewFrame(
146 FrameTreeNode* node,
147 int limit) {
148 FrameSize* frame_size = GetEffectiveLimit(node);
149 // No need to add this to the map if a parent frame has a lower limit.
150 if (!frame_size || frame_size->content_left > limit) {
151 FrameSize* size = &frame_tree_node_sizes_[node->frame_tree_node_id()];
mmenke 2016/08/02 18:02:11 Half this code uses frame_tree_node_ids, half uses
Charlie Harrison 2016/08/02 18:35:37 *sigh* that's one of the complications here. fram
152 size->content_limit = limit;
153 size->content_left = limit;
154 return size;
155 }
156 return frame_size;
157 }
158
159 // This method walks the frame tree and returns the FrameSize of the frame with
160 // the lowest limit. This is the effective bytes limit of |node|.
161 LoaderIOThreadNotifier::FrameSize*
162 LoaderIOThreadNotifier::GetEffectiveLimit(FrameTreeNode* node) {
163 FrameSize* frame_size = nullptr;
164 FrameTreeNode* current_node = node;
165 while (current_node) {
166 std::map<int, FrameSize>::iterator size_it =
167 frame_tree_node_sizes_.find(current_node->frame_tree_node_id());
168 if (size_it != frame_tree_node_sizes_.end() &&
169 (!frame_size ||
170 size_it->second.content_left < frame_size->content_left)) {
171 frame_size = &size_it->second;
172 }
173 current_node = current_node->parent();
174 }
175 return frame_size;
176 }
177
178 void LoaderIOThreadNotifier::UpdateDataAccounting(
179 std::map<GlobalFrameRoutingId, int> updates) {
180 std::unique_ptr<std::set<GlobalFrameRoutingId>> frames_over_limit(
181 new std::set<GlobalFrameRoutingId>);
182 for (const auto& it : updates) {
183 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
184 RenderFrameHost::FromID(it.first.child_id, it.first.frame_routing_id));
185 FrameSize* frame_size = GetEffectiveLimit(rfh->frame_tree_node());
186 DCHECK(frame_size);
187 frame_size->content_left -= it.second;
mmenke 2016/08/02 18:02:12 This should update the content_left value of all f
Charlie Harrison 2016/08/02 18:35:36 I think you mixed up B and C in your example, but
Charlie Harrison 2016/08/08 14:04:39 Done.
188 if (frame_size->content_left <= 0)
189 frames_over_limit->insert(it.first);
190 }
191 if (!frames_over_limit->empty()) {
192 BrowserThread::PostTask(
193 BrowserThread::IO, FROM_HERE,
194 base::Bind(&LoaderIOThreadNotifier::NotifyFramesWentOverSizeLimits,
195 base::Passed(std::move(frames_over_limit))));
196 }
197 }
198
199 // static
200 void LoaderIOThreadNotifier::NotifyFramesWentOverSizeLimits(
201 std::unique_ptr<std::set<GlobalFrameRoutingId>> frames) {
202 DCHECK_CURRENTLY_ON(BrowserThread::IO);
203 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
204 if (rdh && rdh->content_size_manager()) {
205 rdh->content_size_manager()->FramesWentOverSizeLimits(std::move(frames));
206 }
207 }
208
209 // static
210 void LoaderIOThreadNotifier::NotifyFrameHasLimit(
211 const GlobalFrameRoutingId& frame,
212 int limit) {
213 DCHECK_CURRENTLY_ON(BrowserThread::IO);
214 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
215 if (rdh && rdh->content_size_manager()) {
216 rdh->content_size_manager()->FrameHasSizeLimit(frame, limit);
217 }
218 }
219
38 } // namespace content 220 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698