From aed487ef40cff53652d288c243671dabd8a2510c Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 31 Aug 2015 00:22:01 +0530 Subject: [PATCH 1/2] app: add will-download event to defaultSession --- atom/browser/api/atom_api_session.cc | 33 ++++++++++++++++++++++++ atom/browser/api/atom_api_session.h | 8 +++++- atom/browser/api/atom_api_web_contents.h | 2 +- atom/browser/api/lib/app.coffee | 6 +++-- docs/api/app.md | 32 +++++++++++++++++++++++ 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 9961d6cc6601..0b7640e416b5 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -9,6 +9,7 @@ #include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/atom_browser_context.h" +#include "atom/browser/api/atom_api_web_contents.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" @@ -101,6 +102,19 @@ struct Converter { } }; +template<> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + content::DownloadItem* val) { + return mate::ObjectTemplateBuilder(isolate) + .SetValue("url", val->GetURL()) + .SetValue("filename", val->GetSuggestedFilename()) + .SetValue("mimeType", val->GetMimeType()) + .SetValue("hasUserGesture", val->HasUserGesture()) + .Build()->NewInstance(); + } +}; + } // namespace mate namespace atom { @@ -215,9 +229,28 @@ void SetProxyInIO(net::URLRequestContextGetter* getter, Session::Session(AtomBrowserContext* browser_context) : browser_context_(browser_context) { AttachAsUserData(browser_context); + // Observe DownloadManger to get download notifications. + auto download_manager = + content::BrowserContext::GetDownloadManager(browser_context); + download_manager->AddObserver(this); } Session::~Session() { + auto download_manager = + content::BrowserContext::GetDownloadManager(browser_context_); + download_manager->RemoveObserver(this); +} + +void Session::OnDownloadCreated(content::DownloadManager* manager, + content::DownloadItem* item) { + auto web_contents = item->GetWebContents(); + bool prevent_default = Emit("will-download", item, + api::WebContents::CreateFrom(isolate(), + web_contents)); + if (prevent_default) { + item->Cancel(true); + item->Remove(); + } } void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index b353c61c2109..c06348974ff4 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -8,6 +8,7 @@ #include #include "atom/browser/api/trackable_object.h" +#include "content/public/browser/download_manager.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" @@ -27,7 +28,8 @@ class AtomBrowserContext; namespace api { -class Session: public mate::TrackableObject { +class Session: public mate::TrackableObject, + public content::DownloadManager::Observer { public: using ResolveProxyCallback = base::Callback; @@ -41,6 +43,10 @@ class Session: public mate::TrackableObject { explicit Session(AtomBrowserContext* browser_context); ~Session(); + // content::DownloadManager::Observer: + void OnDownloadCreated(content::DownloadManager* manager, + content::DownloadItem* item) override; + // mate::Wrappable implementations: mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 2fbc1d899777..45027309ea65 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -10,8 +10,8 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/common_web_contents_delegate.h" -#include "content/public/common/favicon_url.h" #include "content/public/browser/web_contents_observer.h" +#include "content/public/common/favicon_url.h" #include "native_mate/handle.h" #include "ui/gfx/image/image.h" diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index 3e05106d1927..f71297c596f0 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -32,8 +32,10 @@ app.setAppPath = (path) -> app.getAppPath = -> appPath -# Be compatible with old API. -app.once 'ready', -> @emit 'finish-launching' +app.once 'ready', -> + app.defaultSession.__proto__ = EventEmitter.prototype + # Be compatible with old API. + @emit 'finish-launching' app.terminate = app.quit app.exit = process.exit app.getHomeDir = -> @getPath 'home' diff --git a/docs/api/app.md b/docs/api/app.md index db34d37ec59e..8951adf45cfd 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -330,3 +330,35 @@ Sets the application's [dock menu][dock-menu]. [dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 [tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks + +## `app.defaultSession` + +The default session of the app available once the (ready)[app.md#event-ready] event is fired. + +```javascript +app.on('ready', function() { + var defaultSession = app.defaultSession; +}) +``` + +### Event: 'will-download' + +* `event` Event +* `downloadItem` Object + * `url` String + * `filename` String + * `mimeType` String + * `hasUserGesture` Boolean +* `webContents` (WebContents)[web-contents.md] + +Fired when a download is about to start. Calling `preventDefault()` +will cancel the download. + +```javascript +app.defaultSession.on('will-download', function(e, downloadItem, webContents) { + e.preventDefault(); + require('request')(downloadItem.url, function(data) { + require('fs').writeFileSync('/somewhere', data); + }); +}); +``` From 4062ca5f683bb9a12d9d2ec6209cdff259c059a5 Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 1 Sep 2015 15:32:14 +0530 Subject: [PATCH 2/2] implement wrapSession --- atom/browser/api/atom_api_session.cc | 42 +++++++++++++++++++++++----- atom/browser/api/lib/app.coffee | 15 +++++++--- atom/common/node_bindings.cc | 1 + docs/api/app.md | 32 --------------------- docs/api/session.md | 24 ++++++++++++++++ 5 files changed, 71 insertions(+), 43 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 0b7640e416b5..3ca15ab871fa 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -106,12 +106,12 @@ template<> struct Converter { static v8::Local ToV8(v8::Isolate* isolate, content::DownloadItem* val) { - return mate::ObjectTemplateBuilder(isolate) - .SetValue("url", val->GetURL()) - .SetValue("filename", val->GetSuggestedFilename()) - .SetValue("mimeType", val->GetMimeType()) - .SetValue("hasUserGesture", val->HasUserGesture()) - .Build()->NewInstance(); + mate::Dictionary dict(isolate, v8::Object::New(isolate)); + dict.Set("url", val->GetURL()); + dict.Set("filename", val->GetSuggestedFilename()); + dict.Set("mimeType", val->GetMimeType()); + dict.Set("hasUserGesture", val->HasUserGesture()); + return dict.GetHandle(); } }; @@ -123,6 +123,10 @@ namespace api { namespace { +// The wrapSession funtion which is implemented in JavaScript +using WrapSessionCallback = base::Callback)>; +WrapSessionCallback g_wrap_session; + class ResolveProxyHelper { public: ResolveProxyHelper(AtomBrowserContext* browser_context, @@ -321,9 +325,33 @@ mate::Handle Session::CreateFrom( if (existing) return mate::CreateHandle(isolate, static_cast(existing)); - return mate::CreateHandle(isolate, new Session(browser_context)); + auto handle = mate::CreateHandle(isolate, new Session(browser_context)); + g_wrap_session.Run(handle.ToV8()); + return handle; +} + +void SetWrapSession(const WrapSessionCallback& callback) { + g_wrap_session = callback; +} + +void ClearWrapSession() { + g_wrap_session.Reset(); } } // namespace api } // namespace atom + +namespace { + +void Initialize(v8::Local exports, v8::Local unused, + v8::Local context, void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + mate::Dictionary dict(isolate, exports); + dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession); + dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession); +} + +} // namespace + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize) diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index f71297c596f0..b3446e86e23a 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -1,10 +1,15 @@ EventEmitter = require('events').EventEmitter bindings = process.atomBinding 'app' +sessionBindings = process.atomBinding 'session' app = bindings.app app.__proto__ = EventEmitter.prototype +wrapSession = (session) -> + # session is an Event Emitter. + session.__proto__ = EventEmitter.prototype + app.setApplicationMenu = (menu) -> require('menu').setApplicationMenu menu @@ -32,10 +37,8 @@ app.setAppPath = (path) -> app.getAppPath = -> appPath -app.once 'ready', -> - app.defaultSession.__proto__ = EventEmitter.prototype - # Be compatible with old API. - @emit 'finish-launching' +# Be compatible with old API. +app.once 'ready', -> @emit 'finish-launching' app.terminate = app.quit app.exit = process.exit app.getHomeDir = -> @getPath 'home' @@ -43,5 +46,9 @@ app.getDataPath = -> @getPath 'userData' app.setDataPath = (path) -> @setPath 'userData', path app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments +# Session wrapper. +sessionBindings._setWrapSession wrapSession +process.once 'exit', sessionBindings._clearWrapSession + # Only one App object pemitted. module.exports = app diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 5aed5619f9cf..09666a470b6c 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -40,6 +40,7 @@ REFERENCE_MODULE(atom_browser_power_monitor); REFERENCE_MODULE(atom_browser_power_save_blocker); REFERENCE_MODULE(atom_browser_protocol); REFERENCE_MODULE(atom_browser_global_shortcut); +REFERENCE_MODULE(atom_browser_session); REFERENCE_MODULE(atom_browser_tray); REFERENCE_MODULE(atom_browser_web_contents); REFERENCE_MODULE(atom_browser_web_view_manager); diff --git a/docs/api/app.md b/docs/api/app.md index 8951adf45cfd..db34d37ec59e 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -330,35 +330,3 @@ Sets the application's [dock menu][dock-menu]. [dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 [tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks - -## `app.defaultSession` - -The default session of the app available once the (ready)[app.md#event-ready] event is fired. - -```javascript -app.on('ready', function() { - var defaultSession = app.defaultSession; -}) -``` - -### Event: 'will-download' - -* `event` Event -* `downloadItem` Object - * `url` String - * `filename` String - * `mimeType` String - * `hasUserGesture` Boolean -* `webContents` (WebContents)[web-contents.md] - -Fired when a download is about to start. Calling `preventDefault()` -will cancel the download. - -```javascript -app.defaultSession.on('will-download', function(e, downloadItem, webContents) { - e.preventDefault(); - require('request')(downloadItem.url, function(data) { - require('fs').writeFileSync('/somewhere', data); - }); -}); -``` diff --git a/docs/api/session.md b/docs/api/session.md index 7b0c1b44c7dc..28a0c92ca655 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -13,6 +13,30 @@ win.loadUrl("http://github.com"); var session = win.webContents.session ``` +## Events + +### Event: 'will-download' + +* `event` Event +* `downloadItem` Object + * `url` String + * `filename` String + * `mimeType` String + * `hasUserGesture` Boolean +* `webContents` (WebContents)[web-contents.md] + +Fired when a download is about to start. Calling `preventDefault()` +will cancel the download. + +```javascript +session.on('will-download', function(e, downloadItem, webContents) { + e.preventDefault(); + require('request')(downloadItem.url, function(data) { + require('fs').writeFileSync('/somewhere', data); + }); +}); +``` + ## Methods The `session` object has the following methods: