OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "services/authenticating_url_loader/authenticating_url_loader_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "mojo/services/network/public/interfaces/network_service.mojom.h" | |
10 | |
11 namespace mojo { | |
12 | |
13 AuthenticatingURLLoaderImpl::AuthenticatingURLLoaderImpl( | |
14 InterfaceRequest<AuthenticatingURLLoader> request, | |
15 AuthenticatingURLLoaderFactoryImpl* factory) | |
16 : binding_(this, request.Pass()), | |
17 factory_(factory), | |
18 request_authorization_state_(REQUEST_INITIAL) { | |
19 binding_.set_error_handler(this); | |
20 } | |
21 | |
22 AuthenticatingURLLoaderImpl::~AuthenticatingURLLoaderImpl() { | |
23 } | |
24 | |
25 void AuthenticatingURLLoaderImpl::Start( | |
26 URLRequestPtr request, | |
27 const Callback<void(URLResponsePtr)>& callback) { | |
28 // TODO(blundell): If we need to handle requests with bodies, we'll need to | |
29 // do something here. | |
30 if (request->body) { | |
31 LOG(ERROR) | |
32 << "Cannot pass a request to AuthenticatingURLLoader that has a body"; | |
33 callback.Run(nullptr); | |
34 return; | |
35 } | |
36 url_ = GURL(request->url); | |
37 auto_follow_redirects_ = request->auto_follow_redirects; | |
38 bypass_cache_ = request->bypass_cache; | |
39 headers_ = request->headers.Clone(); | |
40 pending_request_callback_ = callback; | |
41 std::string token = factory_->GetCachedToken(url_); | |
42 if (token != "") { | |
43 auto auth_header = HttpHeader::New(); | |
44 auth_header->name = "Authorization"; | |
45 auth_header->value = "Bearer " + token; | |
46 request->headers.push_back(auth_header.Pass()); | |
47 } | |
48 StartNetworkRequest(request.Pass()); | |
49 } | |
50 | |
51 void AuthenticatingURLLoaderImpl::FollowRedirect( | |
52 const Callback<void(URLResponsePtr)>& callback) { | |
53 mojo::String error; | |
54 | |
55 if (!url_.is_valid() || !url_loader_) { | |
56 error = "No redirect to follow"; | |
57 } | |
58 | |
59 if (auto_follow_redirects_) { | |
60 error = | |
61 "FollowRedirect() should not be " | |
62 "called when auto_follow_redirects has been set"; | |
63 } | |
64 | |
65 if (request_authorization_state_ != REQUEST_INITIAL) { | |
66 error = "Not in the right state to follow a redirect"; | |
67 } | |
68 | |
69 if (!error.is_null()) { | |
70 LOG(ERROR) << "AuthenticatingURLLoader: " << error; | |
71 callback.Run(nullptr); | |
72 return; | |
73 } | |
74 | |
75 pending_request_callback_ = callback; | |
76 FollowRedirectInternal(); | |
77 } | |
78 | |
79 void AuthenticatingURLLoaderImpl::StartNetworkRequest(URLRequestPtr request) { | |
80 factory_->network_service()->CreateURLLoader(mojo::GetProxy(&url_loader_)); | |
81 url_loader_->Start(request.Pass(), | |
82 base::Bind(&AuthenticatingURLLoaderImpl::OnLoadComplete, | |
83 base::Unretained(this))); | |
84 } | |
85 | |
86 void AuthenticatingURLLoaderImpl::OnConnectionError() { | |
87 factory_->OnURLLoaderError(this); | |
88 // The factory deleted this object. | |
89 } | |
90 | |
91 void AuthenticatingURLLoaderImpl::OnLoadComplete(URLResponsePtr response) { | |
92 if (response->redirect_url) { | |
93 url_ = GURL(response->redirect_url); | |
94 request_authorization_state_ = REQUEST_INITIAL; | |
95 | |
96 if (auto_follow_redirects_) { | |
97 FollowRedirectInternal(); | |
98 } else { | |
99 // NOTE: We do not reset |url_loader_| here as it will be needed if the | |
100 // client calls |FollowRedirect()|. | |
101 pending_request_callback_.Run(response.Pass()); | |
102 } | |
103 return; | |
104 } | |
105 | |
106 url_loader_.reset(); | |
107 | |
108 if (response->status_code != 401 || | |
109 request_authorization_state_ == REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN) { | |
110 pending_request_callback_.Run(response.Pass()); | |
111 return; | |
112 } | |
113 | |
114 pending_response_ = response.Pass(); | |
115 | |
116 DCHECK(request_authorization_state_ == REQUEST_INITIAL || | |
117 request_authorization_state_ == | |
118 REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN); | |
119 if (request_authorization_state_ == REQUEST_INITIAL) { | |
120 request_authorization_state_ = REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN; | |
121 } else { | |
122 request_authorization_state_ = REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN; | |
123 } | |
124 factory_->RetrieveToken( | |
125 url_, base::Bind(&AuthenticatingURLLoaderImpl::OnOAuth2TokenReceived, | |
126 base::Unretained(this))); | |
127 return; | |
128 } | |
129 | |
130 void AuthenticatingURLLoaderImpl::FollowRedirectInternal() { | |
131 DCHECK(url_.is_valid()); | |
132 DCHECK(url_loader_); | |
133 DCHECK(request_authorization_state_ == REQUEST_INITIAL); | |
134 | |
135 url_loader_->FollowRedirect(base::Bind( | |
136 &AuthenticatingURLLoaderImpl::OnLoadComplete, base::Unretained(this))); | |
137 } | |
138 | |
139 void AuthenticatingURLLoaderImpl::OnOAuth2TokenReceived(std::string token) { | |
140 if (token.empty()) { | |
141 LOG(ERROR) << "Error while getting token"; | |
142 pending_request_callback_.Run(pending_response_.Pass()); | |
143 return; | |
144 } | |
145 | |
146 auto auth_header = HttpHeader::New(); | |
147 auth_header->name = "Authorization"; | |
148 auth_header->value = "Bearer " + token; | |
149 Array<HttpHeaderPtr> headers; | |
150 if (headers_) | |
151 headers = headers_.Clone(); | |
152 headers.push_back(auth_header.Pass()); | |
153 | |
154 URLRequestPtr request(mojo::URLRequest::New()); | |
155 request->url = url_.spec(); | |
156 request->auto_follow_redirects = false; | |
157 request->bypass_cache = bypass_cache_; | |
158 request->headers = headers.Pass(); | |
159 | |
160 StartNetworkRequest(request.Pass()); | |
161 } | |
162 | |
163 } // namespace mojo | |
OLD | NEW |