diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc index 53d91b4be954..653d81ee463c 100644 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/stream_info.h" #include "net/base/escape.h" #include "net/ssl/client_cert_store.h" @@ -34,8 +35,7 @@ namespace atom { namespace { -void OnOpenExternal(const GURL& escaped_url, - bool allowed) { +void OnOpenExternal(const GURL& escaped_url, bool allowed) { if (allowed) platform_util::OpenExternal( #if defined(OS_WIN) @@ -66,6 +66,8 @@ void HandleExternalProtocolInUI( void OnPdfResourceIntercepted( const GURL& original_url, + int render_process_host_id, + int render_frame_id, const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter) { content::WebContents* web_contents = web_contents_getter.Run(); @@ -75,7 +77,7 @@ void OnPdfResourceIntercepted( if (!WebContentsPreferences::IsPluginsEnabled(web_contents)) { auto browser_context = web_contents->GetBrowserContext(); auto download_manager = - content::BrowserContext::GetDownloadManager(browser_context); + content::BrowserContext::GetDownloadManager(browser_context); download_manager->DownloadUrl( content::DownloadUrlParameters::CreateForWebContentsMainFrame( @@ -86,26 +88,29 @@ void OnPdfResourceIntercepted( // The URL passes the original pdf resource url, that will be requested // by the webui page. // chrome://pdf-viewer/index.html?src=https://somepage/123.pdf - content::NavigationController::LoadURLParams params( - GURL(base::StringPrintf( - "%sindex.html?%s=%s", - kPdfViewerUIOrigin, - kPdfPluginSrc, - net::EscapeUrlEncodedData(original_url.spec(), false).c_str()))); + content::NavigationController::LoadURLParams params(GURL(base::StringPrintf( + "%sindex.html?%s=%s", kPdfViewerUIOrigin, kPdfPluginSrc, + net::EscapeUrlEncodedData(original_url.spec(), false).c_str()))); + + content::RenderFrameHost* frame_host = + content::RenderFrameHost::FromID(render_process_host_id, render_frame_id); + if (!frame_host) { + return; + } + + params.frame_tree_node_id = frame_host->GetFrameTreeNodeId(); web_contents->GetController().LoadURLWithParams(params); } } // namespace -AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() { -} +AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {} bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol( const GURL& url, content::ResourceRequestInfo* info) { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&HandleExternalProtocolInUI, - url, + base::Bind(&HandleExternalProtocolInUI, url, info->GetWebContentsGetterForRequest(), info->HasUserGesture())); return true; @@ -121,16 +126,16 @@ AtomResourceDispatcherHostDelegate::CreateLoginDelegate( std::unique_ptr AtomResourceDispatcherHostDelegate::CreateClientCertStore( content::ResourceContext* resource_context) { - #if defined(USE_NSS_CERTS) - return std::unique_ptr(new net::ClientCertStoreNSS( - net::ClientCertStoreNSS::PasswordDelegateFactory())); - #elif defined(OS_WIN) - return std::unique_ptr(new net::ClientCertStoreWin()); - #elif defined(OS_MACOSX) - return std::unique_ptr(new net::ClientCertStoreMac()); - #elif defined(USE_OPENSSL) - return std::unique_ptr(); - #endif +#if defined(USE_NSS_CERTS) + return std::unique_ptr(new net::ClientCertStoreNSS( + net::ClientCertStoreNSS::PasswordDelegateFactory())); +#elif defined(OS_WIN) + return std::unique_ptr(new net::ClientCertStoreWin()); +#elif defined(OS_MACOSX) + return std::unique_ptr(new net::ClientCertStoreMac()); +#elif defined(USE_OPENSSL) + return std::unique_ptr(); +#endif } bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream( @@ -141,11 +146,20 @@ bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream( std::string* payload) { const content::ResourceRequestInfo* info = content::ResourceRequestInfo::ForRequest(request); - if (mime_type == "application/pdf" && info->IsMainFrame()) { + + int render_process_host_id; + int render_frame_id; + if (!info->GetAssociatedRenderFrame(&render_process_host_id, + &render_frame_id)) { + return false; + } + + if (mime_type == "application/pdf") { *origin = GURL(kPdfViewerUIOrigin); content::BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&OnPdfResourceIntercepted, request->url(), + render_process_host_id, render_frame_id, info->GetWebContentsGetterForRequest())); return true; } diff --git a/atom/browser/ui/webui/pdf_viewer_handler.cc b/atom/browser/ui/webui/pdf_viewer_handler.cc index aee7ff05493e..cc51d2d92df9 100644 --- a/atom/browser/ui/webui/pdf_viewer_handler.cc +++ b/atom/browser/ui/webui/pdf_viewer_handler.cc @@ -58,7 +58,9 @@ void PopulateStreamInfo(base::DictionaryValue* stream_info, PdfViewerHandler::PdfViewerHandler(const std::string& src) : stream_(nullptr), original_url_(src) {} -PdfViewerHandler::~PdfViewerHandler() {} +PdfViewerHandler::~PdfViewerHandler() { + RemoveObserver(); +} void PdfViewerHandler::SetPdfResourceStream(content::StreamInfo* stream) { stream_ = stream; @@ -90,15 +92,11 @@ void PdfViewerHandler::RegisterMessages() { } void PdfViewerHandler::OnJavascriptAllowed() { - auto zoom_controller = WebContentsZoomController::FromWebContents( - web_ui()->GetWebContents()); - zoom_controller->AddObserver(this); + AddObserver(); } void PdfViewerHandler::OnJavascriptDisallowed() { - auto zoom_controller = WebContentsZoomController::FromWebContents( - web_ui()->GetWebContents()); - zoom_controller->RemoveObserver(this); + RemoveObserver(); } void PdfViewerHandler::Initialize(const base::ListValue* args) { @@ -214,4 +212,16 @@ void PdfViewerHandler::OnZoomLevelChanged(content::WebContents* web_contents, } } +void PdfViewerHandler::AddObserver() { + auto zoom_controller = + WebContentsZoomController::FromWebContents(web_ui()->GetWebContents()); + zoom_controller->AddObserver(this); +} + +void PdfViewerHandler::RemoveObserver() { + auto zoom_controller = + WebContentsZoomController::FromWebContents(web_ui()->GetWebContents()); + zoom_controller->RemoveObserver(this); +} + } // namespace atom diff --git a/atom/browser/ui/webui/pdf_viewer_handler.h b/atom/browser/ui/webui/pdf_viewer_handler.h index e6ae315e8764..2da19e684cdc 100644 --- a/atom/browser/ui/webui/pdf_viewer_handler.h +++ b/atom/browser/ui/webui/pdf_viewer_handler.h @@ -45,7 +45,8 @@ class PdfViewerHandler : public content::WebUIMessageHandler, void Reload(const base::ListValue* args); void OnZoomLevelChanged(content::WebContents* web_contents, double level, bool is_temporary); - + void AddObserver(); + void RemoveObserver(); std::unique_ptr initialize_callback_id_; content::StreamInfo* stream_; std::string original_url_; diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 5095a066195c..88bf3ae182e5 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -955,18 +955,40 @@ describe('chromium feature', () => { slashes: true }) - function createBrowserWindow ({plugins}) { + function createBrowserWindow ({plugins, preload}) { w = new BrowserWindow({ show: false, webPreferences: { - preload: path.join(fixtures, 'module', 'preload-pdf-loaded.js'), + preload: path.join(fixtures, 'module', preload), plugins: plugins } }) } + function testPDFIsLoadedInSubFrame (page, preloadFile, done) { + const pagePath = url.format({ + pathname: path.join(fixtures, 'pages', page).replace(/\\/g, '/'), + protocol: 'file', + slashes: true + }) + + createBrowserWindow({plugins: true, preload: preloadFile}) + ipcMain.once('pdf-loaded', (event, state) => { + assert.equal(state, 'success') + done() + }) + w.webContents.on('page-title-updated', () => { + const parsedURL = url.parse(w.webContents.getURL(), true) + assert.equal(parsedURL.protocol, 'chrome:') + assert.equal(parsedURL.hostname, 'pdf-viewer') + assert.equal(parsedURL.query.src, pagePath) + assert.equal(w.webContents.getTitle(), 'cat.pdf') + }) + w.webContents.loadURL(pagePath) + } + it('opens when loading a pdf resource as top level navigation', (done) => { - createBrowserWindow({plugins: true}) + createBrowserWindow({plugins: true, preload: 'preload-pdf-loaded.js'}) ipcMain.once('pdf-loaded', (event, state) => { assert.equal(state, 'success') done() @@ -982,7 +1004,7 @@ describe('chromium feature', () => { }) it('opens a pdf link given params, the query string should be escaped', (done) => { - createBrowserWindow({plugins: true}) + createBrowserWindow({plugins: true, preload: 'preload-pdf-loaded.js'}) ipcMain.once('pdf-loaded', (event, state) => { assert.equal(state, 'success') done() @@ -1000,7 +1022,7 @@ describe('chromium feature', () => { }) it('should download a pdf when plugins are disabled', (done) => { - createBrowserWindow({plugins: false}) + createBrowserWindow({plugins: false, preload: 'preload-pdf-loaded.js'}) ipcRenderer.sendSync('set-download-option', false, false) ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) => { assert.equal(state, 'completed') @@ -1013,7 +1035,7 @@ describe('chromium feature', () => { }) it('should not open when pdf is requested as sub resource', (done) => { - createBrowserWindow({plugins: true}) + createBrowserWindow({plugins: true, preload: 'preload-pdf-loaded.js'}) webFrame.registerURLSchemeAsPrivileged('file', { secure: false, bypassCSP: false, @@ -1026,6 +1048,14 @@ describe('chromium feature', () => { done() }).catch((e) => done(e)) }) + + it('opens when loading a pdf resource in a iframe', (done) => { + testPDFIsLoadedInSubFrame('pdf-in-iframe.html', 'preload-pdf-loaded-in-subframe.js', done) + }) + + it('opens when loading a pdf resource in a nested iframe', (done) => { + testPDFIsLoadedInSubFrame('pdf-in-nested-iframe.html', 'preload-pdf-loaded-in-nested-subframe.js', done) + }) }) describe('window.alert(message, title)', () => { diff --git a/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js b/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js new file mode 100644 index 000000000000..a1115f96e675 --- /dev/null +++ b/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js @@ -0,0 +1,15 @@ +const {ipcRenderer} = require('electron') + +document.addEventListener('DOMContentLoaded', (event) => { + var outerFrame = document.getElementById('outer-frame') + if (outerFrame) { + outerFrame.onload = function () { + var pdframe = outerFrame.contentWindow.document.getElementById('pdf-frame') + if (pdframe) { + pdframe.contentWindow.addEventListener('pdf-loaded', (event) => { + ipcRenderer.send('pdf-loaded', event.detail) + }) + } + } + } +}) diff --git a/spec/fixtures/module/preload-pdf-loaded-in-subframe.js b/spec/fixtures/module/preload-pdf-loaded-in-subframe.js new file mode 100644 index 000000000000..63b356821d8a --- /dev/null +++ b/spec/fixtures/module/preload-pdf-loaded-in-subframe.js @@ -0,0 +1,10 @@ +const {ipcRenderer} = require('electron') + +document.addEventListener('DOMContentLoaded', (event) => { + var subframe = document.getElementById('pdf-frame') + if (subframe) { + subframe.contentWindow.addEventListener('pdf-loaded', (event) => { + ipcRenderer.send('pdf-loaded', event.detail) + }) + } +}) diff --git a/spec/fixtures/pages/pdf-in-iframe.html b/spec/fixtures/pages/pdf-in-iframe.html new file mode 100644 index 000000000000..5b656df4c778 --- /dev/null +++ b/spec/fixtures/pages/pdf-in-iframe.html @@ -0,0 +1,6 @@ + + +