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