forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Finished registration to Google Cloud Print.
No saving state. No network error handling. No /privet/reset. Fixed bug with empty command line arguments. BUG= Review URL: https://chromiumcodereview.appspot.com/17921002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@212667 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
maksymb@chromium.org
committed
Jul 19, 2013
1 parent
6d2143e
commit 6676bf4
Showing
16 changed files
with
1,271 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,5 @@ include_rules = [ | |
"+grit", | ||
"+net", | ||
"+printing", | ||
"+url", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
// Copyright 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "cloud_print/gcp20/prototype/cloud_print_requester.h" | ||
|
||
#include "base/md5.h" | ||
#include "base/message_loop/message_loop.h" | ||
#include "base/rand_util.h" | ||
#include "base/strings/stringprintf.h" | ||
#include "cloud_print/gcp20/prototype/cloud_print_response_parser.h" | ||
#include "google_apis/google_api_keys.h" | ||
#include "net/base/load_flags.h" | ||
#include "net/base/mime_util.h" | ||
#include "net/base/url_util.h" | ||
#include "net/proxy/proxy_config_service_fixed.h" | ||
#include "net/url_request/url_request_context.h" | ||
#include "net/url_request/url_request_context_builder.h" | ||
#include "url/gurl.h" | ||
|
||
namespace { | ||
|
||
const char kProxyIdValue[] = "proxy"; | ||
const char kPrinterNameValue[] = "printer"; | ||
const char kPrinterCapsValue[] = "capabilities"; | ||
const char kPrinterCapsHashValue[] = "capsHash"; | ||
const char kPrinterUserValue[] = "user"; | ||
|
||
const int kGaiaMaxRetries = 3; | ||
|
||
std::string GetCloudPrintUrl() { | ||
return "https://www.google.com/cloudprint"; | ||
} | ||
|
||
GURL CreateRegisterUrl() { | ||
return GURL(GetCloudPrintUrl() + "/register"); | ||
} | ||
|
||
} // namespace | ||
|
||
// Used to return a dummy context, which lives on the message loop | ||
// given in the constructor. | ||
class CloudPrintURLRequestContextGetter : public net::URLRequestContextGetter { | ||
public: | ||
// |task_runner| must not be NULL. | ||
explicit CloudPrintURLRequestContextGetter( | ||
scoped_refptr<base::SingleThreadTaskRunner> task_runner) { | ||
DCHECK(task_runner); | ||
network_task_runner_ = task_runner; | ||
} | ||
|
||
// URLRequestContextGetter implementation. | ||
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { | ||
if (!context_) { | ||
net::URLRequestContextBuilder builder; | ||
#if defined(OS_LINUX) || defined(OS_ANDROID) | ||
builder.set_proxy_config_service( | ||
new net::ProxyConfigServiceFixed(net::ProxyConfig())); | ||
#endif // defined(OS_LINUX) || defined(OS_ANDROID) | ||
context_.reset(builder.Build()); | ||
} | ||
return context_.get(); | ||
} | ||
|
||
virtual scoped_refptr<base::SingleThreadTaskRunner> | ||
GetNetworkTaskRunner() const OVERRIDE { | ||
return network_task_runner_; | ||
} | ||
|
||
protected: | ||
virtual ~CloudPrintURLRequestContextGetter() {} | ||
|
||
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; | ||
scoped_ptr<net::URLRequestContext> context_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(CloudPrintURLRequestContextGetter); | ||
}; | ||
|
||
CloudPrintRequester::CloudPrintRequester( | ||
scoped_refptr<base::SingleThreadTaskRunner> task_runner, | ||
Delegate* delegate) | ||
: context_getter_(new CloudPrintURLRequestContextGetter(task_runner)), | ||
delegate_(delegate) { | ||
oauth_client_info_.client_id = | ||
google_apis::GetOAuth2ClientID(google_apis::CLIENT_CLOUD_PRINT); | ||
oauth_client_info_.client_secret = | ||
google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_CLOUD_PRINT); | ||
oauth_client_info_.redirect_uri = "oob"; | ||
} | ||
|
||
CloudPrintRequester::~CloudPrintRequester() { | ||
} | ||
|
||
bool CloudPrintRequester::StartRegistration(const std::string& proxy_id, | ||
const std::string& device_name, | ||
const std::string& user, | ||
const std::string& cdd) { | ||
std::string mime_boundary; | ||
int r1 = base::RandInt(0, kint32max); | ||
int r2 = base::RandInt(0, kint32max); | ||
base::SStringPrintf(&mime_boundary, | ||
"---------------------------%08X%08X", r1, r2); | ||
|
||
std::string data; | ||
net::AddMultipartValueForUpload(kProxyIdValue, proxy_id, | ||
mime_boundary, std::string(), &data); | ||
net::AddMultipartValueForUpload(kPrinterNameValue, device_name, | ||
mime_boundary, std::string(), &data); | ||
net::AddMultipartValueForUpload("use_cdd", "true", | ||
mime_boundary, std::string(), &data); | ||
net::AddMultipartValueForUpload(kPrinterNameValue, device_name, | ||
mime_boundary, std::string(), &data); | ||
net::AddMultipartValueForUpload(kPrinterCapsValue, cdd, | ||
mime_boundary, "application/json", &data); | ||
net::AddMultipartValueForUpload(kPrinterCapsHashValue, base::MD5String(cdd), | ||
mime_boundary, std::string(), &data); | ||
net::AddMultipartValueForUpload(kPrinterUserValue, user, | ||
mime_boundary, std::string(), &data); | ||
net::AddMultipartFinalDelimiterForUpload(mime_boundary, &data); | ||
|
||
std::string mime_type("multipart/form-data; boundary=" + mime_boundary); | ||
|
||
if (!CreateRequest( | ||
CreateRegisterUrl(), net::URLFetcher::POST, | ||
base::Bind(&CloudPrintRequester::ParseRegisterStartResponse, | ||
base::Unretained(this)))) { | ||
return false; | ||
} | ||
fetcher_->SetUploadData(mime_type, data); | ||
fetcher_->Start(); | ||
|
||
return true; | ||
} | ||
|
||
bool CloudPrintRequester::CompleteRegistration() { | ||
if (!CreateRequest( | ||
GURL(polling_url_ + oauth_client_info_.client_id), | ||
net::URLFetcher::GET, | ||
base::Bind(&CloudPrintRequester::ParseRegisterCompleteResponse, | ||
base::Unretained(this)))) { | ||
return false; | ||
} | ||
fetcher_->Start(); | ||
|
||
return true; | ||
} | ||
|
||
void CloudPrintRequester::OnURLFetchComplete(const net::URLFetcher* source) { | ||
std::string response; | ||
source->GetResponseAsString(&response); | ||
fetcher_.reset(); | ||
VLOG(1) << response; | ||
|
||
// TODO(maksymb): Add |server_http_code| and |server_api| info for errors. | ||
if (!parse_response_callback_.is_null()) { | ||
parse_response_callback_.Run(response); | ||
parse_response_callback_.Reset(); | ||
} | ||
} | ||
|
||
void CloudPrintRequester::OnGetTokensResponse(const std::string& refresh_token, | ||
const std::string& access_token, | ||
int expires_in_seconds) { | ||
access_token_ = access_token; | ||
delegate_->OnGetAuthCodeResponseParsed(refresh_token); | ||
} | ||
|
||
void CloudPrintRequester::OnRefreshTokenResponse( | ||
const std::string& access_token, | ||
int expires_in_seconds) { | ||
NOTIMPLEMENTED(); | ||
} | ||
|
||
void CloudPrintRequester::OnOAuthError() { | ||
NOTIMPLEMENTED(); | ||
} | ||
|
||
void CloudPrintRequester::OnNetworkError(int response_code) { | ||
NOTIMPLEMENTED(); | ||
} | ||
|
||
bool CloudPrintRequester::CreateRequest(const GURL& url, | ||
net::URLFetcher::RequestType method, | ||
const ParserCallback& callback) { | ||
if (fetcher_) | ||
return false; // Only one query is supported. | ||
|
||
fetcher_.reset(net::URLFetcher::Create(url, method, this)); | ||
fetcher_->SetRequestContext(context_getter_); | ||
|
||
int load_flags = fetcher_->GetLoadFlags(); | ||
load_flags |= net::LOAD_DO_NOT_SEND_COOKIES; | ||
load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES; | ||
fetcher_->SetLoadFlags(load_flags); | ||
|
||
fetcher_->AddExtraRequestHeader("X-CloudPrint-Proxy: \"\""); | ||
if (!access_token_.empty()) | ||
fetcher_->AddExtraRequestHeader("Authorization: Bearer " + access_token_); | ||
|
||
parse_response_callback_ = callback; | ||
|
||
return true; | ||
} | ||
|
||
void CloudPrintRequester::ParseRegisterStartResponse( | ||
const std::string& response) { | ||
std::string polling_url; | ||
std::string registration_token; | ||
std::string complete_invite_url; | ||
std::string device_id; | ||
|
||
bool success = cloud_print_response_parser::ParseRegisterStartResponse( | ||
response, | ||
base::Bind(&CloudPrintRequester::Delegate::OnRegistrationError, | ||
base::Unretained(delegate_)), | ||
&polling_url, | ||
®istration_token, | ||
&complete_invite_url, | ||
&device_id); | ||
|
||
if (!success) | ||
return; | ||
|
||
polling_url_ = polling_url; | ||
delegate_->OnRegistrationStartResponseParsed(registration_token, | ||
complete_invite_url, device_id); | ||
} | ||
|
||
void CloudPrintRequester::ParseRegisterCompleteResponse( | ||
const std::string& response) { | ||
std::string authorization_code; | ||
|
||
bool success = cloud_print_response_parser::ParseRegisterCompleteResponse( | ||
response, | ||
base::Bind(&CloudPrintRequester::Delegate::OnRegistrationError, | ||
base::Unretained(delegate_)), | ||
&authorization_code); | ||
|
||
if (!success) | ||
return; | ||
|
||
gaia_.reset(new gaia::GaiaOAuthClient(context_getter_.get())); | ||
gaia_->GetTokensFromAuthCode(oauth_client_info_, authorization_code, | ||
kGaiaMaxRetries, this); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CLOUD_PRINT_GCP20_PROTOTYPE_CLOUD_REQUESTER_H_ | ||
#define CLOUD_PRINT_GCP20_PROTOTYPE_CLOUD_REQUESTER_H_ | ||
|
||
#include <map> | ||
#include <string> | ||
|
||
#include "base/basictypes.h" | ||
#include "base/callback.h" | ||
#include "base/values.h" | ||
#include "google_apis/gaia/gaia_oauth_client.h" | ||
#include "net/url_request/url_fetcher.h" | ||
#include "net/url_request/url_fetcher_delegate.h" | ||
#include "net/url_request/url_request_context_getter.h" | ||
|
||
typedef base::Callback<void(const std::string&)> ParserCallback; | ||
|
||
class CloudPrintURLRequestContextGetter; | ||
|
||
// Class for requesting CloudPrint server and parsing responses. | ||
class CloudPrintRequester : public net::URLFetcherDelegate, | ||
public gaia::GaiaOAuthClient::Delegate { | ||
public: | ||
class Delegate { | ||
public: | ||
Delegate() {} | ||
virtual ~Delegate() {} | ||
|
||
// Invoked when server respond for registration-start query and response is | ||
// successfully parsed. | ||
virtual void OnRegistrationStartResponseParsed( | ||
const std::string& registration_token, | ||
const std::string& complete_invite_url, | ||
const std::string& device_id) = 0; | ||
|
||
// Invoked when server respond for registration-getAuthCode query and | ||
// response is successfully parsed. | ||
virtual void OnGetAuthCodeResponseParsed( | ||
const std::string& refresh_token) = 0; | ||
|
||
// Invoked when server respond with |"success" = false| or we cannot parse | ||
// response. | ||
virtual void OnRegistrationError(const std::string& description) = 0; | ||
}; | ||
|
||
// Creates and initializes objects. | ||
CloudPrintRequester(scoped_refptr<base::SingleThreadTaskRunner> task_runner, | ||
Delegate* delegate); | ||
|
||
// Destroys the object. | ||
virtual ~CloudPrintRequester(); | ||
|
||
// Creates query to server for starting registration. | ||
bool StartRegistration(const std::string& proxy_id, | ||
const std::string& device_name, | ||
const std::string& user, | ||
const std::string& cdd); | ||
|
||
// Creates request for completing registration and receiving refresh token. | ||
bool CompleteRegistration(); | ||
|
||
private: | ||
// net::URLFetcherDelegate | ||
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; | ||
|
||
// gaia::GaiaOAuthClient::Delegate | ||
virtual void OnGetTokensResponse(const std::string& refresh_token, | ||
const std::string& access_token, | ||
int expires_in_seconds) OVERRIDE; | ||
virtual void OnRefreshTokenResponse(const std::string& access_token, | ||
int expires_in_seconds) OVERRIDE; | ||
virtual void OnOAuthError() OVERRIDE; | ||
virtual void OnNetworkError(int response_code) OVERRIDE; | ||
|
||
// Creates request with given |url| and |method|. When response is received | ||
// callback is called. | ||
// TODO(maksymb): Add timeout control for request. | ||
bool CreateRequest(const GURL& url, | ||
net::URLFetcher::RequestType method, | ||
const ParserCallback& callback) WARN_UNUSED_RESULT; | ||
|
||
// Parses register-start server response. | ||
void ParseRegisterStartResponse(const std::string& response); | ||
|
||
// Parses register-complete server response. Initializes gaia (OAuth client) | ||
// and receives refresh token. | ||
void ParseRegisterCompleteResponse(const std::string& response); | ||
|
||
// Fetcher contains |NULL| if no server response is awaiting. Otherwise wait | ||
// until URLFetchComplete will be called and close connection. | ||
scoped_ptr<net::URLFetcher> fetcher_; | ||
|
||
// Callback for parsing server response. | ||
ParserCallback parse_response_callback_; | ||
|
||
// Privet context getter. | ||
scoped_refptr<CloudPrintURLRequestContextGetter> context_getter_; | ||
|
||
// URL for completing registration and receiving OAuth account. | ||
std::string polling_url_; | ||
|
||
// Last valid access_token. | ||
std::string access_token_; | ||
|
||
// OAuth client information (client_id, client_secret, etc). | ||
gaia::OAuthClientInfo oauth_client_info_; | ||
|
||
// OAuth client. | ||
scoped_ptr<gaia::GaiaOAuthClient> gaia_; | ||
|
||
Delegate* delegate_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(CloudPrintRequester); | ||
}; | ||
|
||
#endif // CLOUD_PRINT_GCP20_PROTOTYPE_CLOUD_REQUESTER_H_ | ||
|
Oops, something went wrong.