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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/loader/content_size_frame_counter.cc
diff --git a/content/browser/loader/content_size_frame_counter.cc b/content/browser/loader/content_size_frame_counter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6c5e0f9512502b5b36ef93a56773ef107f218353
--- /dev/null
+++ b/content/browser/loader/content_size_frame_counter.cc
@@ -0,0 +1,189 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/content_size_frame_counter.h"
+
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/loader/content_size_resource_handler_manager.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/common/content_switches.h"
+#include "url/origin.h"
+
+namespace content {
+
+ContentSizeFrameCounter::ContentSizeFrameCounter(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+ContentSizeFrameCounter::~ContentSizeFrameCounter() {}
+
+// TODO(csharrison): This code really wants to be in
+// WebContentsObserver::ReadyToCommitNavigation, which is not available yet.
+// Note: this code is all experimental. In the final version, the render process
+// will notify this component that a given frame should have its data counted.
+// This will likely be in a mojo interface callback. For now, count all
+// cross-origin frames as having a data limit set by a command line flag.
+void ContentSizeFrameCounter::DidFinishNavigation(
+ NavigationHandle* navigation_handle) {
+ if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage())
+ return;
+ const GURL& url = navigation_handle->GetURL();
+ // Only consider http/s or about:blank urls for blocking.
+ if (!url.SchemeIsHTTPOrHTTPS() &&
+ url.spec().compare(url::kAboutBlankURL) != 0) {
+ return;
+ }
+
+ if (web_contents()->GetLastCommittedURL().SchemeIs("chrome"))
+ return;
+
+ // TODO(csharrison): Navigations to about:blank are not counted as
+ // same-origin.
+ if (url::Origin(web_contents()->GetLastCommittedURL())
+ .IsSameOriginWith(url::Origin(url))) {
+ return;
+ }
+
+ std::string policy_string =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kContentSizePolicy);
+ uint64_t content_size = 0;
+ base::StringToUint64(policy_string, &content_size);
+
+ RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
+ navigation_handle->GetRenderFrameHost());
+ FrameSize* frame_size = AddNewFrame(rfh->frame_tree_node(), content_size);
+ if (frame_size->content_left < INT_MAX) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ContentSizeFrameCounter::NotifyFrameHasLimit,
+ rfh->GetGlobalFrameRoutingId(), frame_size->content_left));
+ }
+}
+
+// static
+// This method iterates through all ContentSizeFrameCounters, and calls
+// UpdateDataAccounting on them with updates from the IO thread.
+void ContentSizeFrameCounter::UpdateGlobalDataAccounting(
+ std::unique_ptr<std::map<GlobalFrameRoutingId, uint64_t>> updates) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(updates);
+ std::map<ContentSizeFrameCounter*, std::map<GlobalFrameRoutingId, uint64_t>>
+ per_notifier_map;
+ for (const auto& it : *updates) {
+ RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(
+ it.first.child_id, it.first.frame_routing_id);
+ WebContents* contents = WebContents::FromRenderFrameHost(rfh);
+ if (!contents)
+ continue;
+ ContentSizeFrameCounter* notifier =
+ static_cast<WebContentsImpl*>(contents)->content_size_frame_counter();
+ per_notifier_map[notifier][it.first] += it.second;
+ }
+ for (const auto& it : per_notifier_map) {
+ it.first->UpdateDataAccounting(it.second);
+ }
+}
+
+ContentSizeFrameCounter::FrameSize* ContentSizeFrameCounter::AddNewFrame(
+ FrameTreeNode* node,
+ uint64_t limit) {
+ FrameSize* min_parent_frame_size = nullptr;
+ for (FrameTreeNode* current_node = node->parent(); current_node != nullptr;
+ current_node = current_node->parent()) {
+ std::map<int, FrameSize>::iterator size_it =
+ frame_tree_node_sizes_.find(current_node->frame_tree_node_id());
+ if (size_it != frame_tree_node_sizes_.end() &&
+ (!min_parent_frame_size ||
+ size_it->second.content_left < min_parent_frame_size->content_left)) {
+ min_parent_frame_size = &size_it->second;
+ }
+ }
+
+ // No need to add this to the map if a parent frame has a lower limit.
+ if (min_parent_frame_size && min_parent_frame_size->content_left <= limit)
+ return min_parent_frame_size;
+ FrameSize* size = &frame_tree_node_sizes_[node->frame_tree_node_id()];
+ size->content_left = limit;
+ return size;
+}
+
+void ContentSizeFrameCounter::ApplyUpdateToTree(
+ FrameTreeNode* node,
+ uint64_t bytes_downloaded,
+ std::set<GlobalFrameRoutingId>* routing_ids_to_block) {
+ FrameTreeNode* highest_node_to_block = nullptr;
+ for (FrameTreeNode* current_node = node; current_node != nullptr;
+ current_node = current_node->parent()) {
+ std::map<int, FrameSize>::iterator size_it =
+ frame_tree_node_sizes_.find(current_node->frame_tree_node_id());
+ if (size_it == frame_tree_node_sizes_.end())
+ continue;
+
+ if (size_it->second.content_left < bytes_downloaded) {
+ size_it->second.content_left = 0;
+ highest_node_to_block = node;
+ } else {
+ size_it->second.content_left -= bytes_downloaded;
+ }
+ }
+
+ // No frame went over the size limit.
+ if (!highest_node_to_block)
+ return;
+
+ // Collect all the routing ids to block in the subtree defined by
+ // |highest_node_to_block|.
+ for (FrameTreeNode* ftn : highest_node_to_block->frame_tree()->SubtreeNodes(
+ highest_node_to_block)) {
+ routing_ids_to_block->insert(
+ ftn->current_frame_host()->GetGlobalFrameRoutingId());
+ }
+}
+
+void ContentSizeFrameCounter::UpdateDataAccounting(
+ std::map<GlobalFrameRoutingId, uint64_t> updates) {
+ std::unique_ptr<std::set<GlobalFrameRoutingId>> frames_over_limit(
+ new std::set<GlobalFrameRoutingId>);
+ for (const auto& it : updates) {
+ RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
+ RenderFrameHost::FromID(it.first.child_id, it.first.frame_routing_id));
+ if (!rfh)
+ continue;
+ ApplyUpdateToTree(rfh->frame_tree_node(), it.second,
+ frames_over_limit.get());
+ }
+ if (!frames_over_limit->empty()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ContentSizeFrameCounter::NotifyFramesWentOverSizeLimits,
+ base::Passed(std::move(frames_over_limit))));
+ }
+}
+
+// static
+void ContentSizeFrameCounter::NotifyFramesWentOverSizeLimits(
+ std::unique_ptr<std::set<GlobalFrameRoutingId>> frames) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+ if (rdh && rdh->content_size_manager()) {
+ rdh->content_size_manager()->FramesWentOverSizeLimits(std::move(frames));
+ }
+}
+
+// static
+void ContentSizeFrameCounter::NotifyFrameHasLimit(
+ const GlobalFrameRoutingId& frame,
+ uint64_t limit) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+ if (rdh && rdh->content_size_manager()) {
+ rdh->content_size_manager()->FrameHasSizeLimit(frame, limit);
+ }
+}
+
+} // namespace content
« 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