1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "android_webview/browser/aw_login_delegate.h" 6 7#include "android_webview/browser/aw_browser_context.h" 8#include "base/android/jni_android.h" 9#include "base/logging.h" 10#include "base/supports_user_data.h" 11#include "content/public/browser/browser_thread.h" 12#include "content/public/browser/render_frame_host.h" 13#include "content/public/browser/resource_dispatcher_host.h" 14#include "content/public/browser/resource_request_info.h" 15#include "content/public/browser/web_contents.h" 16#include "net/base/auth.h" 17#include "net/url_request/url_request.h" 18 19using namespace base::android; 20 21using content::BrowserThread; 22using content::RenderFrameHost; 23using content::ResourceDispatcherHost; 24using content::ResourceRequestInfo; 25using content::WebContents; 26 27namespace { 28const char* kAuthAttemptsKey = "android_webview_auth_attempts"; 29 30class UrlRequestAuthAttemptsData : public base::SupportsUserData::Data { 31 public: 32 UrlRequestAuthAttemptsData() : auth_attempts_(0) { } 33 int auth_attempts_; 34}; 35 36} // namespace 37 38namespace android_webview { 39 40AwLoginDelegate::AwLoginDelegate(net::AuthChallengeInfo* auth_info, 41 net::URLRequest* request) 42 : auth_info_(auth_info), 43 request_(request), 44 render_process_id_(0), 45 render_frame_id_(0) { 46 ResourceRequestInfo::GetRenderFrameForRequest( 47 request, &render_process_id_, &render_frame_id_); 48 49 UrlRequestAuthAttemptsData* count = 50 static_cast<UrlRequestAuthAttemptsData*>( 51 request->GetUserData(kAuthAttemptsKey)); 52 53 if (count == NULL) { 54 count = new UrlRequestAuthAttemptsData(); 55 request->SetUserData(kAuthAttemptsKey, count); 56 } 57 58 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 59 base::Bind(&AwLoginDelegate::HandleHttpAuthRequestOnUIThread, 60 this, (count->auth_attempts_ == 0))); 61 count->auth_attempts_++; 62} 63 64AwLoginDelegate::~AwLoginDelegate() { 65 // The Auth handler holds a ref count back on |this| object, so it should be 66 // impossible to reach here while this object still owns an auth handler. 67 DCHECK(!aw_http_auth_handler_); 68} 69 70void AwLoginDelegate::Proceed(const base::string16& user, 71 const base::string16& password) { 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 73 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 74 base::Bind(&AwLoginDelegate::ProceedOnIOThread, 75 this, user, password)); 76} 77 78void AwLoginDelegate::Cancel() { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 80 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 81 base::Bind(&AwLoginDelegate::CancelOnIOThread, this)); 82} 83 84void AwLoginDelegate::HandleHttpAuthRequestOnUIThread( 85 bool first_auth_attempt) { 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 87 88 aw_http_auth_handler_.reset(AwHttpAuthHandlerBase::Create( 89 this, auth_info_.get(), first_auth_attempt)); 90 91 RenderFrameHost* render_frame_host = RenderFrameHost::FromID( 92 render_process_id_, render_frame_id_); 93 WebContents* web_contents = WebContents::FromRenderFrameHost( 94 render_frame_host); 95 if (!aw_http_auth_handler_->HandleOnUIThread(web_contents)) { 96 Cancel(); 97 return; 98 } 99} 100 101void AwLoginDelegate::CancelOnIOThread() { 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 103 if (request_) { 104 request_->CancelAuth(); 105 ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_); 106 request_ = NULL; 107 } 108 DeleteAuthHandlerSoon(); 109} 110 111void AwLoginDelegate::ProceedOnIOThread(const base::string16& user, 112 const base::string16& password) { 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 114 if (request_) { 115 request_->SetAuth(net::AuthCredentials(user, password)); 116 ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_); 117 request_ = NULL; 118 } 119 DeleteAuthHandlerSoon(); 120} 121 122void AwLoginDelegate::OnRequestCancelled() { 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 124 request_ = NULL; 125 DeleteAuthHandlerSoon(); 126} 127 128void AwLoginDelegate::DeleteAuthHandlerSoon() { 129 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 130 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 131 base::Bind(&AwLoginDelegate::DeleteAuthHandlerSoon, this)); 132 return; 133 } 134 aw_http_auth_handler_.reset(); 135} 136 137} // namespace android_webview 138