Chromium Code Reviews| 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 |