From 1ff33b7c81f61429c1e0bac5d32458dd3129cae1 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Fri, 6 May 2016 00:04:16 +0530 Subject: [PATCH 1/4] protocol: fix registerStandardSchemes api --- atom/app/atom_content_client.cc | 7 --- atom/browser/api/atom_api_protocol.cc | 4 +- atom/browser/atom_browser_client.cc | 12 ---- atom/browser/atom_browser_client.h | 3 +- atom/common/options_switches.cc | 3 - atom/common/options_switches.h | 1 - spec/api-protocol-spec.js | 80 ++++++++++++++++++++++++++- spec/fixtures/pages/b.html | 2 +- 8 files changed, 83 insertions(+), 29 deletions(-) diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc index 25e9d0f1932a..8f59c77768c6 100644 --- a/atom/app/atom_content_client.cc +++ b/atom/app/atom_content_client.cc @@ -183,13 +183,6 @@ base::string16 AtomContentClient::GetLocalizedString(int message_id) const { void AtomContentClient::AddAdditionalSchemes( std::vector* standard_schemes, std::vector* savable_schemes) { - std::vector schemes; - ConvertStringWithSeparatorToVector(&schemes, ",", - switches::kRegisterStandardSchemes); - if (!schemes.empty()) { - for (const std::string& scheme : schemes) - standard_schemes->push_back({scheme.c_str(), url::SCHEME_WITHOUT_PORT}); - } standard_schemes->push_back({"chrome-extension", url::SCHEME_WITHOUT_PORT}); } diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 3835fac62d7a..115a3c58ad41 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -15,6 +15,7 @@ #include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/node_includes.h" #include "native_mate/dictionary.h" +#include "url/url_util.h" using content::BrowserThread; @@ -31,7 +32,8 @@ Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context) void Protocol::RegisterStandardSchemes( const std::vector& schemes) { - atom::AtomBrowserClient::SetCustomSchemes(schemes); + for (const auto& scheme : schemes) + url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); } void Protocol::RegisterServiceWorkerSchemes( diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index f4add58e3a89..8ecd37a6bca4 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -49,8 +49,6 @@ namespace { // Next navigation should not restart renderer process. bool g_suppress_renderer_process_restart = false; -// Custom schemes to be registered to standard. -std::string g_custom_schemes = ""; // Custom schemes to be registered to handle service worker. std::string g_custom_service_worker_schemes = ""; @@ -61,11 +59,6 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() { g_suppress_renderer_process_restart = true; } -void AtomBrowserClient::SetCustomSchemes( - const std::vector& schemes) { - g_custom_schemes = base::JoinString(schemes, ","); -} - void AtomBrowserClient::SetCustomServiceWorkerSchemes( const std::vector& schemes) { g_custom_service_worker_schemes = base::JoinString(schemes, ","); @@ -153,11 +146,6 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( if (process_type != "renderer") return; - // The registered standard schemes. - if (!g_custom_schemes.empty()) - command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes, - g_custom_schemes); - // The registered service worker schemes. if (!g_custom_service_worker_schemes.empty()) command_line->AppendSwitchASCII(switches::kRegisterServiceWorkerSchemes, diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index 5354e14cc617..ef5fd5a43300 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -36,8 +36,7 @@ class AtomBrowserClient : public brightray::BrowserClient, // Don't force renderer process to restart for once. static void SuppressRendererProcessRestartForOnce(); - // Custom schemes to be registered to standard. - static void SetCustomSchemes(const std::vector& schemes); + // Custom schemes to be registered to handle service worker. static void SetCustomServiceWorkerSchemes( const std::vector& schemes); diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 166942db962c..de130eee13eb 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -125,9 +125,6 @@ const char kPpapiFlashVersion[] = "ppapi-flash-version"; // Disable HTTP cache. const char kDisableHttpCache[] = "disable-http-cache"; -// Register schemes to standard. -const char kRegisterStandardSchemes[] = "register-standard-schemes"; - // Register schemes to handle service worker. const char kRegisterServiceWorkerSchemes[] = "register-service-worker-schemes"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 653f35a812bf..fadde79f18c8 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -70,7 +70,6 @@ extern const char kEnablePlugins[]; extern const char kPpapiFlashPath[]; extern const char kPpapiFlashVersion[]; extern const char kDisableHttpCache[]; -extern const char kRegisterStandardSchemes[]; extern const char kRegisterServiceWorkerSchemes[]; extern const char kSSLVersionFallbackMin[]; extern const char kCipherSuiteBlacklist[]; diff --git a/spec/api-protocol-spec.js b/spec/api-protocol-spec.js index 9f2a25eb4a54..c84d5be25a06 100644 --- a/spec/api-protocol-spec.js +++ b/spec/api-protocol-spec.js @@ -3,6 +3,7 @@ const http = require('http') const path = require('path') const qs = require('querystring') const remote = require('electron').remote +const BrowserWindow = remote.require('electron').BrowserWindow const protocol = remote.require('electron').protocol describe('protocol module', function () { @@ -344,6 +345,7 @@ describe('protocol module', function () { }) }) }) + it('sends object as response', function (done) { var handler = function (request, callback) { callback({ @@ -394,7 +396,7 @@ describe('protocol module', function () { var handler = function (request, callback) { callback(fakeFilePath) } - protocol.registerBufferProtocol(protocolName, handler, function (error) { + protocol.registerFileProtocol(protocolName, handler, function (error) { if (error) { return done(error) } @@ -415,7 +417,7 @@ describe('protocol module', function () { var handler = function (request, callback) { callback(new Date()) } - protocol.registerBufferProtocol(protocolName, handler, function (error) { + protocol.registerFileProtocol(protocolName, handler, function (error) { if (error) { return done(error) } @@ -814,4 +816,78 @@ describe('protocol module', function () { }) }) }) + + describe('protocol.registerStandardSchemes', function () { + const standardScheme = 'app' + const origin = standardScheme + '://fake-host' + const imageURL = origin + '/test.png' + const filePath = path.join(__dirname, 'fixtures', 'pages', 'b.html') + const fileContent = '' + var w = null + var success = null + + before(function () { + protocol.registerStandardSchemes([standardScheme]) + }) + + beforeEach(function () { + w = new BrowserWindow({show: false}) + success = false + }) + + afterEach(function (done) { + protocol.unregisterProtocol(standardScheme, function () { + if (w != null) { + w.destroy() + } + w = null + done() + }) + }) + + it('resolves relative resources', function (done) { + var handler = function (request, callback) { + if (request.url === imageURL) { + success = true + callback() + } else { + callback(filePath) + } + } + protocol.registerFileProtocol(standardScheme, handler, function (error) { + if (error) { + return done(error) + } + w.webContents.on('did-finish-load', function () { + assert(success) + done() + }) + w.loadURL(origin) + }) + }) + + it('resolves absolute resources', function (done) { + var handler = function (request, callback) { + if (request.url === imageURL) { + success = true + callback() + } else { + callback({ + data: fileContent, + mimeType: 'text/html' + }) + } + } + protocol.registerStringProtocol(standardScheme, handler, function (error) { + if (error) { + return done(error) + } + w.webContents.on('did-finish-load', function () { + assert(success) + done() + }) + w.loadURL(origin) + }) + }) + }) }) diff --git a/spec/fixtures/pages/b.html b/spec/fixtures/pages/b.html index 812431f2b45b..d35c863b42c5 100644 --- a/spec/fixtures/pages/b.html +++ b/spec/fixtures/pages/b.html @@ -1,8 +1,8 @@ + - From 0f2ae385ed6379ddabfd6dab4b54b17c0efbac3d Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sun, 8 May 2016 00:13:23 +0530 Subject: [PATCH 2/4] allow protocol module initialization before app ready. * ensure registerStandardSchemes can only be called before app ready * ensure other protocol methods can only be used after app ready --- atom/browser/api/atom_api_protocol.cc | 53 ++++++++++++++++++++++----- atom/browser/api/atom_api_protocol.h | 21 +++++++++-- lib/browser/api/protocol.js | 6 --- spec/api-protocol-spec.js | 6 +-- spec/static/main.js | 5 +++ 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 115a3c58ad41..341baf2d1d1f 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -7,6 +7,7 @@ #include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" +#include "atom/browser/browser.h" #include "atom/browser/net/url_request_async_asar_job.h" #include "atom/browser/net/url_request_buffer_job.h" #include "atom/browser/net/url_request_fetch_job.h" @@ -23,15 +24,38 @@ namespace atom { namespace api { -Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context) - : request_context_getter_(browser_context->GetRequestContext()), - job_factory_(browser_context->job_factory()) { - CHECK(job_factory_); +Protocol::Protocol(v8::Isolate* isolate) + : request_context_getter_(nullptr), + job_factory_(nullptr) { + if (Browser::Get()->is_ready()) { + OnWillFinishLaunching(); + } else { + Browser::Get()->AddObserver(this); + } Init(isolate); } +Protocol::~Protocol() { + Browser::Get()->RemoveObserver(this); +} + +void Protocol::OnWillFinishLaunching() { + auto browser_context = static_cast( + atom::AtomBrowserMainParts::Get()->browser_context()); + request_context_getter_ = browser_context->GetRequestContext(); + job_factory_ = browser_context->job_factory(); + CHECK(job_factory_); +} + void Protocol::RegisterStandardSchemes( const std::vector& schemes) { + if (Browser::Get()->is_ready()) { + isolate()->ThrowException(v8::Exception::Error(mate::StringToV8( + isolate(), + "\"protocol.registerStandardSchemes\" should be called before" + "app is ready"))); + return; + } for (const auto& scheme : schemes) url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); } @@ -45,6 +69,10 @@ void Protocol::UnregisterProtocol( const std::string& scheme, mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); + if (!job_factory_) { + OnIOCompleted(callback, PROTOCOL_FAIL); + return; + } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::UnregisterProtocolInIO, @@ -63,6 +91,10 @@ Protocol::ProtocolError Protocol::UnregisterProtocolInIO( void Protocol::IsProtocolHandled(const std::string& scheme, const BooleanCallback& callback) { + if (!job_factory_) { + callback.Run(false); + return; + } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::IsProtocolHandledInIO, @@ -78,6 +110,10 @@ void Protocol::UninterceptProtocol( const std::string& scheme, mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); + if (!job_factory_) { + OnIOCompleted(callback, PROTOCOL_FAIL); + return; + } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::UninterceptProtocolInIO, @@ -124,9 +160,8 @@ std::string Protocol::ErrorCodeToString(ProtocolError error) { } // static -mate::Handle Protocol::Create( - v8::Isolate* isolate, AtomBrowserContext* browser_context) { - return mate::CreateHandle(isolate, new Protocol(isolate, browser_context)); +mate::Handle Protocol::Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new Protocol(isolate)); } // static @@ -167,9 +202,7 @@ void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); - auto browser_context = static_cast( - atom::AtomBrowserMainParts::Get()->browser_context()); - dict.Set("protocol", atom::api::Protocol::Create(isolate, browser_context)); + dict.Set("protocol", atom::api::Protocol::Create(isolate)); } } // namespace diff --git a/atom/browser/api/atom_api_protocol.h b/atom/browser/api/atom_api_protocol.h index d7fa7f5211f8..80b7006259a9 100644 --- a/atom/browser/api/atom_api_protocol.h +++ b/atom/browser/api/atom_api_protocol.h @@ -9,6 +9,7 @@ #include #include +#include "atom/browser/browser_observer.h" #include "atom/browser/net/atom_url_request_job_factory.h" #include "base/callback.h" #include "base/containers/scoped_ptr_hash_map.h" @@ -30,21 +31,25 @@ class AtomURLRequestJobFactory; namespace api { -class Protocol : public mate::Wrappable { +class Protocol : public mate::Wrappable, + public BrowserObserver { public: using Handler = base::Callback)>; using CompletionCallback = base::Callback)>; using BooleanCallback = base::Callback; - static mate::Handle Create( - v8::Isolate* isolate, AtomBrowserContext* browser_context); + static mate::Handle Create(v8::Isolate* isolate); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context); + explicit Protocol(v8::Isolate* isolate); + ~Protocol(); + + // BrowserObserver: + void OnWillFinishLaunching() override; private: // Possible errors. @@ -101,6 +106,10 @@ class Protocol : public mate::Wrappable { mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); + if (!job_factory_) { + OnIOCompleted(callback, PROTOCOL_FAIL); + return; + } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::RegisterProtocolInIO, @@ -138,6 +147,10 @@ class Protocol : public mate::Wrappable { mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); + if (!job_factory_) { + OnIOCompleted(callback, PROTOCOL_FAIL); + return; + } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::InterceptProtocolInIO, diff --git a/lib/browser/api/protocol.js b/lib/browser/api/protocol.js index dac679f43e44..3c7bed5d1cc5 100644 --- a/lib/browser/api/protocol.js +++ b/lib/browser/api/protocol.js @@ -1,9 +1,3 @@ -const app = require('electron').app - -if (!app.isReady()) { - throw new Error('Can not initialize protocol module before app is ready') -} - const protocol = process.atomBinding('protocol').protocol // Warn about removed APIs. diff --git a/spec/api-protocol-spec.js b/spec/api-protocol-spec.js index c84d5be25a06..2a1d158c3dfd 100644 --- a/spec/api-protocol-spec.js +++ b/spec/api-protocol-spec.js @@ -818,7 +818,7 @@ describe('protocol module', function () { }) describe('protocol.registerStandardSchemes', function () { - const standardScheme = 'app' + const standardScheme = remote.getGlobal('standardScheme') const origin = standardScheme + '://fake-host' const imageURL = origin + '/test.png' const filePath = path.join(__dirname, 'fixtures', 'pages', 'b.html') @@ -826,10 +826,6 @@ describe('protocol module', function () { var w = null var success = null - before(function () { - protocol.registerStandardSchemes([standardScheme]) - }) - beforeEach(function () { w = new BrowserWindow({show: false}) success = false diff --git a/spec/static/main.js b/spec/static/main.js index 025ff394bc66..33c3bb48136a 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -6,6 +6,7 @@ const app = electron.app const ipcMain = electron.ipcMain const dialog = electron.dialog const BrowserWindow = electron.BrowserWindow +const protocol = electron.protocol const fs = require('fs') const path = require('path') @@ -71,6 +72,10 @@ if (global.isCi) { }) } +// Register app as standard scheme. +global.standardScheme = 'app' +protocol.registerStandardSchemes([global.standardScheme]) + app.on('window-all-closed', function () { app.quit() }) From 9c71c9fa6abaa98e751d31e5d317cbe65e1fe533 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sun, 8 May 2016 01:31:04 +0530 Subject: [PATCH 3/4] fix docs and spec --- atom/browser/api/atom_api_protocol.cc | 2 +- docs/api/protocol.md | 14 ++++++++------ spec/api-protocol-spec.js | 6 ++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 341baf2d1d1f..20667ffd3a04 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -52,7 +52,7 @@ void Protocol::RegisterStandardSchemes( if (Browser::Get()->is_ready()) { isolate()->ThrowException(v8::Exception::Error(mate::StringToV8( isolate(), - "\"protocol.registerStandardSchemes\" should be called before" + "protocol.registerStandardSchemes should be called before" "app is ready"))); return; } diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 9474a4539a70..ab0bd7578894 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -7,11 +7,10 @@ An example of implementing a protocol that has the same effect as the ```javascript const electron = require('electron'); -const { app } = electron; +const { app, protocol } = electron; const path = require('path'); app.on('ready', function() { - const { protocol } = electron; protocol.registerFileProtocol('atom', function(request, callback) { const url = request.url.substr(7); callback({path: path.normalize(__dirname + '/' + url)}); @@ -21,9 +20,8 @@ app.on('ready', function() { }); }); ``` - -**Note:** This module can only be used after the `ready` event in the `app` -module is emitted. +**Note:** All methods unless specified can only be used after the `ready` +event in the `app` module is emitted. ## Methods @@ -35,7 +33,11 @@ The `protocol` module has the following methods: A standard `scheme` adheres to what RFC 3986 calls [generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3). This -includes `file:` and `filesystem:`. +includes `file:`, `filesystem:`, `http` etc. Registering a scheme as standard, will +allow relative and absolute resources to be resolved correctly when served. + +**Note:** This method can only be used before the `ready` event in the +`app` module is emitted. ### `protocol.registerServiceWorkerSchemes(schemes)` diff --git a/spec/api-protocol-spec.js b/spec/api-protocol-spec.js index 2a1d158c3dfd..cfbbc6608e06 100644 --- a/spec/api-protocol-spec.js +++ b/spec/api-protocol-spec.js @@ -841,6 +841,12 @@ describe('protocol module', function () { }) }) + it('throws when called after ready event', function () { + assert.throws(function () { + protocol.registerStandardSchemes(['some-scheme']) + }, 'protocol.registerStandardSchemes should be called before app is ready') + }) + it('resolves relative resources', function (done) { var handler = function (request, callback) { if (request.url === imageURL) { From 70dac71639f6f0104601eab289364853b73a1be6 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sun, 8 May 2016 16:44:14 +0530 Subject: [PATCH 4/4] delay protocol object creation --- atom/browser/api/atom_api_protocol.cc | 71 ++++++++------------------- atom/browser/api/atom_api_protocol.h | 24 ++------- lib/browser/api/protocol.js | 35 +++++++++---- lib/browser/chrome-extension.js | 7 +-- 4 files changed, 52 insertions(+), 85 deletions(-) diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 20667ffd3a04..226f689d32de 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -7,7 +7,6 @@ #include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/browser.h" #include "atom/browser/net/url_request_async_asar_job.h" #include "atom/browser/net/url_request_buffer_job.h" #include "atom/browser/net/url_request_fetch_job.h" @@ -24,40 +23,11 @@ namespace atom { namespace api { -Protocol::Protocol(v8::Isolate* isolate) - : request_context_getter_(nullptr), - job_factory_(nullptr) { - if (Browser::Get()->is_ready()) { - OnWillFinishLaunching(); - } else { - Browser::Get()->AddObserver(this); - } - Init(isolate); -} - -Protocol::~Protocol() { - Browser::Get()->RemoveObserver(this); -} - -void Protocol::OnWillFinishLaunching() { - auto browser_context = static_cast( - atom::AtomBrowserMainParts::Get()->browser_context()); - request_context_getter_ = browser_context->GetRequestContext(); - job_factory_ = browser_context->job_factory(); +Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context) + : request_context_getter_(browser_context->GetRequestContext()), + job_factory_(browser_context->job_factory()) { CHECK(job_factory_); -} - -void Protocol::RegisterStandardSchemes( - const std::vector& schemes) { - if (Browser::Get()->is_ready()) { - isolate()->ThrowException(v8::Exception::Error(mate::StringToV8( - isolate(), - "protocol.registerStandardSchemes should be called before" - "app is ready"))); - return; - } - for (const auto& scheme : schemes) - url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); + Init(isolate); } void Protocol::RegisterServiceWorkerSchemes( @@ -69,10 +39,6 @@ void Protocol::UnregisterProtocol( const std::string& scheme, mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); - if (!job_factory_) { - OnIOCompleted(callback, PROTOCOL_FAIL); - return; - } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::UnregisterProtocolInIO, @@ -91,10 +57,6 @@ Protocol::ProtocolError Protocol::UnregisterProtocolInIO( void Protocol::IsProtocolHandled(const std::string& scheme, const BooleanCallback& callback) { - if (!job_factory_) { - callback.Run(false); - return; - } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::IsProtocolHandledInIO, @@ -110,10 +72,6 @@ void Protocol::UninterceptProtocol( const std::string& scheme, mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); - if (!job_factory_) { - OnIOCompleted(callback, PROTOCOL_FAIL); - return; - } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::UninterceptProtocolInIO, @@ -160,15 +118,15 @@ std::string Protocol::ErrorCodeToString(ProtocolError error) { } // static -mate::Handle Protocol::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new Protocol(isolate)); +mate::Handle Protocol::Create( + v8::Isolate* isolate, AtomBrowserContext* browser_context) { + return mate::CreateHandle(isolate, new Protocol(isolate, browser_context)); } // static void Protocol::BuildPrototype( v8::Isolate* isolate, v8::Local prototype) { mate::ObjectTemplateBuilder(isolate, prototype) - .SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes) .SetMethod("registerServiceWorkerSchemes", &Protocol::RegisterServiceWorkerSchemes) .SetMethod("registerStringProtocol", @@ -198,11 +156,24 @@ void Protocol::BuildPrototype( namespace { +void RegisterStandardSchemes( + const std::vector& schemes) { + for (const auto& scheme : schemes) + url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); +} + +mate::Handle CreateProtocol(v8::Isolate* isolate) { + auto browser_context = static_cast( + atom::AtomBrowserMainParts::Get()->browser_context()); + return atom::api::Protocol::Create(isolate, browser_context); +} + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); - dict.Set("protocol", atom::api::Protocol::Create(isolate)); + dict.SetMethod("createProtocolObject", base::Bind(&CreateProtocol, isolate)); + dict.SetMethod("registerStandardSchemes", &RegisterStandardSchemes); } } // namespace diff --git a/atom/browser/api/atom_api_protocol.h b/atom/browser/api/atom_api_protocol.h index 80b7006259a9..19fca9ac81bd 100644 --- a/atom/browser/api/atom_api_protocol.h +++ b/atom/browser/api/atom_api_protocol.h @@ -9,7 +9,6 @@ #include #include -#include "atom/browser/browser_observer.h" #include "atom/browser/net/atom_url_request_job_factory.h" #include "base/callback.h" #include "base/containers/scoped_ptr_hash_map.h" @@ -31,25 +30,21 @@ class AtomURLRequestJobFactory; namespace api { -class Protocol : public mate::Wrappable, - public BrowserObserver { +class Protocol : public mate::Wrappable { public: using Handler = base::Callback)>; using CompletionCallback = base::Callback)>; using BooleanCallback = base::Callback; - static mate::Handle Create(v8::Isolate* isolate); + static mate::Handle Create( + v8::Isolate* isolate, AtomBrowserContext* browser_context); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - explicit Protocol(v8::Isolate* isolate); - ~Protocol(); - - // BrowserObserver: - void OnWillFinishLaunching() override; + Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context); private: // Possible errors. @@ -93,9 +88,6 @@ class Protocol : public mate::Wrappable, DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler); }; - // Register schemes to standard scheme list. - void RegisterStandardSchemes(const std::vector& schemes); - // Register schemes that can handle service worker. void RegisterServiceWorkerSchemes(const std::vector& schemes); @@ -106,10 +98,6 @@ class Protocol : public mate::Wrappable, mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); - if (!job_factory_) { - OnIOCompleted(callback, PROTOCOL_FAIL); - return; - } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::RegisterProtocolInIO, @@ -147,10 +135,6 @@ class Protocol : public mate::Wrappable, mate::Arguments* args) { CompletionCallback callback; args->GetNext(&callback); - if (!job_factory_) { - OnIOCompleted(callback, PROTOCOL_FAIL); - return; - } content::BrowserThread::PostTaskAndReplyWithResult( content::BrowserThread::IO, FROM_HERE, base::Bind(&Protocol::InterceptProtocolInIO, diff --git a/lib/browser/api/protocol.js b/lib/browser/api/protocol.js index 3c7bed5d1cc5..2507acddc83d 100644 --- a/lib/browser/api/protocol.js +++ b/lib/browser/api/protocol.js @@ -1,4 +1,6 @@ -const protocol = process.atomBinding('protocol').protocol +const app = require('electron').app +const {createProtocolObject, registerStandardSchemes} = process.atomBinding('protocol') +let protocol = null // Warn about removed APIs. var logAndThrow = function (callback, message) { @@ -10,16 +12,29 @@ var logAndThrow = function (callback, message) { } } -protocol.registerProtocol = function (scheme, handler, callback) { - return logAndThrow(callback, 'registerProtocol API has been replaced by the register[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.') +exports.registerStandardSchemes = function (schemes) { + if (app.isReady()) { + throw new Error('protocol.registerStandardSchemes should be called before app is ready') + } + registerStandardSchemes(schemes) } -protocol.isHandledProtocol = function (scheme, callback) { - return logAndThrow(callback, 'isHandledProtocol API has been replaced by isProtocolHandled.') -} +app.once('ready', function () { + protocol = createProtocolObject() + // Be compatible with old APIs. + protocol.registerProtocol = function (scheme, handler, callback) { + return logAndThrow(callback, 'registerProtocol API has been replaced by the register[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.') + } -protocol.interceptProtocol = function (scheme, handler, callback) { - return logAndThrow(callback, 'interceptProtocol API has been replaced by the intercept[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.') -} + protocol.isHandledProtocol = function (scheme, callback) { + return logAndThrow(callback, 'isHandledProtocol API has been replaced by isProtocolHandled.') + } -module.exports = protocol + protocol.interceptProtocol = function (scheme, handler, callback) { + return logAndThrow(callback, 'interceptProtocol API has been replaced by the intercept[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.') + } + + for (let method in protocol) { + exports[method] = protocol[method].bind(protocol) + } +}) diff --git a/lib/browser/chrome-extension.js b/lib/browser/chrome-extension.js index 562e77a11509..9da12720ae30 100644 --- a/lib/browser/chrome-extension.js +++ b/lib/browser/chrome-extension.js @@ -1,5 +1,4 @@ -const electron = require('electron') -const app = electron.app +const {app, protocol, BrowserWindow} = require('electron') const fs = require('fs') const path = require('path') const url = require('url') @@ -70,9 +69,7 @@ app.on('will-quit', function () { // We can not use protocol or BrowserWindow until app is ready. app.once('ready', function () { - var BrowserWindow, chromeExtensionHandler, i, init, len, protocol, srcDirectory - protocol = electron.protocol - BrowserWindow = electron.BrowserWindow + var chromeExtensionHandler, i, init, len, srcDirectory // Load persisted extensions. loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')