blob: 78b76340f07594e71f6b6e7d9303300e5cf9cdd8 [file] [log] [blame]
// Copyright 2015 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 "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
namespace extensions {
namespace {
class MimeHandlerStreamManagerFactory
: public BrowserContextKeyedServiceFactory {
public:
MimeHandlerStreamManagerFactory();
static MimeHandlerStreamManagerFactory* GetInstance();
MimeHandlerStreamManager* Get(content::BrowserContext* context);
private:
// BrowserContextKeyedServiceFactory overrides.
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const override;
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
};
MimeHandlerStreamManagerFactory::MimeHandlerStreamManagerFactory()
: BrowserContextKeyedServiceFactory(
"MimeHandlerStreamManager",
BrowserContextDependencyManager::GetInstance()) {
}
// static
MimeHandlerStreamManagerFactory*
MimeHandlerStreamManagerFactory::GetInstance() {
return base::Singleton<MimeHandlerStreamManagerFactory>::get();
}
MimeHandlerStreamManager* MimeHandlerStreamManagerFactory::Get(
content::BrowserContext* context) {
return static_cast<MimeHandlerStreamManager*>(
GetServiceForBrowserContext(context, true));
}
KeyedService* MimeHandlerStreamManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new MimeHandlerStreamManager();
}
content::BrowserContext*
MimeHandlerStreamManagerFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
return extensions::ExtensionsBrowserClient::Get()->GetOriginalContext(
context);
}
} // namespace
// A WebContentsObserver that observes for a particular RenderFrameHost either
// navigating or closing (including by crashing). This is necessary to ensure
// that streams that aren't claimed by a MimeHandlerViewGuest are not leaked, by
// aborting the stream if any of those events occurs.
class MimeHandlerStreamManager::EmbedderObserver
: public content::WebContentsObserver {
public:
EmbedderObserver(MimeHandlerStreamManager* stream_manager,
int render_process_id,
int render_frame_id,
const std::string& view_id);
private:
// WebContentsObserver overrides.
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void RenderProcessGone(base::TerminationStatus status) override;
void DidStartProvisionalLoadForFrame(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) override;
void WebContentsDestroyed() override;
void AbortStream();
bool IsTrackedRenderFrameHost(content::RenderFrameHost* render_frame_host);
MimeHandlerStreamManager* const stream_manager_;
const int render_process_id_;
const int render_frame_id_;
const std::string view_id_;
};
MimeHandlerStreamManager::MimeHandlerStreamManager()
: extension_registry_observer_(this) {
}
MimeHandlerStreamManager::~MimeHandlerStreamManager() {
}
// static
MimeHandlerStreamManager* MimeHandlerStreamManager::Get(
content::BrowserContext* context) {
return MimeHandlerStreamManagerFactory::GetInstance()->Get(context);
}
void MimeHandlerStreamManager::AddStream(
const std::string& view_id,
std::unique_ptr<StreamContainer> stream,
int render_process_id,
int render_frame_id) {
streams_by_extension_id_[stream->extension_id()].insert(view_id);
auto result = streams_.insert(std::make_pair(view_id, std::move(stream)));
DCHECK(result.second);
embedder_observers_[view_id] = base::MakeUnique<EmbedderObserver>(
this, render_process_id, render_frame_id, view_id);
}
std::unique_ptr<StreamContainer> MimeHandlerStreamManager::ReleaseStream(
const std::string& view_id) {
auto stream = streams_.find(view_id);
if (stream == streams_.end())
return nullptr;
std::unique_ptr<StreamContainer> result =
base::WrapUnique(stream->second.release());
streams_by_extension_id_[result->extension_id()].erase(view_id);
streams_.erase(stream);
embedder_observers_.erase(view_id);
return result;
}
void MimeHandlerStreamManager::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionInfo::Reason reason) {
auto streams = streams_by_extension_id_.find(extension->id());
if (streams == streams_by_extension_id_.end())
return;
for (const auto& view_id : streams->second) {
streams_.erase(view_id);
embedder_observers_.erase(view_id);
}
streams_by_extension_id_.erase(streams);
}
MimeHandlerStreamManager::EmbedderObserver::EmbedderObserver(
MimeHandlerStreamManager* stream_manager,
int render_process_id,
int render_frame_id,
const std::string& view_id)
: WebContentsObserver(content::WebContents::FromRenderFrameHost(
content::RenderFrameHost::FromID(render_process_id,
render_frame_id))),
stream_manager_(stream_manager),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
view_id_(view_id) {
}
void MimeHandlerStreamManager::EmbedderObserver::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
if (!IsTrackedRenderFrameHost(render_frame_host))
return;
AbortStream();
}
void MimeHandlerStreamManager::EmbedderObserver::RenderProcessGone(
base::TerminationStatus status) {
AbortStream();
}
void MimeHandlerStreamManager::EmbedderObserver::
DidStartProvisionalLoadForFrame(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) {
if (!IsTrackedRenderFrameHost(render_frame_host))
return;
AbortStream();
}
void MimeHandlerStreamManager::EmbedderObserver::WebContentsDestroyed() {
AbortStream();
}
void MimeHandlerStreamManager::EmbedderObserver::AbortStream() {
Observe(nullptr);
// This will cause the stream to be destroyed.
stream_manager_->ReleaseStream(view_id_);
}
bool MimeHandlerStreamManager::EmbedderObserver::IsTrackedRenderFrameHost(
content::RenderFrameHost* render_frame_host) {
return render_frame_host->GetRoutingID() == render_frame_id_ &&
render_frame_host->GetProcess()->GetID() == render_process_id_;
}
} // namespace extensions