1 // Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4
5 #include "libcef/browser/net_service/login_delegate.h"
6
7 #include "libcef/browser/browser_host_base.h"
8 #include "libcef/browser/net_service/browser_urlrequest_impl.h"
9 #include "libcef/browser/thread_util.h"
10
11 #include "base/memory/scoped_refptr.h"
12 #include "base/threading/sequenced_task_runner_handle.h"
13 #include "content/public/browser/global_request_id.h"
14 #include "content/public/browser/web_contents.h"
15
16 namespace net_service {
17
18 namespace {
19
20 class AuthCallbackImpl : public CefAuthCallback {
21 public:
AuthCallbackImpl(base::WeakPtr<LoginDelegate> delegate)22 explicit AuthCallbackImpl(base::WeakPtr<LoginDelegate> delegate)
23 : delegate_(delegate),
24 task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
25
26 AuthCallbackImpl(const AuthCallbackImpl&) = delete;
27 AuthCallbackImpl& operator=(const AuthCallbackImpl&) = delete;
28
~AuthCallbackImpl()29 ~AuthCallbackImpl() override {
30 if (delegate_.MaybeValid()) {
31 // If |delegate_| isn't valid this will be a no-op.
32 task_runner_->PostTask(FROM_HERE,
33 base::BindOnce(&LoginDelegate::Cancel, delegate_));
34 }
35 }
36
Continue(const CefString & username,const CefString & password)37 void Continue(const CefString& username, const CefString& password) override {
38 if (!task_runner_->RunsTasksInCurrentSequence()) {
39 task_runner_->PostTask(
40 FROM_HERE, base::BindOnce(&AuthCallbackImpl::Continue, this, username,
41 password));
42 return;
43 }
44
45 if (delegate_) {
46 delegate_->Continue(username, password);
47 delegate_ = nullptr;
48 }
49 }
50
Cancel()51 void Cancel() override {
52 if (!task_runner_->RunsTasksInCurrentSequence()) {
53 task_runner_->PostTask(FROM_HERE,
54 base::BindOnce(&AuthCallbackImpl::Cancel, this));
55 return;
56 }
57
58 if (delegate_) {
59 delegate_->Cancel();
60 delegate_ = nullptr;
61 }
62 }
63
64 private:
65 base::WeakPtr<LoginDelegate> delegate_;
66 scoped_refptr<base::SequencedTaskRunner> task_runner_;
67
68 IMPLEMENT_REFCOUNTING(AuthCallbackImpl);
69 };
70
RunCallbackOnIOThread(CefRefPtr<CefBrowserHostBase> browser,absl::optional<CefBrowserURLRequest::RequestInfo> url_request_info,const net::AuthChallengeInfo & auth_info,const GURL & origin_url,CefRefPtr<AuthCallbackImpl> callback_impl)71 void RunCallbackOnIOThread(
72 CefRefPtr<CefBrowserHostBase> browser,
73 absl::optional<CefBrowserURLRequest::RequestInfo> url_request_info,
74 const net::AuthChallengeInfo& auth_info,
75 const GURL& origin_url,
76 CefRefPtr<AuthCallbackImpl> callback_impl) {
77 CEF_REQUIRE_IOT();
78
79 // TODO(network): After the old network code path is deleted move this
80 // callback to the BrowserURLRequest's context thread.
81 if (url_request_info) {
82 bool handled = url_request_info->second->GetAuthCredentials(
83 auth_info.is_proxy, auth_info.challenger.host(),
84 auth_info.challenger.port(), auth_info.realm, auth_info.scheme,
85 callback_impl.get());
86 if (handled) {
87 // The user will execute the callback, or the request will be canceled on
88 // AuthCallbackImpl destruction.
89 return;
90 }
91 }
92
93 if (browser) {
94 CefRefPtr<CefClient> client = browser->GetClient();
95 if (client) {
96 CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
97 if (handler) {
98 bool handled = handler->GetAuthCredentials(
99 browser.get(), origin_url.spec(), auth_info.is_proxy,
100 auth_info.challenger.host(), auth_info.challenger.port(),
101 auth_info.realm, auth_info.scheme, callback_impl.get());
102 if (handled) {
103 // The user will execute the callback, or the request will be canceled
104 // on AuthCallbackImpl destruction.
105 return;
106 }
107 }
108 }
109 }
110
111 callback_impl->Cancel();
112 }
113 } // namespace
114
LoginDelegate(const net::AuthChallengeInfo & auth_info,content::WebContents * web_contents,const content::GlobalRequestID & request_id,const GURL & origin_url,LoginAuthRequiredCallback callback)115 LoginDelegate::LoginDelegate(const net::AuthChallengeInfo& auth_info,
116 content::WebContents* web_contents,
117 const content::GlobalRequestID& request_id,
118 const GURL& origin_url,
119 LoginAuthRequiredCallback callback)
120 : callback_(std::move(callback)), weak_ptr_factory_(this) {
121 CEF_REQUIRE_UIT();
122
123 // May be nullptr for requests originating from CefURLRequest.
124 CefRefPtr<CefBrowserHostBase> browser;
125 if (web_contents) {
126 browser = CefBrowserHostBase::GetBrowserForContents(web_contents);
127 }
128
129 // |callback| needs to be executed asynchronously.
130 CEF_POST_TASK(CEF_UIT, base::BindOnce(&LoginDelegate::Start,
131 weak_ptr_factory_.GetWeakPtr(), browser,
132 auth_info, request_id, origin_url));
133 }
134
Continue(const CefString & username,const CefString & password)135 void LoginDelegate::Continue(const CefString& username,
136 const CefString& password) {
137 CEF_REQUIRE_UIT();
138 if (!callback_.is_null()) {
139 std::move(callback_).Run(
140 net::AuthCredentials(username.ToString16(), password.ToString16()));
141 }
142 }
143
Cancel()144 void LoginDelegate::Cancel() {
145 CEF_REQUIRE_UIT();
146 if (!callback_.is_null()) {
147 std::move(callback_).Run(absl::nullopt);
148 }
149 }
150
Start(CefRefPtr<CefBrowserHostBase> browser,const net::AuthChallengeInfo & auth_info,const content::GlobalRequestID & request_id,const GURL & origin_url)151 void LoginDelegate::Start(CefRefPtr<CefBrowserHostBase> browser,
152 const net::AuthChallengeInfo& auth_info,
153 const content::GlobalRequestID& request_id,
154 const GURL& origin_url) {
155 CEF_REQUIRE_UIT();
156
157 auto url_request_info = CefBrowserURLRequest::FromRequestID(request_id);
158
159 if (browser || url_request_info) {
160 // AuthCallbackImpl is bound to the current thread.
161 CefRefPtr<AuthCallbackImpl> callbackImpl =
162 new AuthCallbackImpl(weak_ptr_factory_.GetWeakPtr());
163
164 // Execute callbacks on the IO thread to maintain the "old"
165 // network_delegate callback behaviour.
166 CEF_POST_TASK(CEF_IOT, base::BindOnce(&RunCallbackOnIOThread, browser,
167 url_request_info, auth_info,
168 origin_url, callbackImpl));
169 } else {
170 Cancel();
171 }
172 }
173
174 } // namespace net_service