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 19 using namespace base::android; 20 21 using content::BrowserThread; 22 using content::RenderFrameHost; 23 using content::ResourceDispatcherHost; 24 using content::ResourceRequestInfo; 25 using content::WebContents; 26 27 namespace { 28 const char* kAuthAttemptsKey = "android_webview_auth_attempts"; 29 30 class UrlRequestAuthAttemptsData : public base::SupportsUserData::Data { 31 public: 32 UrlRequestAuthAttemptsData() : auth_attempts_(0) { } 33 int auth_attempts_; 34 }; 35 36 } // namespace 37 38 namespace android_webview { 39 40 AwLoginDelegate::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 64 AwLoginDelegate::~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 70 void 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 78 void AwLoginDelegate::Cancel() { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 80 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 81 base::Bind(&AwLoginDelegate::CancelOnIOThread, this)); 82 } 83 84 void 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 101 void 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 111 void 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 122 void AwLoginDelegate::OnRequestCancelled() { 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 124 request_ = NULL; 125 DeleteAuthHandlerSoon(); 126 } 127 128 void 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