Index: content/browser/appcache/appcache_frame_node_navigation.cc |
diff --git a/content/browser/appcache/appcache_frame_node_navigation.cc b/content/browser/appcache/appcache_frame_node_navigation.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..afe4c3f262ccfb4e34ee64184f3c754945bcb0eb |
--- /dev/null |
+++ b/content/browser/appcache/appcache_frame_node_navigation.cc |
@@ -0,0 +1,183 @@ |
+// 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/appcache/appcache_frame_node_navigation.h" |
+ |
+#include <map> |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/lazy_instance.h" |
+#include "content/browser/appcache/appcache_dispatcher_host.h" |
+#include "content/browser/appcache/chrome_appcache_service.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/common/browser_side_navigation_policy.h" |
+ |
+namespace { |
+ |
+typedef std::map<int, content::AppCacheFrameNavigationHandler*> |
+ FrameToNavigationHandlerMap; |
+base::LazyInstance<FrameToNavigationHandlerMap> g_frame_navigation_handler_map; |
+ |
+// PlzNavigate: Used to generate the host id for a navigation initiated by the |
+// browser. Starts at -2 and keeps going down. |
+static int g_next_appcache_host_id = -2; |
+ |
+} // namespace |
+ |
+namespace content { |
+ |
+AppCacheFrameNavigationHandler::AppCacheFrameNavigationHandler( |
+ ChromeAppCacheService* appcache_service, |
+ int frame_node_id) |
+ : frame_node_id_(frame_node_id), |
+ appcache_service_(appcache_service), |
+ frontend_proxy_(this), |
+ commit_received_(false), |
+ weak_factory_(this) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ AddRef(); |
+ g_frame_navigation_handler_map.Get()[frame_node_id] = this; |
+} |
+ |
+AppCacheFrameNavigationHandler::~AppCacheFrameNavigationHandler() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+} |
+ |
+// static |
+int AppCacheFrameNavigationHandler::BeginNavigation( |
+ AppCacheServiceImpl* appcache_service, |
+ int frame_node_id) { |
+ DCHECK(IsBrowserSideNavigationEnabled()); |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ if (!appcache_service) |
+ return kAppCacheNoHostId; |
+ |
+ // If we have an existing AppCacheFrameNavigationHandler for the |
+ // |frame_node_id| passed in, we have no choice at this point but to |
+ // release that instance. |
+ // Please note this only happens if the tasks we posted below never |
+ // ran. |
+ FrameToNavigationHandlerMap::iterator index = |
+ g_frame_navigation_handler_map.Get().find(frame_node_id); |
+ if (index != g_frame_navigation_handler_map.Get().end()) { |
+ if (!index->second->commit_received_) |
+ index->second->Release(); |
+ } |
+ |
+ AppCacheFrameNavigationHandler* navigation_handler = |
+ new AppCacheFrameNavigationHandler( |
+ static_cast<ChromeAppCacheService*>(appcache_service), frame_node_id); |
+ g_frame_navigation_handler_map.Get()[frame_node_id] = navigation_handler; |
+ |
+ int host_id = g_next_appcache_host_id--; |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&AppCacheFrameNavigationHandler::RegisterPendingHostHelper, |
+ navigation_handler->weak_factory_.GetWeakPtr(), host_id)); |
+ |
+ return host_id; |
+} |
+ |
+// static |
+void AppCacheFrameNavigationHandler::CommitNavigation(int frame_node_id, |
+ int process_id) { |
+ DCHECK(IsBrowserSideNavigationEnabled()); |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ DCHECK(g_frame_navigation_handler_map.Get().find(frame_node_id) != |
+ g_frame_navigation_handler_map.Get().end()); |
+ |
+ g_frame_navigation_handler_map.Get()[frame_node_id]->commit_received_ = true; |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&AppCacheFrameNavigationHandler::CommitNavigationHelper, |
+ g_frame_navigation_handler_map.Get()[frame_node_id] |
+ ->weak_factory_.GetWeakPtr(), |
+ process_id)); |
+} |
+ |
+void AppCacheFrameNavigationHandler::FailedNavigation(int frame_node_id) { |
+ DCHECK(IsBrowserSideNavigationEnabled()); |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ FrameToNavigationHandlerMap::iterator index = |
+ g_frame_navigation_handler_map.Get().find(frame_node_id); |
+ |
+ DCHECK(index != g_frame_navigation_handler_map.Get().end()); |
+ |
+ index->second->Release(); |
+} |
+ |
+bool AppCacheFrameNavigationHandler::Send(IPC::Message* msg) { |
+ DCHECK(false); |
+ return false; |
+} |
+ |
+void AppCacheFrameNavigationHandler::RegisterPendingHostHelper(int host_id) { |
+ DCHECK(IsBrowserSideNavigationEnabled()); |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ DCHECK(!backend_impl_.get()); |
+ backend_impl_.reset(new AppCacheBackendImpl); |
+ backend_impl_->Initialize(appcache_service_.get(), &frontend_proxy_, -1, |
+ frame_node_id_); |
+ backend_impl_->RegisterHost(host_id); |
+} |
+ |
+void AppCacheFrameNavigationHandler::CommitNavigationHelper(int process_id) { |
+ DCHECK(IsBrowserSideNavigationEnabled()); |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ DCHECK(backend_impl_.get()); |
+ |
+ // When the navigation for a frame tree node commits, we need to switch the |
+ // AppCacheBackendImpl instance from a frame based navigation to a process |
+ // based navigation. For this we unregister the AppCacheBackendImpl instance |
+ // from the AppCache service. We then set the process id in the |
+ // AppCacheBackendImpl instance. This ensures that it is registered using |
+ // the process id in the AppCacheDispatcherHost::FrameNavigationCommitted() |
+ // function. |
+ appcache_service_->UnregisterBackendForFrame(backend_impl_.get()); |
+ |
+ scoped_refptr<AppCacheDispatcherHost> dispatcher_host = |
+ AppCacheDispatcherHost::GetHostForProcess(process_id); |
+ if (dispatcher_host.get()) { |
+ backend_impl_->set_process_id(process_id); |
+ backend_impl_->set_frame_id(-1); |
+ dispatcher_host->FrameNavigationCommitted(std::move(backend_impl_)); |
+ } |
+ |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ base::Bind(&AppCacheFrameNavigationHandler::Release, |
+ base::Unretained(this))); |
+ // Don't access any member from here on. |
+} |
+ |
+void AppCacheFrameNavigationHandler::DeleteOnCorrectThread() const { |
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
+ // The reference to us in the global map needs to be remove in the UI |
+ // thread. |
+ FrameToNavigationHandlerMap::iterator index = |
+ g_frame_navigation_handler_map.Get().find(frame_node_id_); |
+ if ((index != g_frame_navigation_handler_map.Get().end()) && |
+ index->second == this) { |
+ g_frame_navigation_handler_map.Get().erase(index); |
+ } |
+ } |
+ |
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
michaeln
2016/11/22 00:17:27
if we go thru this code path, we do we leave a dan
ananta
2016/11/23 04:05:14
This file has gone
|
+ delete this; |
+ return; |
+ } |
+ |
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { |
+ BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, this); |
+ return; |
+ } |
+ |
+ // Better to leak than crash on shutdown. |
+} |
+ |
+} // namespace content |