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

Side by Side Diff: content/browser/loader/content_size_frame_counter.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: while -> for 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/loader/content_size_frame_counter.h"
6
7 #include "content/browser/frame_host/frame_tree.h"
8 #include "content/browser/frame_host/render_frame_host_impl.h"
9 #include "content/browser/loader/content_size_resource_handler_manager.h"
10 #include "content/browser/loader/resource_dispatcher_host_impl.h"
11 #include "content/browser/web_contents/web_contents_impl.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/navigation_handle.h"
14 #include "content/public/common/content_switches.h"
15 #include "url/origin.h"
16
17 namespace content {
18
19 ContentSizeFrameCounter::ContentSizeFrameCounter(WebContents* web_contents)
20 : WebContentsObserver(web_contents) {}
21
22 ContentSizeFrameCounter::~ContentSizeFrameCounter() {}
23
24 // TODO(csharrison): This code really wants to be in
25 // WebContentsObserver::ReadyToCommitNavigation, which is not available yet.
26 // Note: this code is all experimental. In the final version, the render process
27 // will notify this component that a given frame should have its data counted.
28 // This will likely be in a mojo interface callback. For now, count all
29 // cross-origin frames as having a data limit set by a command line flag.
30 void ContentSizeFrameCounter::DidFinishNavigation(
31 NavigationHandle* navigation_handle) {
32 if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage())
33 return;
34 const GURL& url = navigation_handle->GetURL();
35 // Only consider http/s or about:blank urls for blocking.
36 if (!url.SchemeIsHTTPOrHTTPS() &&
37 url.spec().compare(url::kAboutBlankURL) != 0) {
38 return;
39 }
40
41 if (web_contents()->GetLastCommittedURL().SchemeIs("chrome"))
42 return;
43
44 // TODO(csharrison): Navigations to about:blank are not counted as
45 // same-origin.
46 if (url::Origin(web_contents()->GetLastCommittedURL())
47 .IsSameOriginWith(url::Origin(url))) {
48 return;
49 }
50
51 std::string policy_string =
52 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
53 switches::kContentSizePolicy);
54 uint64_t content_size = 0;
55 base::StringToUint64(policy_string, &content_size);
56
57 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
58 navigation_handle->GetRenderFrameHost());
59 FrameSize* frame_size = AddNewFrame(rfh->frame_tree_node(), content_size);
60 if (frame_size->content_left < INT_MAX) {
61 BrowserThread::PostTask(
62 BrowserThread::IO, FROM_HERE,
63 base::Bind(&ContentSizeFrameCounter::NotifyFrameHasLimit,
64 rfh->GetGlobalFrameRoutingId(), frame_size->content_left));
65 }
66 }
67
68 // static
69 // This method iterates through all ContentSizeFrameCounters, and calls
70 // UpdateDataAccounting on them with updates from the IO thread.
71 void ContentSizeFrameCounter::UpdateGlobalDataAccounting(
72 std::unique_ptr<std::map<GlobalFrameRoutingId, uint64_t>> updates) {
73 DCHECK_CURRENTLY_ON(BrowserThread::UI);
74 DCHECK(updates);
75 std::map<ContentSizeFrameCounter*, std::map<GlobalFrameRoutingId, uint64_t>>
76 per_notifier_map;
77 for (const auto& it : *updates) {
78 RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(
79 it.first.child_id, it.first.frame_routing_id);
80 WebContents* contents = WebContents::FromRenderFrameHost(rfh);
81 if (!contents)
82 continue;
83 ContentSizeFrameCounter* notifier =
84 static_cast<WebContentsImpl*>(contents)->content_size_frame_counter();
85 per_notifier_map[notifier][it.first] += it.second;
86 }
87 for (const auto& it : per_notifier_map) {
88 it.first->UpdateDataAccounting(it.second);
89 }
90 }
91
92 ContentSizeFrameCounter::FrameSize* ContentSizeFrameCounter::AddNewFrame(
93 FrameTreeNode* node,
94 uint64_t limit) {
95 FrameSize* min_parent_frame_size = nullptr;
96 for (FrameTreeNode* current_node = node->parent(); current_node != nullptr;
97 current_node = current_node->parent()) {
98 std::map<int, FrameSize>::iterator size_it =
99 frame_tree_node_sizes_.find(current_node->frame_tree_node_id());
100 if (size_it != frame_tree_node_sizes_.end() &&
101 (!min_parent_frame_size ||
102 size_it->second.content_left < min_parent_frame_size->content_left)) {
103 min_parent_frame_size = &size_it->second;
104 }
105 }
106
107 // No need to add this to the map if a parent frame has a lower limit.
108 if (min_parent_frame_size && min_parent_frame_size->content_left <= limit)
109 return min_parent_frame_size;
110 FrameSize* size = &frame_tree_node_sizes_[node->frame_tree_node_id()];
111 size->content_left = limit;
112 return size;
113 }
114
115 void ContentSizeFrameCounter::ApplyUpdateToTree(
116 FrameTreeNode* node,
117 uint64_t bytes_downloaded,
118 std::set<GlobalFrameRoutingId>* routing_ids_to_block) {
119 FrameTreeNode* highest_node_to_block = nullptr;
120 for (FrameTreeNode* current_node = node; current_node != nullptr;
121 current_node = current_node->parent()) {
122 std::map<int, FrameSize>::iterator size_it =
123 frame_tree_node_sizes_.find(current_node->frame_tree_node_id());
124 if (size_it == frame_tree_node_sizes_.end())
125 continue;
126
127 if (size_it->second.content_left < bytes_downloaded) {
128 size_it->second.content_left = 0;
129 highest_node_to_block = node;
130 } else {
131 size_it->second.content_left -= bytes_downloaded;
132 }
133 }
134
135 // No frame went over the size limit.
136 if (!highest_node_to_block)
137 return;
138
139 // Collect all the routing ids to block in the subtree defined by
140 // |highest_node_to_block|.
141 for (FrameTreeNode* ftn : highest_node_to_block->frame_tree()->SubtreeNodes(
142 highest_node_to_block)) {
143 routing_ids_to_block->insert(
144 ftn->current_frame_host()->GetGlobalFrameRoutingId());
145 }
146 }
147
148 void ContentSizeFrameCounter::UpdateDataAccounting(
149 std::map<GlobalFrameRoutingId, uint64_t> updates) {
150 std::unique_ptr<std::set<GlobalFrameRoutingId>> frames_over_limit(
151 new std::set<GlobalFrameRoutingId>);
152 for (const auto& it : updates) {
153 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
154 RenderFrameHost::FromID(it.first.child_id, it.first.frame_routing_id));
155 if (!rfh)
156 continue;
157 ApplyUpdateToTree(rfh->frame_tree_node(), it.second,
158 frames_over_limit.get());
159 }
160 if (!frames_over_limit->empty()) {
161 BrowserThread::PostTask(
162 BrowserThread::IO, FROM_HERE,
163 base::Bind(&ContentSizeFrameCounter::NotifyFramesWentOverSizeLimits,
164 base::Passed(std::move(frames_over_limit))));
165 }
166 }
167
168 // static
169 void ContentSizeFrameCounter::NotifyFramesWentOverSizeLimits(
170 std::unique_ptr<std::set<GlobalFrameRoutingId>> frames) {
171 DCHECK_CURRENTLY_ON(BrowserThread::IO);
172 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
173 if (rdh && rdh->content_size_manager()) {
174 rdh->content_size_manager()->FramesWentOverSizeLimits(std::move(frames));
175 }
176 }
177
178 // static
179 void ContentSizeFrameCounter::NotifyFrameHasLimit(
180 const GlobalFrameRoutingId& frame,
181 uint64_t limit) {
182 DCHECK_CURRENTLY_ON(BrowserThread::IO);
183 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
184 if (rdh && rdh->content_size_manager()) {
185 rdh->content_size_manager()->FrameHasSizeLimit(frame, limit);
186 }
187 }
188
189 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/content_size_frame_counter.h ('k') | content/browser/loader/content_size_resource_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698