diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index c79dea9f7c..436d76fb90 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -13,10 +13,11 @@ #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_session.h" +#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/browser.h" -#include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/login_handler.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/node_includes.h" @@ -132,8 +133,6 @@ void OnClientCertificateSelected( v8::Isolate* isolate, std::shared_ptr delegate, mate::Arguments* args) { - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); mate::Dictionary cert_data; if (!(args->Length() == 1 && args->GetNext(&cert_data))) { args->ThrowError(); @@ -147,10 +146,18 @@ void OnClientCertificateSelected( net::X509Certificate::CreateCertificateListFromBytes( encoded_data.data(), encoded_data.size(), net::X509Certificate::FORMAT_AUTO); - delegate->ContinueWithCertificate(certs[0].get()); } +void PassLoginInformation(scoped_refptr login_handler, + mate::Arguments* args) { + base::string16 username, password; + if (args->GetNext(&username) && args->GetNext(&password)) + login_handler->Login(username, password); + else + login_handler->CancelAuth(); +} + } // namespace App::App() { @@ -233,6 +240,16 @@ void App::OnSelectCertificate( cert_request_info->client_certs[0].get()); } +void App::OnLogin(LoginHandler* login_handler) { + bool prevent_default = + Emit("login", base::Bind(&PassLoginInformation, + make_scoped_refptr(login_handler))); + + // Default behavior is to alwasy cancel the auth. + if (!prevent_default) + login_handler->CancelAuth(); +} + void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) { Emit("gpu-process-crashed"); } diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 94cd9bbc68..63cda4447e 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -50,6 +50,7 @@ class App : public mate::EventEmitter, content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, scoped_ptr delegate) override; + void OnLogin(LoginHandler* login_handler) override; // content::GpuDataManagerObserver: void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 79ebe91a87..739921fda9 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -134,6 +134,10 @@ void Browser::ClientCertificateSelector( delegate.Pass())); } +void Browser::RequestLogin(LoginHandler* login_handler) { + FOR_EACH_OBSERVER(BrowserObserver, observers_, OnLogin(login_handler)); +} + void Browser::NotifyAndShutdown() { if (is_shutdown_) return; diff --git a/atom/browser/browser.h b/atom/browser/browser.h index bae281d4d3..8719e18f31 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -29,6 +29,8 @@ class MenuModel; namespace atom { +class LoginHandler; + // This class is used for control application-wide operations. class Browser : public WindowListObserver { public: @@ -122,6 +124,9 @@ class Browser : public WindowListObserver { net::SSLCertRequestInfo* cert_request_info, scoped_ptr delegate); + // Request basic auth login. + void RequestLogin(LoginHandler* login_handler); + void AddObserver(BrowserObserver* obs) { observers_.AddObserver(obs); } diff --git a/atom/browser/browser_observer.h b/atom/browser/browser_observer.h index 45e86e620f..7dccbfbac3 100644 --- a/atom/browser/browser_observer.h +++ b/atom/browser/browser_observer.h @@ -20,6 +20,8 @@ class SSLCertRequestInfo; namespace atom { +class LoginHandler; + class BrowserObserver { public: // The browser is about to close all windows. @@ -57,6 +59,9 @@ class BrowserObserver { net::SSLCertRequestInfo* cert_request_info, scoped_ptr delegate) {} + // The browser requests HTTP login. + virtual void OnLogin(LoginHandler* login_handler) {} + protected: virtual ~BrowserObserver() {} }; diff --git a/atom/browser/login_handler.cc b/atom/browser/login_handler.cc index 1980cc133a..ededcd0c85 100644 --- a/atom/browser/login_handler.cc +++ b/atom/browser/login_handler.cc @@ -4,19 +4,76 @@ #include "atom/browser/login_handler.h" +#include "atom/browser/browser.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/resource_dispatcher_host.h" #include "net/base/auth.h" +#include "net/url_request/url_request.h" + +using content::BrowserThread; namespace atom { +namespace { + +// Helper to remove the ref from an net::URLRequest to the LoginHandler. +// Should only be called from the IO thread, since it accesses an +// net::URLRequest. +void ResetLoginHandlerForRequest(net::URLRequest* request) { + content::ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request); +} + +} // namespace + LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request) - : auth_info_(auth_info), request_(request), weak_factory_(this) { + : auth_info_(auth_info), request_(request) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&Browser::RequestLogin, + base::Unretained(Browser::Get()), + make_scoped_refptr(this))); } LoginHandler::~LoginHandler() { } +void LoginHandler::Login(const base::string16& username, + const base::string16& password) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&LoginHandler::DoLogin, this, username, password)); +} + +void LoginHandler::CancelAuth() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&LoginHandler::DoCancelAuth, this)); +} + void LoginHandler::OnRequestCancelled() { + request_ = nullptr; +} + +void LoginHandler::DoCancelAuth() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (request_) { + request_->CancelAuth(); + // Verify that CancelAuth doesn't destroy the request via our delegate. + DCHECK(request_ != nullptr); + ResetLoginHandlerForRequest(request_); + } +} + +void LoginHandler::DoLogin(const base::string16& username, + const base::string16& password) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (request_) { + request_->SetAuth(net::AuthCredentials(username, password)); + ResetLoginHandlerForRequest(request_); + } } } // namespace atom diff --git a/atom/browser/login_handler.h b/atom/browser/login_handler.h index 421e2e4383..077e4b6cf9 100644 --- a/atom/browser/login_handler.h +++ b/atom/browser/login_handler.h @@ -5,7 +5,7 @@ #ifndef ATOM_BROWSER_LOGIN_HANDLER_H_ #define ATOM_BROWSER_LOGIN_HANDLER_H_ -#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" #include "content/public/browser/resource_dispatcher_host_login_delegate.h" namespace net { @@ -15,10 +15,17 @@ class URLRequest; namespace atom { +// Handles the HTTP basic auth, must be created on IO thread. class LoginHandler : public content::ResourceDispatcherHostLoginDelegate { public: LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request); + // The auth is cancelled, must be called on UI thread. + void CancelAuth(); + + // Login with |username| and |password|, must be called on UI thread. + void Login(const base::string16& username, const base::string16& password); + protected: ~LoginHandler() override; @@ -26,6 +33,10 @@ class LoginHandler : public content::ResourceDispatcherHostLoginDelegate { void OnRequestCancelled() override; private: + // Must be called on IO thread. + void DoCancelAuth(); + void DoLogin(const base::string16& username, const base::string16& password); + // Who/where/what asked for the authentication. scoped_refptr auth_info_; @@ -33,8 +44,6 @@ class LoginHandler : public content::ResourceDispatcherHostLoginDelegate { // This should only be accessed on the IO loop. net::URLRequest* request_; - base::WeakPtrFactory weak_factory_; - DISALLOW_COPY_AND_ASSIGN(LoginHandler); };