Merge pull request #10793 from ahmedmohamedali/master

Add support for pdf in sub frames (https://github.com/electron/electr
This commit is contained in:
Cheng Zhao 2017-11-20 11:37:42 +09:00 committed by GitHub
commit cd5785c410
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 130 additions and 39 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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_;

View file

@ -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)', () => {

View 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)
})
}
}
}
})

View 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)
})
}
})

View file

@ -0,0 +1,6 @@
<html>
<body>
<iframe id="pdf-frame" src="../assets/cat.pdf"/>
</script>
</body>
</html>

View file

@ -0,0 +1,5 @@
<html>
<body>
<iframe id="outer-frame" src="./pdf-in-iframe.html"/>
</body>
</html>

@ -1 +1 @@
Subproject commit 0784acb6519ea45c0cef26d8599fa8c7f6b9c7ca
Subproject commit b0c0a9e10bfac39d6da64a9e66e3509731d6fa69