Merge pull request #10793 from ahmedmohamedali/master
Add support for pdf in sub frames (https://github.com/electron/electr…
This commit is contained in:
commit
cd5785c410
9 changed files with 130 additions and 39 deletions
|
@ -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<net::ClientCertStore>
|
||||
AtomResourceDispatcherHostDelegate::CreateClientCertStore(
|
||||
content::ResourceContext* resource_context) {
|
||||
#if defined(USE_NSS_CERTS)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
|
||||
net::ClientCertStoreNSS::PasswordDelegateFactory()));
|
||||
#elif defined(OS_WIN)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
|
||||
#elif defined(OS_MACOSX)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
|
||||
#elif defined(USE_OPENSSL)
|
||||
return std::unique_ptr<net::ClientCertStore>();
|
||||
#endif
|
||||
#if defined(USE_NSS_CERTS)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
|
||||
net::ClientCertStoreNSS::PasswordDelegateFactory()));
|
||||
#elif defined(OS_WIN)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
|
||||
#elif defined(OS_MACOSX)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
|
||||
#elif defined(USE_OPENSSL)
|
||||
return std::unique_ptr<net::ClientCertStore>();
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<base::Value> initialize_callback_id_;
|
||||
content::StreamInfo* stream_;
|
||||
std::string original_url_;
|
||||
|
|
|
@ -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)', () => {
|
||||
|
|
15
spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js
vendored
Normal file
15
spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js
vendored
Normal file
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
10
spec/fixtures/module/preload-pdf-loaded-in-subframe.js
vendored
Normal file
10
spec/fixtures/module/preload-pdf-loaded-in-subframe.js
vendored
Normal file
|
@ -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)
|
||||
})
|
||||
}
|
||||
})
|
6
spec/fixtures/pages/pdf-in-iframe.html
vendored
Normal file
6
spec/fixtures/pages/pdf-in-iframe.html
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<body>
|
||||
<iframe id="pdf-frame" src="../assets/cat.pdf"/>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
5
spec/fixtures/pages/pdf-in-nested-iframe.html
vendored
Normal file
5
spec/fixtures/pages/pdf-in-nested-iframe.html
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<iframe id="outer-frame" src="./pdf-in-iframe.html"/>
|
||||
</body>
|
||||
</html>
|
2
vendor/libchromiumcontent
vendored
2
vendor/libchromiumcontent
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 0784acb6519ea45c0cef26d8599fa8c7f6b9c7ca
|
||||
Subproject commit b0c0a9e10bfac39d6da64a9e66e3509731d6fa69
|
Loading…
Reference in a new issue