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