OLD | NEW |
(Empty) | |
| 1 // Copyright 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/chrome_to_mobile/common/cloud_print_request_impl.h" |
| 6 |
| 7 #include "base/memory/ref_counted.h" |
| 8 #include "chrome/browser/signin/oauth2_token_service.h" |
| 9 #include "chrome/common/cloud_print/cloud_print_consts.h" |
| 10 #include "chrome/common/cloud_print/cloud_print_helpers.h" |
| 11 #include "google_apis/gaia/google_service_auth_error.h" |
| 12 #include "google_apis/gaia/oauth2_access_token_consumer.h" |
| 13 #include "googleurl/src/gurl.h" |
| 14 #include "net/base/load_flags.h" |
| 15 #include "net/http/http_response_headers.h" |
| 16 #include "net/http/http_status_code.h" |
| 17 #include "net/url_request/url_fetcher.h" |
| 18 #include "net/url_request/url_request_context_getter.h" |
| 19 #include "net/url_request/url_request_status.h" |
| 20 |
| 21 namespace { |
| 22 |
| 23 // The OAuth2 scope of the google cloud print server. |
| 24 const char kCloudPrintOAuthScope[] = |
| 25 "https://www.googleapis.com/auth/cloudprint"; |
| 26 |
| 27 // Returns a |GURL| built from |origin_url| and the information required by |
| 28 // cloud print server for all the cloud print requests. |
| 29 GURL PrepareURL(const GURL& origin_url, |
| 30 const std::string& cloud_print_client_id) { |
| 31 std::string query = "client=" + cloud_print_client_id; |
| 32 if (origin_url.has_query()) |
| 33 query = origin_url.query() + "&" + query; |
| 34 GURL::Replacements replacements; |
| 35 replacements.SetQueryStr(query); |
| 36 return origin_url.ReplaceComponents(replacements); |
| 37 } |
| 38 |
| 39 // Returns a |std::string| that includes the required request headers by cloud |
| 40 // printer server, |oauth2_access_token| and |additional_headers|. |
| 41 std::string GenerateCloudPrintFetcherHeaders( |
| 42 const std::string& oauth2_access_token, |
| 43 const std::string& additional_headers) { |
| 44 std::string headers; |
| 45 if (!oauth2_access_token.empty()) { |
| 46 headers = "Authorization: OAuth "; |
| 47 headers += oauth2_access_token; |
| 48 headers += "\r\n"; |
| 49 } |
| 50 headers += cloud_print::kChromeCloudPrintProxyHeader; |
| 51 |
| 52 if (!additional_headers.empty()) { |
| 53 headers += "\r\n"; |
| 54 headers += additional_headers; |
| 55 } |
| 56 return headers; |
| 57 } |
| 58 |
| 59 // Creates a |net::URLFetcher| at cloud print |url| with authentication |
| 60 // |oauth2_access_token|. It is sent with the headers required by |
| 61 // cloud print server and |additional_header|. The request is of type |
| 62 // |request_type|; if it is a POST request, mime type and post data are given by |
| 63 // |post_data_mime_type| and |post_data|. The request is sent in the request |
| 64 // context obtained by |request_context_getter|. |
| 65 net::URLFetcher* CreateCloudPrintURLFetcher( |
| 66 const GURL& url, |
| 67 const std::string& oauth2_access_token, |
| 68 const std::string& additional_headers, |
| 69 net::URLFetcher::RequestType request_type, |
| 70 std::string post_data_mime_type, |
| 71 std::string post_data, |
| 72 net::URLRequestContextGetter* request_context_getter, |
| 73 net::URLFetcherDelegate* delegate) { |
| 74 net::URLFetcher* request = net::URLFetcher::Create( |
| 75 0, url, request_type, delegate); |
| 76 request->SetRequestContext(request_context_getter); |
| 77 request->SetExtraRequestHeaders(GenerateCloudPrintFetcherHeaders( |
| 78 oauth2_access_token, additional_headers)); |
| 79 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 80 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 81 if (request_type == net::URLFetcher::POST) |
| 82 request->SetUploadData(post_data_mime_type, post_data); |
| 83 return request; |
| 84 } |
| 85 |
| 86 } // namespace |
| 87 |
| 88 namespace chrome_to_mobile { |
| 89 |
| 90 // Class that handles cloud print requests authenticated with oauth2 refresh |
| 91 // tokens. It calls back its owner when the request completes; it can be deleted |
| 92 // at any time and once it is deleted before the request completes, its owner |
| 93 // will not be called back. |
| 94 class CloudPrintRequestImpl::Fetcher : public OAuth2AccessTokenConsumer, |
| 95 public net::URLFetcherDelegate { |
| 96 public: |
| 97 Fetcher(const GURL& url, |
| 98 const std::string& additional_headers, |
| 99 const net::URLFetcher::RequestType& request_type, |
| 100 const std::string& post_data_mime_type, |
| 101 const std::string& post_data, |
| 102 net::URLRequestContextGetter* request_context_getter, |
| 103 CloudPrintRequestImpl* owner); |
| 104 ~Fetcher(); |
| 105 |
| 106 // Starts the request authenticated by |oauth2_refrech_token| |
| 107 // This method starts with fetching an oauth2 access token using |
| 108 // |oauth2_token_service| with |oauth2_refresh_token|. If it fails to |
| 109 // obtain an oauth2 access token, |owner_| will be called back; otherwise it |
| 110 // continues to send request to cloud printer server and |owner_| will be |
| 111 // called back when the request completes. |
| 112 void Start(OAuth2TokenService* oauth2_token_service); |
| 113 |
| 114 protected: |
| 115 // |OAuth2AccessTokenConsumer| |
| 116 virtual void OnGetTokenSuccess(const std::string& access_token, |
| 117 const base::Time& expiration_date) OVERRIDE; |
| 118 virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; |
| 119 // |net::URLFetcherDelegate| |
| 120 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; |
| 121 |
| 122 private: |
| 123 friend CloudPrintRequestImpl; |
| 124 |
| 125 const GURL url_; |
| 126 const std::string additional_headers_; |
| 127 const net::URLFetcher::RequestType request_type_; |
| 128 const std::string post_data_mime_type_; |
| 129 const std::string post_data_; |
| 130 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| 131 CloudPrintRequestImpl* const owner_; |
| 132 |
| 133 scoped_ptr<OAuth2TokenService::Request> oauth2_access_token_request_; |
| 134 scoped_ptr<net::URLFetcher> cloud_print_request_; |
| 135 }; |
| 136 |
| 137 CloudPrintRequestImpl::Fetcher::Fetcher( |
| 138 const GURL& url, |
| 139 const std::string& additional_headers, |
| 140 const net::URLFetcher::RequestType& request_type, |
| 141 const std::string& post_data_mime_type, |
| 142 const std::string& post_data, |
| 143 net::URLRequestContextGetter* request_context_getter, |
| 144 CloudPrintRequestImpl* owner) |
| 145 : url_(url), |
| 146 additional_headers_(additional_headers), |
| 147 request_type_(request_type), |
| 148 post_data_mime_type_(post_data_mime_type), |
| 149 post_data_(post_data), |
| 150 request_context_getter_(request_context_getter), |
| 151 owner_(owner) { |
| 152 } |
| 153 |
| 154 CloudPrintRequestImpl::Fetcher::~Fetcher() { |
| 155 } |
| 156 |
| 157 void CloudPrintRequestImpl::Fetcher::Start( |
| 158 OAuth2TokenService* oauth2_token_service) { |
| 159 DCHECK(oauth2_token_service); |
| 160 std::vector<std::string> scopes(1, kCloudPrintOAuthScope); |
| 161 oauth2_access_token_request_.reset(oauth2_token_service->StartRequest( |
| 162 scopes, this)); |
| 163 } |
| 164 |
| 165 void CloudPrintRequestImpl::Fetcher::OnGetTokenSuccess( |
| 166 const std::string& oauth2_access_token, |
| 167 const base::Time& expiration_date) { |
| 168 oauth2_access_token_request_.reset(); |
| 169 cloud_print_request_.reset(CreateCloudPrintURLFetcher( |
| 170 url_, |
| 171 oauth2_access_token, |
| 172 additional_headers_, |
| 173 request_type_, |
| 174 post_data_mime_type_, |
| 175 post_data_, |
| 176 request_context_getter_, |
| 177 this)); |
| 178 cloud_print_request_->Start(); |
| 179 } |
| 180 |
| 181 void CloudPrintRequestImpl::Fetcher::OnGetTokenFailure( |
| 182 const GoogleServiceAuthError& error) { |
| 183 LOG(ERROR) << "Fail to fetch oauth token due to error: " << error.state(); |
| 184 oauth2_access_token_request_.reset(); |
| 185 owner_->OnGetOAuth2AccessTokenFailure(); |
| 186 } |
| 187 |
| 188 void CloudPrintRequestImpl::Fetcher::OnURLFetchComplete( |
| 189 const net::URLFetcher* source) { |
| 190 owner_->OnFetchComplete(source); |
| 191 } |
| 192 |
| 193 CloudPrintRequestImpl::CloudPrintRequestImpl( |
| 194 const GURL& url, |
| 195 const std::string& additional_headers, |
| 196 const net::URLFetcher::RequestType& request_type, |
| 197 const std::string& post_data_mime_type, |
| 198 const std::string& post_data, |
| 199 const Settings& settings, |
| 200 CloudPrintRequestImpl::Delegate* delegate) |
| 201 : settings_(settings), |
| 202 delegate_(delegate), |
| 203 fetcher_(new Fetcher(PrepareURL(url, settings.cloud_print_client_id), |
| 204 additional_headers, |
| 205 request_type, |
| 206 post_data_mime_type, |
| 207 post_data, |
| 208 settings.request_context_getter, |
| 209 this)), |
| 210 auth_token_failure_(false) { |
| 211 } |
| 212 |
| 213 CloudPrintRequestImpl::~CloudPrintRequestImpl() { |
| 214 } |
| 215 |
| 216 void CloudPrintRequestImpl::Start() { |
| 217 DCHECK(CalledOnValidThread()); |
| 218 fetcher_->Start(settings_.oauth2_token_service); |
| 219 } |
| 220 |
| 221 void CloudPrintRequestImpl::OnGetOAuth2AccessTokenFailure() { |
| 222 DCHECK(CalledOnValidThread()); |
| 223 auth_token_failure_ = true; |
| 224 delegate_->OnRequestComplete(this); |
| 225 } |
| 226 |
| 227 void CloudPrintRequestImpl::OnFetchComplete(const net::URLFetcher* fetcher) { |
| 228 DCHECK(CalledOnValidThread()); |
| 229 if (!fetcher->GetStatus().is_success() || fetcher->GetResponseCode() != 200) { |
| 230 std::string response_data; |
| 231 fetcher->GetResponseAsString(&response_data); |
| 232 LOG(ERROR) << "Fail to get cloud print response: " << response_data; |
| 233 } |
| 234 |
| 235 delegate_->OnRequestComplete(this); |
| 236 } |
| 237 |
| 238 std::string CloudPrintRequestImpl::GetResponseData(bool* success) const { |
| 239 DCHECK(CalledOnValidThread()); |
| 240 const net::URLFetcher* cloud_print_request = |
| 241 fetcher_->cloud_print_request_.get(); |
| 242 |
| 243 if (!cloud_print_request || |
| 244 !cloud_print_request->GetStatus().is_success() || |
| 245 cloud_print_request->GetResponseCode() != 200) { |
| 246 *success = false; |
| 247 return std::string(); |
| 248 } |
| 249 |
| 250 *success = true; |
| 251 std::string data; |
| 252 fetcher_->cloud_print_request_->GetResponseAsString(&data); |
| 253 return data; |
| 254 } |
| 255 |
| 256 std::string CloudPrintRequestImpl::GetResponseMimeType() const { |
| 257 if (!fetcher_->cloud_print_request_.get()) |
| 258 return std::string(); |
| 259 |
| 260 std::string mime_type; |
| 261 net::HttpResponseHeaders* headers = |
| 262 fetcher_->cloud_print_request_->GetResponseHeaders(); |
| 263 if (headers) |
| 264 headers->GetMimeType(&mime_type); |
| 265 return mime_type; |
| 266 } |
| 267 |
| 268 bool CloudPrintRequestImpl::HasOAuth2AccessTokenFailure() const { |
| 269 return auth_token_failure_; |
| 270 } |
| 271 |
| 272 bool CloudPrintRequestImpl::HasCloudPrintAuthError() const { |
| 273 if (!fetcher_->cloud_print_request_.get()) |
| 274 return false; |
| 275 return fetcher_->cloud_print_request_->GetResponseCode() == |
| 276 net::HTTP_FORBIDDEN; |
| 277 } |
| 278 |
| 279 } // namespace chrome_to_mobile |
| 280 |
OLD | NEW |