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

Unified 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, 5 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/loader_io_thread_notifier.cc
diff --git a/content/browser/loader/loader_io_thread_notifier.cc b/content/browser/loader/loader_io_thread_notifier.cc
index a10537c9d3d342714e9245ce6628915cf3343176..ddebb98da55dc39d82f93c82a6f6dcb845fb2bc8 100644
--- a/content/browser/loader/loader_io_thread_notifier.cc
+++ b/content/browser/loader/loader_io_thread_notifier.cc
@@ -5,9 +5,13 @@
#include "content/browser/loader/loader_io_thread_notifier.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/loader/global_routing_id.h"
+#include "content/browser/loader/content_size_resource_handler.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 {
@@ -19,6 +23,24 @@ void NotifyRenderFrameDeletedOnIO(const GlobalFrameRoutingId& id) {
rdhi->OnRenderFrameDeleted(id);
}
+class ContentSizeNavigationThrottle : public NavigationThrottle {
+ public:
+ ContentSizeNavigationThrottle(NavigationHandle* handle,
+ LoaderIOThreadNotifier* notifier)
+ : NavigationThrottle(handle), notifier_(notifier) {}
+ ~ContentSizeNavigationThrottle() override {}
+
+ // NavigationThrottle:
+ NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
+ return notifier_->WillProcessNavigationResponse(navigation_handle());
+ }
+
+ private:
+ LoaderIOThreadNotifier* notifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSizeNavigationThrottle);
+};
+
} // namespace
LoaderIOThreadNotifier::LoaderIOThreadNotifier(WebContents* web_contents)
@@ -35,4 +57,164 @@ void LoaderIOThreadNotifier::RenderFrameDeleted(
->GetGlobalFrameRoutingId()));
}
+// static
+NavigationThrottle* LoaderIOThreadNotifier::MaybeCreateThrottle(
+ NavigationHandle* handle) {
+ 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
+ return nullptr;
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kContentSizePolicy)) {
+ return nullptr;
+ }
+
+ LoaderIOThreadNotifier* notifier =
+ static_cast<WebContentsImpl*>(handle->GetWebContents())
+ ->loader_io_thread_notifier();
+ return new ContentSizeNavigationThrottle(handle, notifier);
+}
+
+// TODO(csharrison): This should be moved to ReadyToCommitNavigation once that
+// is available. This callback is incorrect for transfer navigations.
+NavigationThrottle::ThrottleCheckResult
+LoaderIOThreadNotifier::WillProcessNavigationResponse(
+ 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
+ const GURL& url = navigation_handle->GetURL();
+ // 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
+ if (!url.SchemeIsHTTPOrHTTPS() &&
+ url.spec().compare(url::kAboutBlankURL) != 0) {
+ return NavigationThrottle::PROCEED;
+ }
+
+ if (web_contents()->GetLastCommittedURL().SchemeIs("chrome"))
+ return NavigationThrottle::PROCEED;
+
+ // TODO(csharrison): Navigations to about:blank are not counted as
+ // same-origin.
+ if (url::Origin(web_contents()->GetLastCommittedURL())
+ .IsSameOriginWith(url::Origin(url))) {
+ return NavigationThrottle::PROCEED;
+ }
+
+ std::string policy_string =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ 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
+ int content_size = 0;
+ 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
+
+ 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(&LoaderIOThreadNotifier::NotifyFrameHasLimit,
+ rfh->GetGlobalFrameRoutingId(), frame_size->content_left));
+ }
+ return frame_size->content_left <= 0 ? NavigationThrottle::CANCEL
+ : NavigationThrottle::PROCEED;
+}
+
+void LoaderIOThreadNotifier::RenderFrameCreated(
+ 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.
+}
+
+// static
+// This method iterates through all LoaderIOThreadNotifiers, and calls
+// UpdateDataAccounting on them with updates from the IO thread.
+void LoaderIOThreadNotifier::UpdateGlobalDataAccounting(
+ std::unique_ptr<std::map<GlobalFrameRoutingId, int>> updates) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(updates);
+ std::map<LoaderIOThreadNotifier*, std::map<GlobalFrameRoutingId, int>>
+ 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);
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
+ if (!contents)
+ continue;
+ LoaderIOThreadNotifier* notifier =
+ static_cast<WebContentsImpl*>(contents)->loader_io_thread_notifier();
+ 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.
+ }
+ for (const auto& it : per_notifier_map) {
+ it.first->UpdateDataAccounting(it.second);
+ }
+}
+
+LoaderIOThreadNotifier::FrameSize* LoaderIOThreadNotifier::AddNewFrame(
+ FrameTreeNode* node,
+ int limit) {
+ FrameSize* frame_size = GetEffectiveLimit(node);
+ // No need to add this to the map if a parent frame has a lower limit.
+ if (!frame_size || frame_size->content_left > limit) {
+ 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
+ size->content_limit = limit;
+ size->content_left = limit;
+ return size;
+ }
+ return frame_size;
+}
+
+// This method walks the frame tree and returns the FrameSize of the frame with
+// the lowest limit. This is the effective bytes limit of |node|.
+LoaderIOThreadNotifier::FrameSize*
+LoaderIOThreadNotifier::GetEffectiveLimit(FrameTreeNode* node) {
+ FrameSize* frame_size = nullptr;
+ FrameTreeNode* current_node = node;
+ while (current_node) {
+ 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() &&
+ (!frame_size ||
+ size_it->second.content_left < frame_size->content_left)) {
+ frame_size = &size_it->second;
+ }
+ current_node = current_node->parent();
+ }
+ return frame_size;
+}
+
+void LoaderIOThreadNotifier::UpdateDataAccounting(
+ std::map<GlobalFrameRoutingId, int> 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));
+ FrameSize* frame_size = GetEffectiveLimit(rfh->frame_tree_node());
+ DCHECK(frame_size);
+ 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.
+ if (frame_size->content_left <= 0)
+ frames_over_limit->insert(it.first);
+ }
+ if (!frames_over_limit->empty()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&LoaderIOThreadNotifier::NotifyFramesWentOverSizeLimits,
+ base::Passed(std::move(frames_over_limit))));
+ }
+}
+
+// static
+void LoaderIOThreadNotifier::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 LoaderIOThreadNotifier::NotifyFrameHasLimit(
+ const GlobalFrameRoutingId& frame,
+ int 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

Powered by Google App Engine
This is Rietveld 408576698