| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "android_webview/browser/aw_login_delegate.h" |
| |
| #include "android_webview/browser/aw_browser_context.h" |
| #include "base/android/jni_android.h" |
| #include "base/logging.h" |
| #include "base/supports_user_data.h" |
| #include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_request_handler.h" |
| #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/resource_dispatcher_host.h" |
| #include "content/public/browser/resource_request_info.h" |
| #include "content/public/browser/web_contents.h" |
| #include "net/base/auth.h" |
| #include "net/url_request/url_request.h" |
| |
| using namespace base::android; |
| |
| using content::BrowserThread; |
| using content::RenderFrameHost; |
| using content::ResourceDispatcherHost; |
| using content::ResourceRequestInfo; |
| using content::WebContents; |
| using data_reduction_proxy::DataReductionProxyAuthRequestHandler; |
| using data_reduction_proxy::DataReductionProxySettings; |
| |
| namespace { |
| const char* kAuthAttemptsKey = "android_webview_auth_attempts"; |
| |
| class UrlRequestAuthAttemptsData : public base::SupportsUserData::Data { |
| public: |
| UrlRequestAuthAttemptsData() : auth_attempts_(0) { } |
| int auth_attempts_; |
| }; |
| |
| } // namespace |
| |
| namespace android_webview { |
| |
| AwLoginDelegate::AwLoginDelegate(net::AuthChallengeInfo* auth_info, |
| net::URLRequest* request) |
| : auth_info_(auth_info), |
| request_(request), |
| render_process_id_(0), |
| render_frame_id_(0) { |
| ResourceRequestInfo::GetRenderFrameForRequest( |
| request, &render_process_id_, &render_frame_id_); |
| |
| UrlRequestAuthAttemptsData* count = |
| static_cast<UrlRequestAuthAttemptsData*>( |
| request->GetUserData(kAuthAttemptsKey)); |
| |
| if (count == NULL) { |
| count = new UrlRequestAuthAttemptsData(); |
| request->SetUserData(kAuthAttemptsKey, count); |
| } |
| |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::Bind(&AwLoginDelegate::HandleHttpAuthRequestOnUIThread, |
| this, (count->auth_attempts_ == 0))); |
| count->auth_attempts_++; |
| } |
| |
| AwLoginDelegate::~AwLoginDelegate() { |
| // The Auth handler holds a ref count back on |this| object, so it should be |
| // impossible to reach here while this object still owns an auth handler. |
| DCHECK(aw_http_auth_handler_ == NULL); |
| } |
| |
| void AwLoginDelegate::Proceed(const base::string16& user, |
| const base::string16& password) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::Bind(&AwLoginDelegate::ProceedOnIOThread, |
| this, user, password)); |
| } |
| |
| void AwLoginDelegate::Cancel() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::Bind(&AwLoginDelegate::CancelOnIOThread, this)); |
| } |
| |
| void AwLoginDelegate::HandleHttpAuthRequestOnUIThread( |
| bool first_auth_attempt) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| aw_http_auth_handler_.reset(AwHttpAuthHandlerBase::Create( |
| this, auth_info_.get(), first_auth_attempt)); |
| |
| RenderFrameHost* render_frame_host = RenderFrameHost::FromID( |
| render_process_id_, render_frame_id_); |
| WebContents* web_contents = WebContents::FromRenderFrameHost( |
| render_frame_host); |
| AwBrowserContext* browser_context = |
| AwBrowserContext::FromWebContents(web_contents); |
| DataReductionProxySettings* drp_settings = |
| browser_context->GetDataReductionProxySettings(); |
| if (drp_settings && drp_settings->IsDataReductionProxyEnabled()) { |
| // The data reduction proxy auth handler should only be reset on the first |
| // auth attempt, because it maintains internal state to cancel if there have |
| // been too many attempts. |
| if (!drp_auth_handler_.get()) { |
| drp_auth_handler_.reset(new DataReductionProxyAuthRequestHandler( |
| drp_settings)); |
| } |
| DCHECK(drp_auth_handler_.get()); |
| base::string16 user, password; |
| DataReductionProxyAuthRequestHandler::TryHandleResult drp_result = |
| drp_auth_handler_->TryHandleAuthentication( |
| auth_info_.get(), &user, &password); |
| if (drp_result == |
| DataReductionProxyAuthRequestHandler::TRY_HANDLE_RESULT_PROCEED) { |
| Proceed(user, password); |
| return; |
| } |
| if (drp_result == |
| DataReductionProxyAuthRequestHandler::TRY_HANDLE_RESULT_CANCEL) { |
| Cancel(); |
| return; |
| } |
| // Fall through if |drp_result| is IGNORE |
| } |
| |
| if (!aw_http_auth_handler_->HandleOnUIThread(web_contents)) { |
| Cancel(); |
| return; |
| } |
| } |
| |
| void AwLoginDelegate::CancelOnIOThread() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| if (request_) { |
| request_->CancelAuth(); |
| ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_); |
| request_ = NULL; |
| } |
| DeleteAuthHandlerSoon(); |
| } |
| |
| void AwLoginDelegate::ProceedOnIOThread(const base::string16& user, |
| const base::string16& password) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| if (request_) { |
| request_->SetAuth(net::AuthCredentials(user, password)); |
| ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_); |
| request_ = NULL; |
| } |
| DeleteAuthHandlerSoon(); |
| } |
| |
| void AwLoginDelegate::OnRequestCancelled() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| request_ = NULL; |
| DeleteAuthHandlerSoon(); |
| } |
| |
| void AwLoginDelegate::DeleteAuthHandlerSoon() { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::Bind(&AwLoginDelegate::DeleteAuthHandlerSoon, this)); |
| return; |
| } |
| aw_http_auth_handler_.reset(); |
| } |
| |
| } // namespace android_webview |