- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / identity / experimental_web_auth_flow.cc
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 "chrome/browser/extensions/api/identity/experimental_web_auth_flow.h"
6
7 #include "base/location.h"
8 #include "base/message_loop/message_loop.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/browser_navigator.h"
12 #include "content/public/browser/load_notification_details.h"
13 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/resource_request_details.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/page_transition_types.h"
20 #include "ui/base/window_open_disposition.h"
21 #include "url/gurl.h"
22
23 using content::LoadNotificationDetails;
24 using content::NavigationController;
25 using content::RenderViewHost;
26 using content::ResourceRedirectDetails;
27 using content::WebContents;
28 using content::WebContentsObserver;
29
30 namespace extensions {
31
32 ExperimentalWebAuthFlow::ExperimentalWebAuthFlow(
33     Delegate* delegate,
34     Profile* profile,
35     const GURL& provider_url,
36     Mode mode,
37     const gfx::Rect& initial_bounds,
38     chrome::HostDesktopType host_desktop_type)
39     : delegate_(delegate),
40       profile_(profile),
41       provider_url_(provider_url),
42       mode_(mode),
43       initial_bounds_(initial_bounds),
44       host_desktop_type_(host_desktop_type),
45       popup_shown_(false),
46       contents_(NULL) {
47 }
48
49 ExperimentalWebAuthFlow::~ExperimentalWebAuthFlow() {
50   DCHECK(delegate_ == NULL);
51
52   // Stop listening to notifications first since some of the code
53   // below may generate notifications.
54   registrar_.RemoveAll();
55   WebContentsObserver::Observe(NULL);
56
57   if (contents_) {
58     // The popup owns the contents if it was displayed.
59     if (popup_shown_)
60       contents_->Close();
61     else
62       delete contents_;
63   }
64 }
65
66 void ExperimentalWebAuthFlow::Start() {
67   contents_ = CreateWebContents();
68   WebContentsObserver::Observe(contents_);
69
70   NavigationController* controller = &(contents_->GetController());
71
72   // Register for appropriate notifications to intercept navigation to the
73   // redirect URLs.
74   registrar_.Add(
75       this,
76       content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
77       content::Source<WebContents>(contents_));
78
79   controller->LoadURL(
80       provider_url_,
81       content::Referrer(),
82       content::PAGE_TRANSITION_AUTO_TOPLEVEL,
83       std::string());
84 }
85
86 void ExperimentalWebAuthFlow::DetachDelegateAndDelete() {
87   delegate_ = NULL;
88   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
89 }
90
91 WebContents* ExperimentalWebAuthFlow::CreateWebContents() {
92   return WebContents::Create(WebContents::CreateParams(profile_));
93 }
94
95 void ExperimentalWebAuthFlow::ShowAuthFlowPopup() {
96   Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile_,
97                                        host_desktop_type_);
98   browser_params.initial_bounds = initial_bounds_;
99   Browser* browser = new Browser(browser_params);
100   chrome::NavigateParams params(browser, contents_);
101   params.disposition = CURRENT_TAB;
102   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
103   chrome::Navigate(&params);
104   // Observe method and WebContentsObserver::* methods will be called
105   // for varous navigation events. That is where we check for redirect
106   // to the right URL.
107   popup_shown_ = true;
108 }
109
110 void ExperimentalWebAuthFlow::BeforeUrlLoaded(const GURL& url) {
111   if (delegate_)
112     delegate_->OnAuthFlowURLChange(url);
113 }
114
115 void ExperimentalWebAuthFlow::AfterUrlLoaded() {
116   // Do nothing if a popup is already created.
117   if (popup_shown_)
118     return;
119
120   // Report results directly if not in interactive mode.
121   if (mode_ != ExperimentalWebAuthFlow::INTERACTIVE) {
122     if (delegate_) {
123       delegate_->OnAuthFlowFailure(
124           ExperimentalWebAuthFlow::INTERACTION_REQUIRED);
125     }
126     return;
127   }
128
129   // We are in interactive mode and window is not shown yet; show the window.
130   ShowAuthFlowPopup();
131 }
132
133 void ExperimentalWebAuthFlow::Observe(int type,
134                           const content::NotificationSource& source,
135                           const content::NotificationDetails& details) {
136   switch (type) {
137     case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
138       ResourceRedirectDetails* redirect_details =
139           content::Details<ResourceRedirectDetails>(details).ptr();
140       if (redirect_details != NULL)
141         BeforeUrlLoaded(redirect_details->new_url);
142     }
143     break;
144     default:
145       NOTREACHED() << "Got a notification that we did not register for: "
146                    << type;
147       break;
148   }
149 }
150
151 void ExperimentalWebAuthFlow::ProvisionalChangeToMainFrameUrl(
152     const GURL& url,
153     RenderViewHost* render_view_host) {
154   BeforeUrlLoaded(url);
155 }
156
157 void ExperimentalWebAuthFlow::DidStopLoading(RenderViewHost* render_view_host) {
158   AfterUrlLoaded();
159 }
160
161 void ExperimentalWebAuthFlow::WebContentsDestroyed(WebContents* web_contents) {
162   contents_ = NULL;
163   if (delegate_)
164     delegate_->OnAuthFlowFailure(ExperimentalWebAuthFlow::WINDOW_CLOSED);
165 }
166
167 }  // namespace extensions