Skip to content

Commit

Permalink
Finished registration to Google Cloud Print.
Browse files Browse the repository at this point in the history
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
Show file tree
Hide file tree
Showing 16 changed files with 1,271 additions and 44 deletions.
1 change: 1 addition & 0 deletions cloud_print/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ include_rules = [
"+grit",
"+net",
"+printing",
"+url",
]
246 changes: 246 additions & 0 deletions cloud_print/gcp20/prototype/cloud_print_requester.cc
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,
&registration_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);
}

120 changes: 120 additions & 0 deletions cloud_print/gcp20/prototype/cloud_print_requester.h
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_

Loading

0 comments on commit 6676bf4

Please sign in to comment.