From 945e26750e1ff9af897d2d8998024e1d2c4a64f5 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sat, 21 Jan 2017 00:46:38 +0530 Subject: [PATCH] manage the lifetime of streams created --- atom/browser/atom_browser_context.cc | 2 + atom/browser/atom_browser_context.h | 3 + .../atom_resource_dispatcher_host_delegate.cc | 29 ++++---- .../browser/atom_web_ui_controller_factory.cc | 16 ++--- atom/browser/stream_manager.cc | 66 +++++++++++++++++++ atom/browser/stream_manager.h | 66 +++++++++++++++++++ atom/browser/ui/webui/pdf_viewer_handler.cc | 52 +++++++++++++-- atom/browser/ui/webui/pdf_viewer_handler.h | 11 ++-- filenames.gypi | 2 + 9 files changed, 216 insertions(+), 31 deletions(-) create mode 100644 atom/browser/stream_manager.cc create mode 100644 atom/browser/stream_manager.h diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index 76a23cdcda4e..2167f3973585 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -17,6 +17,7 @@ #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/net/atom_url_request_job_factory.h" #include "atom/browser/net/http_protocol_handler.h" +#include "atom/browser/stream_manager.h" #include "atom/browser/web_view_manager.h" #include "atom/common/atom_version.h" #include "atom/common/chrome_version.h" @@ -73,6 +74,7 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition, const base::DictionaryValue& options) : brightray::BrowserContext(partition, in_memory), ct_delegate_(new AtomCTDelegate), + stream_manager_(new StreamManager), network_delegate_(new AtomNetworkDelegate), cookie_delegate_(new AtomCookieDelegate) { // Construct user agent string. diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index 340c8f46626f..87aa92c4fc1c 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -19,6 +19,7 @@ class AtomCTDelegate; class AtomDownloadManagerDelegate; class AtomNetworkDelegate; class AtomPermissionManager; +class StreamManager; class WebViewManager; class AtomBrowserContext : public brightray::BrowserContext { @@ -58,6 +59,7 @@ class AtomBrowserContext : public brightray::BrowserContext { AtomCookieDelegate* cookie_delegate() const { return cookie_delegate_.get(); } + StreamManager* stream_manager() const { return stream_manager_.get(); } protected: AtomBrowserContext(const std::string& partition, bool in_memory, @@ -70,6 +72,7 @@ class AtomBrowserContext : public brightray::BrowserContext { std::unique_ptr permission_manager_; std::unique_ptr blob_reader_; std::unique_ptr ct_delegate_; + std::unique_ptr stream_manager_; std::string user_agent_; bool use_cache_; diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc index aa507c38c3d2..1bd78970feeb 100644 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -4,14 +4,15 @@ #include "atom/browser/atom_resource_dispatcher_host_delegate.h" +#include "atom/browser/atom_browser_context.h" #include "atom/browser/login_handler.h" +#include "atom/browser/stream_manager.h" #include "atom/browser/web_contents_permission_helper.h" #include "atom/common/platform_util.h" +#include "base/guid.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/stream_handle.h" -#include "content/public/browser/stream_info.h" #include "net/base/escape.h" #include "net/ssl/client_cert_store.h" #include "net/url_request/url_request.h" @@ -61,19 +62,24 @@ void HandleExternalProtocolInUI( permission_helper->RequestOpenExternalPermission(callback, has_user_gesture); } -void OnPdfStreamCreated(std::unique_ptr stream, - int64_t expected_content_size, - const content::ResourceRequestInfo::WebContentsGetter& - web_contents_getter) { +void OnPdfStreamCreated( + std::unique_ptr stream, + int64_t expected_content_size, + const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, + int render_process_id, + int render_frame_id) { content::WebContents* web_contents = web_contents_getter.Run(); if (!web_contents) return; - auto stream_url = stream->handle->GetURL(); - auto original_url = stream->original_url; + auto browser_context = + static_cast(web_contents->GetBrowserContext()); + auto stream_manager = browser_context->stream_manager(); + std::string view_id = base::GenerateGUID(); + stream_manager->AddStream(std::move(stream), view_id, render_process_id, + render_frame_id); content::NavigationController::LoadURLParams params(GURL(base::StringPrintf( - "chrome://pdf-viewer/index.html?streamURL=%s&originalURL=%s", - stream_url.spec().c_str(), original_url.spec().c_str()))); + "chrome://pdf-viewer/index.html?viewId=%s", view_id.c_str()))); web_contents->GetController().LoadURLWithParams(params); } @@ -137,7 +143,8 @@ void AtomResourceDispatcherHostDelegate::OnStreamCreated( BrowserThread::UI, FROM_HERE, base::Bind(&OnPdfStreamCreated, base::Passed(&stream), request->GetExpectedContentSize(), - info->GetWebContentsGetterForRequest())); + info->GetWebContentsGetterForRequest(), info->GetChildID(), + info->GetRenderFrameID())); } } // namespace atom diff --git a/atom/browser/atom_web_ui_controller_factory.cc b/atom/browser/atom_web_ui_controller_factory.cc index a53eac354db4..7ffbdde7b8a2 100644 --- a/atom/browser/atom_web_ui_controller_factory.cc +++ b/atom/browser/atom_web_ui_controller_factory.cc @@ -88,10 +88,9 @@ class PdfViewerUI : public content::WebUIController { public: PdfViewerUI(content::BrowserContext* browser_context, content::WebUI* web_ui, - const std::string& stream_url, - const std::string& original_url) + const std::string& view_id) : content::WebUIController(web_ui) { - web_ui->AddMessageHandler(new PdfViewerHandler(stream_url, original_url)); + web_ui->AddMessageHandler(new PdfViewerHandler(view_id)); content::URLDataSource::Add(browser_context, new BundledDataSource); } @@ -143,16 +142,15 @@ AtomWebUIControllerFactory::CreateWebUIControllerForURL(content::WebUI* web_ui, if (url.host() == kChromeUIPdfViewerHost) { base::StringPairs toplevel_params; base::SplitStringIntoKeyValuePairs(url.query(), '=', '&', &toplevel_params); - std::string stream_url, original_url; + std::string view_id; for (const auto& param : toplevel_params) { - if (param.first == "streamURL") { - stream_url = param.second; - } else if (param.first == "originalURL") { - original_url = param.second; + if (param.first == "viewId") { + view_id = param.second; + break; } } auto browser_context = web_ui->GetWebContents()->GetBrowserContext(); - return new PdfViewerUI(browser_context, web_ui, stream_url, original_url); + return new PdfViewerUI(browser_context, web_ui, view_id); } return nullptr; } diff --git a/atom/browser/stream_manager.cc b/atom/browser/stream_manager.cc new file mode 100644 index 000000000000..7f19d31cb565 --- /dev/null +++ b/atom/browser/stream_manager.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/stream_manager.h" + +#include "base/memory/ptr_util.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" + +namespace atom { + +StreamManager::StreamManager() {} + +StreamManager::~StreamManager() {} + +void StreamManager::AddStream(std::unique_ptr stream, + const std::string& view_id, + int render_process_id, + int render_frame_id) { + streams_.insert(std::make_pair(view_id, std::move(stream))); + observers_[view_id] = base::MakeUnique( + this, view_id, render_process_id, render_frame_id); +} + +std::unique_ptr StreamManager::ReleaseStream( + const std::string& view_id) { + auto stream = streams_.find(view_id); + if (stream == streams_.end()) + return nullptr; + + std::unique_ptr result = + base::WrapUnique(stream->second.release()); + streams_.erase(stream); + observers_.erase(view_id); + return result; +} + +StreamManager::EmbedderObserver::EmbedderObserver(StreamManager* stream_manager, + const std::string& view_id, + int render_process_id, + int render_frame_id) + : stream_manager_(stream_manager), view_id_(view_id) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost( + content::RenderFrameHost::FromID(render_process_id, render_frame_id)); + content::WebContentsObserver::Observe(web_contents); +} + +void StreamManager::EmbedderObserver::RenderProcessGone( + base::TerminationStatus status) { + AbortStream(); +} + +void StreamManager::EmbedderObserver::WebContentsDestroyed() { + AbortStream(); +} + +void StreamManager::EmbedderObserver::AbortStream() { + Observe(nullptr); + stream_manager_->ReleaseStream(view_id_); +} + +} // namespace atom diff --git a/atom/browser/stream_manager.h b/atom/browser/stream_manager.h new file mode 100644 index 000000000000..9f4101ed7358 --- /dev/null +++ b/atom/browser/stream_manager.h @@ -0,0 +1,66 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_STREAM_MANAGER_H_ +#define ATOM_BROWSER_STREAM_MANAGER_H_ + +#include +#include + +#include "base/macros.h" +#include "content/public/browser/stream_info.h" +#include "content/public/browser/web_contents_observer.h" + +namespace atom { + +// A container for streams that have not been claimed by associated +// WebContents. +class StreamManager { + public: + StreamManager(); + ~StreamManager(); + + void AddStream(std::unique_ptr stream, + const std::string& view_id, + int render_process_id, + int render_frame_id); + + std::unique_ptr ReleaseStream( + const std::string& view_id); + + private: + // WebContents observer that deletes an unclaimed stream + // associated with it, when destroyed. + class EmbedderObserver : public content::WebContentsObserver { + public: + EmbedderObserver(StreamManager* stream_manager, + const std::string& view_id, + int render_process_id, + int render_frame_id); + + private: + // content::WebContentsObserver: + void RenderProcessGone(base::TerminationStatus status) override; + void WebContentsDestroyed() override; + + void AbortStream(); + + StreamManager* stream_manager_; + std::string view_id_; + int render_process_id_; + int render_frame_id_; + + DISALLOW_COPY_AND_ASSIGN(EmbedderObserver); + }; + + std::map> streams_; + + std::map> observers_; + + DISALLOW_COPY_AND_ASSIGN(StreamManager); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_STREAM_MANAGER_H_ diff --git a/atom/browser/ui/webui/pdf_viewer_handler.cc b/atom/browser/ui/webui/pdf_viewer_handler.cc index 82c80d7a81a4..ee53c13ef231 100644 --- a/atom/browser/ui/webui/pdf_viewer_handler.cc +++ b/atom/browser/ui/webui/pdf_viewer_handler.cc @@ -4,22 +4,53 @@ #include "atom/browser/ui/webui/pdf_viewer_handler.h" -#include "base/bind.h" -#include "base/bind_helpers.h" +#include "atom/browser/atom_browser_context.h" +#include "atom/browser/stream_manager.h" #include "base/values.h" +#include "content/public/browser/stream_handle.h" +#include "content/public/browser/stream_info.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/common/page_zoom.h" +#include "net/http/http_response_headers.h" namespace atom { -PdfViewerHandler::PdfViewerHandler(const std::string& stream_url, - const std::string& original_url) - : stream_url_(stream_url), original_url_(original_url) {} +namespace { + +void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers, + base::DictionaryValue* result) { + if (!headers) + return; + + size_t iter = 0; + std::string header_name; + std::string header_value; + while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { + base::Value* existing_value = nullptr; + if (result->Get(header_name, &existing_value)) { + base::StringValue* existing_string_value = + static_cast(existing_value); + existing_string_value->GetString()->append(", ").append(header_value); + } else { + result->SetString(header_name, header_value); + } + } +} + +} // namespace + +PdfViewerHandler::PdfViewerHandler(const std::string& view_id) + : view_id_(view_id) {} PdfViewerHandler::~PdfViewerHandler() {} void PdfViewerHandler::RegisterMessages() { + auto browser_context = static_cast( + web_ui()->GetWebContents()->GetBrowserContext()); + auto stream_manager = browser_context->stream_manager(); + stream_ = stream_manager->ReleaseStream(view_id_); + web_ui()->RegisterMessageCallback( "initialize", base::Bind(&PdfViewerHandler::Initialize, base::Unretained(this))); @@ -50,8 +81,15 @@ void PdfViewerHandler::Initialize(const base::ListValue* args) { const base::Value* callback_id; CHECK(args->Get(0, &callback_id)); std::unique_ptr stream_info(new base::DictionaryValue); - stream_info->SetString("streamURL", stream_url_); - stream_info->SetString("originalURL", original_url_); + auto stream_url = stream_->handle->GetURL().spec(); + auto original_url = stream_->original_url.spec(); + stream_info->SetString("streamURL", stream_url); + stream_info->SetString("originalURL", original_url); + std::unique_ptr headers_dict( + new base::DictionaryValue); + CreateResponseHeadersDictionary(stream_->response_headers.get(), + headers_dict.get()); + stream_info->Set("responseHeaders", std::move(headers_dict)); ResolveJavascriptCallback(*callback_id, *stream_info); } diff --git a/atom/browser/ui/webui/pdf_viewer_handler.h b/atom/browser/ui/webui/pdf_viewer_handler.h index 10e376d0918a..3096aa9d8ef6 100644 --- a/atom/browser/ui/webui/pdf_viewer_handler.h +++ b/atom/browser/ui/webui/pdf_viewer_handler.h @@ -15,12 +15,15 @@ namespace base { class ListValue; } +namespace content { +class StreamInfo; +} + namespace atom { class PdfViewerHandler : public content::WebUIMessageHandler { public: - PdfViewerHandler(const std::string& stream_url, - const std::string& original_url); + explicit PdfViewerHandler(const std::string& view_id); ~PdfViewerHandler() override; // WebUIMessageHandler implementation. @@ -37,8 +40,8 @@ class PdfViewerHandler : public content::WebUIMessageHandler { // Keeps track of events related to zooming. std::unique_ptr host_zoom_map_subscription_; - std::string stream_url_; - std::string original_url_; + std::unique_ptr stream_; + std::string view_id_; DISALLOW_COPY_AND_ASSIGN(PdfViewerHandler); }; diff --git a/filenames.gypi b/filenames.gypi index 47e17c7e82ae..6b233bd8d96a 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -278,6 +278,8 @@ 'atom/browser/relauncher.h', 'atom/browser/render_process_preferences.cc', 'atom/browser/render_process_preferences.h', + 'atom/browser/stream_manager.cc', + 'atom/browser/stream_manager.h', 'atom/browser/ui/accelerator_util.cc', 'atom/browser/ui/accelerator_util.h', 'atom/browser/ui/accelerator_util_mac.mm',