Commit f0cb5b9f authored by gene@chromium.org's avatar gene@chromium.org

Chrome proxy refactoring.Adding myself to the OWNERS file for handling cloud...

Chrome proxy refactoring.Adding myself to the OWNERS file for handling cloud print proxy issues.Split proxy code from cloud_print_proxy_backend to a separate pieces:  - auth code goes to cloud_print_auth.h/cc  - connector logic goes to cloud_print_connector.h/cc (printer enumeration, registration and deletion)  - wiring backend/frontend threads, notifications with other parts will stay in cloud_print_backend.h/ccMade proxy logic more straightforward.
Review URL: http://codereview.chromium.org/8387011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107758 0039d316-1c4b-4281-b951-d872f2087c98
parent 121352a9
...@@ -845,6 +845,10 @@ ...@@ -845,6 +845,10 @@
'service/service_process_prefs.h', 'service/service_process_prefs.h',
'service/service_utility_process_host.cc', 'service/service_utility_process_host.cc',
'service/service_utility_process_host.h', 'service/service_utility_process_host.h',
'service/cloud_print/cloud_print_auth.cc',
'service/cloud_print/cloud_print_auth.h',
'service/cloud_print/cloud_print_connector.cc',
'service/cloud_print/cloud_print_connector.h',
'service/cloud_print/cloud_print_consts.cc', 'service/cloud_print/cloud_print_consts.cc',
'service/cloud_print/cloud_print_consts.h', 'service/cloud_print/cloud_print_consts.h',
'service/cloud_print/cloud_print_helpers.cc', 'service/cloud_print/cloud_print_helpers.cc',
......
ajwong@chromium.org ajwong@chromium.org
dmaclach@chromium.org dmaclach@chromium.org
hclam@chromium.org hclam@chromium.org
sanjeevr@chromium.org
scottbyer@chromium.org scottbyer@chromium.org
gene@chromium.org
abodenha@chromium.org
// Copyright (c) 2011 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 "chrome/service/cloud_print/cloud_print_auth.h"
#include "base/string_util.h"
#include "chrome/common/net/gaia/gaia_urls.h"
#include "chrome/service/cloud_print/cloud_print_consts.h"
#include "chrome/service/cloud_print/cloud_print_helpers.h"
#include "chrome/service/cloud_print/cloud_print_token_store.h"
#include "chrome/service/gaia/service_gaia_authenticator.h"
#include "chrome/service/net/service_url_request_context.h"
#include "chrome/service/service_process.h"
CloudPrintAuth::CloudPrintAuth(
Client* client,
const GURL& cloud_print_server_url,
const base::DictionaryValue* print_sys_settings,
const gaia::OAuthClientInfo& oauth_client_info,
const std::string& proxy_id)
: client_(client),
oauth_client_info_(oauth_client_info),
cloud_print_server_url_(cloud_print_server_url),
proxy_id_(proxy_id) {
DCHECK(client);
if (print_sys_settings) {
// It is possible to have no print settings specified.
print_system_settings_.reset(print_sys_settings->DeepCopy());
}
}
CloudPrintAuth::~CloudPrintAuth() {
}
void CloudPrintAuth::AuthenticateWithLsid(
const std::string& lsid,
const std::string& last_robot_refresh_token,
const std::string& last_robot_email,
const std::string& last_user_email) {
// Keeping VLOGs for Cloud Print proxy logging. It is convinient for finding
// issues with GCP in the field, where only release version is avaialble.
VLOG(1) << "CP_AUTH: Authenticating with LSID";
scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_print(
new ServiceGaiaAuthenticator(
kProxyAuthUserAgent, kCloudPrintGaiaServiceId,
GaiaUrls::GetInstance()->client_login_url(),
g_service_process->io_thread()->message_loop_proxy()));
gaia_auth_for_print->set_message_loop(MessageLoop::current());
if (gaia_auth_for_print->AuthenticateWithLsid(lsid)) {
// Stash away the user email so we can save it in prefs.
user_email_ = gaia_auth_for_print->email();
// If the same user is re-enabling Cloud Print and we have stashed robot
// credentials, we will use those.
if ((0 == base::strcasecmp(user_email_.c_str(), last_user_email.c_str())) &&
!last_robot_refresh_token.empty() &&
!last_robot_email.empty()) {
AuthenticateWithRobotToken(last_robot_refresh_token,
last_robot_email);
}
AuthenticateWithToken(gaia_auth_for_print->auth_token());
} else {
// Notify client about authentication error.
client_->OnInvalidCredentials();
}
}
void CloudPrintAuth::AuthenticateWithToken(
const std::string cloud_print_token) {
VLOG(1) << "CP_AUTH: Authenticating with token";
client_login_token_ = cloud_print_token;
// We need to get the credentials of the robot here.
GURL get_authcode_url =
CloudPrintHelpers::GetUrlForGetAuthCode(cloud_print_server_url_,
oauth_client_info_.client_id,
proxy_id_);
request_ = new CloudPrintURLFetcher;
request_->StartGetRequest(get_authcode_url,
this,
kCloudPrintAuthMaxRetryCount,
std::string());
}
void CloudPrintAuth::AuthenticateWithRobotToken(
const std::string& robot_oauth_refresh_token,
const std::string& robot_email) {
VLOG(1) << "CP_AUTH: Authenticating with robot token";
robot_email_ = robot_email;
refresh_token_ = robot_oauth_refresh_token;
RefreshAccessToken();
}
void CloudPrintAuth::AuthenticateWithRobotAuthCode(
const std::string& robot_oauth_auth_code,
const std::string& robot_email) {
VLOG(1) << "CP_AUTH: Authenticating with robot auth code";
robot_email_ = robot_email;
// Now that we have an auth code we need to get the refresh and access tokens.
oauth_client_.reset(new gaia::GaiaOAuthClient(
gaia::kGaiaOAuth2Url,
g_service_process->GetServiceURLRequestContextGetter()));
oauth_client_->GetTokensFromAuthCode(oauth_client_info_,
robot_oauth_auth_code,
kCloudPrintAuthMaxRetryCount,
this);
}
void CloudPrintAuth::RefreshAccessToken() {
oauth_client_.reset(new gaia::GaiaOAuthClient(
gaia::kGaiaOAuth2Url,
g_service_process->GetServiceURLRequestContextGetter()));
oauth_client_->RefreshToken(oauth_client_info_,
refresh_token_,
kCloudPrintAuthMaxRetryCount,
this);
}
void CloudPrintAuth::OnGetTokensResponse(const std::string& refresh_token,
const std::string& access_token,
int expires_in_seconds) {
refresh_token_ = refresh_token;
// After saving the refresh token, this is just like having just refreshed
// the access token. Just call OnRefreshTokenResponse.
OnRefreshTokenResponse(access_token, expires_in_seconds);
}
void CloudPrintAuth::OnRefreshTokenResponse(const std::string& access_token,
int expires_in_seconds) {
client_->OnAuthenticationComplete(access_token, refresh_token_,
robot_email_, user_email_);
// Schedule a task to refresh the access token again when it is about to
// expire.
DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs);
int64 refresh_delay =
(expires_in_seconds - kTokenRefreshGracePeriodSecs)*1000;
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
NewRunnableMethod(this, &CloudPrintAuth::RefreshAccessToken),
refresh_delay);
}
void CloudPrintAuth::OnOAuthError() {
// Notify client about authentication error.
client_->OnInvalidCredentials();
}
void CloudPrintAuth::OnNetworkError(int response_code) {
// Since we specify infinite retries on network errors, this should never
// be called.
NOTREACHED() <<
"OnNetworkError invoked when not expected, response code is " <<
response_code;
}
CloudPrintURLFetcher::ResponseAction CloudPrintAuth::HandleJSONData(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded) {
if (!succeeded) {
VLOG(1) << "CP_AUTH: Creating robot account failed";
client_->OnInvalidCredentials();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
std::string auth_code;
if (!json_data->GetString(kOAuthCodeValue, &auth_code)) {
VLOG(1) << "CP_AUTH: Creating robot account returned invalid json response";
client_->OnInvalidCredentials();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
json_data->GetString(kXMPPJidValue, &robot_email_);
// Now that we have an auth code we need to get the refresh and access tokens.
oauth_client_.reset(new gaia::GaiaOAuthClient(
gaia::kGaiaOAuth2Url,
g_service_process->GetServiceURLRequestContextGetter()));
oauth_client_->GetTokensFromAuthCode(oauth_client_info_,
auth_code,
kCloudPrintAPIMaxRetryCount,
this);
return CloudPrintURLFetcher::STOP_PROCESSING;
}
CloudPrintURLFetcher::ResponseAction CloudPrintAuth::OnRequestAuthError() {
VLOG(1) << "CP_AUTH: Creating robot account authentication error";
// Notify client about authentication error.
client_->OnInvalidCredentials();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
std::string CloudPrintAuth::GetAuthHeader() {
DCHECK(!client_login_token_.empty());
std::string header;
header = "Authorization: GoogleLogin auth=";
header += client_login_token_;
return header;
}
// Copyright (c) 2011 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 CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_AUTH_H_
#define CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_AUTH_H_
#pragma once
#include <string>
#include "base/values.h"
#include "chrome/common/net/gaia/gaia_oauth_client.h"
#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
#include "googleurl/src/gurl.h"
// CloudPrintAuth is a class to handle login, token refresh, and other
// authentication tasks for Cloud Print.
// CloudPrintAuth will create new robot account for this proxy if needed.
// CloudPrintAuth will obtain new OAuth token.
// CloudPrintAuth will schedule periodic OAuth token refresh
// It is running in the same thread as CloudPrintProxyBackend::Core.
class CloudPrintAuth
: public base::RefCountedThreadSafe<CloudPrintAuth>,
public CloudPrintURLFetcherDelegate,
public gaia::GaiaOAuthClient::Delegate {
public:
class Client {
public:
virtual void OnAuthenticationComplete(
const std::string& access_token,
const std::string& robot_oauth_refresh_token,
const std::string& robot_email,
const std::string& user_email) = 0;
virtual void OnInvalidCredentials() = 0;
protected:
virtual ~Client() {}
};
CloudPrintAuth(Client* client,
const GURL& cloud_print_server_url,
const base::DictionaryValue* print_sys_settings,
const gaia::OAuthClientInfo& oauth_client_info,
const std::string& proxy_id);
virtual ~CloudPrintAuth();
// Note:
//
// The Authenticate* methods are the various entry points from
// CloudPrintProxyBackend::Core. It calls us on a dedicated thread to
// actually perform synchronous (and potentially blocking) operations.
//
// When we are passed in an LSID we authenticate using that
// and retrieve new auth tokens.
void AuthenticateWithLsid(const std::string& lsid,
const std::string& last_robot_refresh_token,
const std::string& last_robot_email,
const std::string& last_user_email);
void AuthenticateWithToken(const std::string cloud_print_token);
void AuthenticateWithRobotToken(const std::string& robot_oauth_refresh_token,
const std::string& robot_email);
void AuthenticateWithRobotAuthCode(const std::string& robot_oauth_auth_code,
const std::string& robot_email);
void RefreshAccessToken();
// gaia::GaiaOAuthClient::Delegate implementation.
virtual void OnGetTokensResponse(const std::string& refresh_token,
const std::string& access_token,
int expires_in_seconds);
virtual void OnRefreshTokenResponse(const std::string& access_token,
int expires_in_seconds);
virtual void OnOAuthError();
virtual void OnNetworkError(int response_code);
// CloudPrintURLFetcher::Delegate implementation.
virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
private:
Client* client_;
gaia::OAuthClientInfo oauth_client_info_;
scoped_ptr<gaia::GaiaOAuthClient> oauth_client_;
scoped_ptr<DictionaryValue> print_system_settings_;
// The CloudPrintURLFetcher instance for the current request.
scoped_refptr<CloudPrintURLFetcher> request_;
GURL cloud_print_server_url_;
// Proxy id, need to send to the cloud print server to find and update
// necessary printers during the migration process.
const std::string& proxy_id_;
// The OAuth2 refresh token for the robot.
std::string refresh_token_;
// The email address of the user. This is only used during initial
// authentication with an LSID. This is only used for storing in prefs for
// display purposes.
std::string user_email_;
// The email address of the robot account.
std::string robot_email_;
// client login token used to authenticate request to cloud print server to
// get the robot account.
std::string client_login_token_;
DISALLOW_COPY_AND_ASSIGN(CloudPrintAuth);
};
#endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_AUTH_H_
This diff is collapsed.
// Copyright (c) 2011 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 CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_CONNECTOR_H_
#define CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_CONNECTOR_H_
#pragma once
#include <list>
#include <map>
#include <string>
#include "base/threading/thread.h"
#include "base/values.h"
#include "chrome/service/cloud_print/print_system.h"
#include "chrome/service/cloud_print/printer_job_handler.h"
// CloudPrintConnector handles top printer management tasks.
// - Matching local and cloud printers
// - Registration of local printers
// - Deleting cloud printers
// All tasks are posted to the commond queue (PendingTasks) and executed
// one-by-one in FIFO order.
// CloudPrintConnector will notify client over Client interface.
class CloudPrintConnector
: public base::RefCountedThreadSafe<CloudPrintConnector>,
public cloud_print::PrintServerWatcherDelegate,
public PrinterJobHandlerDelegate,
public CloudPrintURLFetcherDelegate {
public:
class Client {
public:
virtual void OnPrintersAvailable(const printing::PrinterList& printers) = 0;
virtual void OnAuthFailed() = 0;
protected:
virtual ~Client() {}
};
CloudPrintConnector(Client* client,
const std::string& proxy_id,
const GURL& cloud_print_server_url,
const DictionaryValue* print_system_settings);
virtual ~CloudPrintConnector();
bool Start();
void Stop();
bool IsRunning();
// Register printer from the list.
void RegisterPrinters(const printing::PrinterList& printers);
// Check for jobs for specific printer. If printer id is empty
// jobs will be checked for all available printers.
void CheckForJobs(const std::string& reason, const std::string& printer_id);
// cloud_print::PrintServerWatcherDelegate implementation
virtual void OnPrinterAdded();
// PrinterJobHandler::Delegate implementation
virtual void OnPrinterDeleted(const std::string& printer_name);
virtual void OnAuthError();
// CloudPrintURLFetcher::Delegate implementation.
virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
const content::URLFetcher* source,
const GURL& url,
const std::string& data);
virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
private:
// Prototype for a response handler.
typedef CloudPrintURLFetcher::ResponseAction
(CloudPrintConnector::*ResponseHandler)(
const content::URLFetcher* source,
const GURL& url,
DictionaryValue* json_data,
bool succeeded);
// Begin response handlers
CloudPrintURLFetcher::ResponseAction HandlePrinterListResponse(
const content::URLFetcher* source,
const GURL& url,
DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandlePrinterDeleteResponse(
const content::URLFetcher* source,
const GURL& url,
DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleRegisterPrinterResponse(
const content::URLFetcher* source,
const GURL& url,
DictionaryValue* json_data,
bool succeeded);
// End response handlers
// Helper functions for network requests.
void StartGetRequest(const GURL& url,
int max_retries,
ResponseHandler handler);
void StartPostRequest(const GURL& url,
int max_retries,
const std::string& mime_type,
const std::string& post_data,
ResponseHandler handler);
// Reports a diagnostic message to the server.
void ReportUserMessage(const std::string& message_id,
const std::string& failure_message);
bool RemovePrinterFromList(const std::string& printer_name,
printing::PrinterList* printer_list);
void InitJobHandlerForPrinter(DictionaryValue* printer_data);
enum PendingTaskType {
PENDING_PRINTERS_AVAILABLE,
PENDING_PRINTER_REGISTER,
PENDING_PRINTER_DELETE
};
struct PendingTask {
PendingTaskType type;
// Optional members, depending on type.
std::string printer_id; // For pending delete.
printing::PrinterBasicInfo printer_info; // For pending registration.
PendingTask() {}
~PendingTask() {}
};
void AddPendingAvailableTask();
void AddPendingDeleteTask(const std::string& id);
void AddPendingRegisterTask(const printing::PrinterBasicInfo& info);
void AddPendingTask(const PendingTask& task);
void ProcessPendingTask();
void ContinuePendingTaskProcessing();
void OnPrintersAvailable();
void OnPrinterRegister(const printing::PrinterBasicInfo& info);
void OnPrinterDelete(const std::string& name);
void OnReceivePrinterCaps(
bool succeeded,
const std::string& printer_name,
const printing::PrinterCapsAndDefaults& caps_and_defaults);
bool IsSamePrinter(const std::string& name1, const std::string& name2) const;
// CloudPrintConnector client.
Client* client_;
// Print system settings.
scoped_ptr<DictionaryValue> print_system_settings_;
// Pointer to current print system.
scoped_refptr<cloud_print::PrintSystem> print_system_;
// Watcher for print system updates.
scoped_refptr<cloud_print::PrintSystem::PrintServerWatcher>
print_server_watcher_;
// Id of the Cloud Print proxy.
std::string proxy_id_;
// Cloud Print server url.
GURL cloud_print_server_url_;
// A map of printer id to job handler.
typedef std::map<std::string, scoped_refptr<PrinterJobHandler> >
JobHandlerMap;
JobHandlerMap job_handler_map_;
// Next response handler.
ResponseHandler next_response_handler_;
// The list of peding tasks to be done in the background.
std::list<PendingTask> pending_tasks_;
// The CloudPrintURLFetcher instance for the current request.
scoped_refptr<CloudPrintURLFetcher> request_;
// The CloudPrintURLFetcher instance for the user message request.
scoped_refptr<CloudPrintURLFetcher> user_message_request_;
DISALLOW_COPY_AND_ASSIGN(CloudPrintConnector);
};
#endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_CONNECTOR_H_
...@@ -38,6 +38,7 @@ const char kTagDryRunFlag[] = "__cp__dry_run"; ...@@ -38,6 +38,7 @@ const char kTagDryRunFlag[] = "__cp__dry_run";
const char kDefaultCloudPrintServerUrl[] = "https://www.google.com/cloudprint"; const char kDefaultCloudPrintServerUrl[] = "https://www.google.com/cloudprint";
const char kCloudPrintGaiaServiceId[] = "cloudprint"; const char kCloudPrintGaiaServiceId[] = "cloudprint";
const char kSyncGaiaServiceId[] = "chromiumsync"; const char kSyncGaiaServiceId[] = "chromiumsync";
const char kProxyAuthUserAgent[] = "ChromiumBrowser";
const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com"; const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com";
// The cloud print server expects the X-Google-CloudPrint-Proxy header for // The cloud print server expects the X-Google-CloudPrint-Proxy header for
// certain requests. // certain requests.
......
...@@ -18,6 +18,7 @@ extern const char kPrinterStatusValue[]; ...@@ -18,6 +18,7 @@ extern const char kPrinterStatusValue[];
extern const char kPrinterTagValue[]; extern const char kPrinterTagValue[];
extern const char kPrinterRemoveTagValue[]; extern const char kPrinterRemoveTagValue[];
extern const char kMessageTextValue[]; extern const char kMessageTextValue[];
// Values in the respone JSON from the cloud print server // Values in the respone JSON from the cloud print server
extern const char kPrinterListValue[]; extern const char kPrinterListValue[];
extern const char kSuccessValue[]; extern const char kSuccessValue[];
...@@ -38,6 +39,7 @@ extern const char kTagDryRunFlag[]; ...@@ -38,6 +39,7 @@ extern const char kTagDryRunFlag[];
extern const char kDefaultCloudPrintServerUrl[]; extern const char kDefaultCloudPrintServerUrl[];
extern const char kCloudPrintGaiaServiceId[]; extern const char kCloudPrintGaiaServiceId[];
extern const char kSyncGaiaServiceId[]; extern const char kSyncGaiaServiceId[];
extern const char kProxyAuthUserAgent[];
extern const char kCloudPrintPushNotificationsSource[]; extern const char kCloudPrintPushNotificationsSource[];
extern const char kChromeCloudPrintProxyHeader[]; extern const char kChromeCloudPrintProxyHeader[];
extern const char kCloudPrintUserAgent[]; extern const char kCloudPrintUserAgent[];
...@@ -56,6 +58,10 @@ extern const char kDefaultCloudPrintOAuthClientSecret[]; ...@@ -56,6 +58,10 @@ extern const char kDefaultCloudPrintOAuthClientSecret[];
const int kJobDataMaxRetryCount = 5; const int kJobDataMaxRetryCount = 5;
// Max retry count (infinity) for API fetch requests. // Max retry count (infinity) for API fetch requests.
const int kCloudPrintAPIMaxRetryCount = -1; const int kCloudPrintAPIMaxRetryCount = -1;
// Max retry count (infinity) for Registration requests.
const int kCloudPrintRegisterMaxRetryCount = -1;
// Max retry count (infinity) for authentication requests.
const int kCloudPrintAuthMaxRetryCount = -1;
// When we don't have XMPP notifications available, we resort to polling for // When we don't have XMPP notifications available, we resort to polling for
// print jobs. We choose a random interval in seconds between these 2 values. // print jobs. We choose a random interval in seconds between these 2 values.
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/service/cloud_print/cloud_print_consts.h" #include "chrome/service/cloud_print/cloud_print_consts.h"
#include "chrome/service/cloud_print/cloud_print_token_store.h"
#include "chrome/service/service_process.h" #include "chrome/service/service_process.h"
std::string StringFromJobStatus(cloud_print::PrintJobStatus status) { std::string StringFromJobStatus(cloud_print::PrintJobStatus status) {
...@@ -266,3 +267,20 @@ bool CloudPrintHelpers::IsDryRunJob(const std::vector<std::string>& tags) { ...@@ -266,3 +267,20 @@ bool CloudPrintHelpers::IsDryRunJob(const std::vector<std::string>& tags) {
} }
return false; return false;
} }
std::string CloudPrintHelpers::GetCloudPrintAuthHeader() {
std::string header;
CloudPrintTokenStore* token_store = CloudPrintTokenStore::current();
if (!token_store || token_store->token().empty()) {
// Using LOG here for critical errors. GCP connector may run in the headless
// mode and error indication might be useful for user in that case.
LOG(ERROR) << "CP_PROXY: Missing OAuth token for request";
}
if (token_store) {
header = "Authorization: OAuth ";
header += token_store->token();
}
return header;
}
...@@ -70,6 +70,8 @@ class CloudPrintHelpers { ...@@ -70,6 +70,8 @@ class CloudPrintHelpers {
// Returns true is tags indicate a dry run (test) job. // Returns true is tags indicate a dry run (test) job.
static bool IsDryRunJob(const std::vector<std::string>& tags); static bool IsDryRunJob(const std::vector<std::string>& tags);
static std::string GetCloudPrintAuthHeader();
private: private:
CloudPrintHelpers() { CloudPrintHelpers() {
} }
......
...@@ -158,7 +158,8 @@ bool CloudPrintProxy::CreateBackend() { ...@@ -158,7 +158,8 @@ bool CloudPrintProxy::CreateBackend() {
GURL cloud_print_server_url(cloud_print_server_url_str.c_str()); GURL cloud_print_server_url(cloud_print_server_url_str.c_str());
DCHECK(cloud_print_server_url.is_valid()); DCHECK(cloud_print_server_url.is_valid());
backend_.reset(new CloudPrintProxyBackend(this, cloud_print_server_url, backend_.reset(new CloudPrintProxyBackend(this, proxy_id_,
cloud_print_server_url,
print_system_settings, print_system_settings,
oauth_client_info, oauth_client_info,
enable_job_poll)); enable_job_poll));
......
...@@ -58,6 +58,7 @@ class CloudPrintProxyBackend { ...@@ -58,6 +58,7 @@ class CloudPrintProxyBackend {
// use system default settings. // use system default settings.
CloudPrintProxyBackend( CloudPrintProxyBackend(
CloudPrintProxyFrontend* frontend, CloudPrintProxyFrontend* frontend,
const std::string& proxy_id,
const GURL& cloud_print_server_url, const GURL& cloud_print_server_url,
const base::DictionaryValue* print_sys_settings, const base::DictionaryValue* print_sys_settings,
const gaia::OAuthClientInfo& oauth_client_info, const gaia::OAuthClientInfo& oauth_client_info,
......
...@@ -16,7 +16,7 @@ CloudPrintTokenStore* CloudPrintTokenStore::current() { ...@@ -16,7 +16,7 @@ CloudPrintTokenStore* CloudPrintTokenStore::current() {
return lazy_tls.Pointer()->Get(); return lazy_tls.Pointer()->Get();
} }
CloudPrintTokenStore::CloudPrintTokenStore() : token_is_oauth_(false) { CloudPrintTokenStore::CloudPrintTokenStore() {
lazy_tls.Pointer()->Set(this); lazy_tls.Pointer()->Set(this);
} }
...@@ -24,8 +24,7 @@ CloudPrintTokenStore::~CloudPrintTokenStore() { ...@@ -24,8 +24,7 @@ CloudPrintTokenStore::~CloudPrintTokenStore() {
lazy_tls.Pointer()->Set(NULL); lazy_tls.Pointer()->Set(NULL);
} }
void CloudPrintTokenStore::SetToken(const std::string& token, bool is_oauth) { void CloudPrintTokenStore::SetToken(const std::string& token) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
token_ = token; token_ = token;
token_is_oauth_ = is_oauth;
} }
...@@ -23,19 +23,14 @@ class CloudPrintTokenStore : public base::NonThreadSafe { ...@@ -23,19 +23,14 @@ class CloudPrintTokenStore : public base::NonThreadSafe {
CloudPrintTokenStore(); CloudPrintTokenStore();
~CloudPrintTokenStore(); ~CloudPrintTokenStore();
void SetToken(const std::string& token, bool is_oauth); void SetToken(const std::string& token);
std::string token() const { std::string token() const {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
return token_; return token_;
} }
bool token_is_oauth() const {
DCHECK(CalledOnValidThread());
return token_is_oauth_;
}
private: private:
std::string token_; std::string token_;
bool token_is_oauth_;
DISALLOW_COPY_AND_ASSIGN(CloudPrintTokenStore); DISALLOW_COPY_AND_ASSIGN(CloudPrintTokenStore);
}; };
......
...@@ -10,12 +10,8 @@ TEST(CloudPrintTokenStoreTest, Basic) { ...@@ -10,12 +10,8 @@ TEST(CloudPrintTokenStoreTest, Basic) {
EXPECT_EQ(NULL, CloudPrintTokenStore::current()); EXPECT_EQ(NULL, CloudPrintTokenStore::current());
CloudPrintTokenStore* store = new CloudPrintTokenStore; CloudPrintTokenStore* store = new CloudPrintTokenStore;
EXPECT_EQ(store, CloudPrintTokenStore::current()); EXPECT_EQ(store, CloudPrintTokenStore::current());
CloudPrintTokenStore::current()->SetToken("myclientlogintoken", false); CloudPrintTokenStore::current()->SetToken("myclientlogintoken");
EXPECT_EQ(CloudPrintTokenStore::current()->token(), "myclientlogintoken"); EXPECT_EQ(CloudPrintTokenStore::current()->token(), "myclientlogintoken");
EXPECT_FALSE(CloudPrintTokenStore::current()->token_is_oauth());
CloudPrintTokenStore::current()->SetToken("myoauth2token", true);
EXPECT_EQ(CloudPrintTokenStore::current()->token(), "myoauth2token");
EXPECT_TRUE(CloudPrintTokenStore::current()->token_is_oauth());
delete store; delete store;
EXPECT_EQ(NULL, CloudPrintTokenStore::current()); EXPECT_EQ(NULL, CloudPrintTokenStore::current());
} }
......
...@@ -20,6 +20,10 @@ CloudPrintURLFetcher::CloudPrintURLFetcher() ...@@ -20,6 +20,10 @@ CloudPrintURLFetcher::CloudPrintURLFetcher()
num_retries_(0) { num_retries_(0) {
} }
bool CloudPrintURLFetcher::IsSameRequest(const content::URLFetcher* source) {
return (request_.get() == source);
}
void CloudPrintURLFetcher::StartGetRequest( void CloudPrintURLFetcher::StartGetRequest(
const GURL& url, const GURL& url,
Delegate* delegate, Delegate* delegate,
...@@ -65,15 +69,14 @@ void CloudPrintURLFetcher::OnURLFetchComplete( ...@@ -65,15 +69,14 @@ void CloudPrintURLFetcher::OnURLFetchComplete(
source->GetResponseCode(), source->GetResponseCode(),
source->GetCookies(), source->GetCookies(),
data); data);
// If we get auth error, notify delegate and check if it wants to proceed.
if (action == CONTINUE_PROCESSING &&
source->GetResponseCode() == RC_FORBIDDEN) {
action = delegate_->OnRequestAuthError();
}
if (action == CONTINUE_PROCESSING) { if (action == CONTINUE_PROCESSING) {
// If we are not using an OAuth token, and we got an auth error, we are
// done. Else, the token may have been refreshed. Let us try again.
if ((RC_FORBIDDEN == source->GetResponseCode()) &&
(!CloudPrintTokenStore::current() ||
!CloudPrintTokenStore::current()->token_is_oauth())) {
delegate_->OnRequestAuthError();
return;
}
// We need to retry on all network errors. // We need to retry on all network errors.
if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200))
action = RETRY_REQUEST; action = RETRY_REQUEST;
...@@ -105,6 +108,12 @@ void CloudPrintURLFetcher::OnURLFetchComplete( ...@@ -105,6 +108,12 @@ void CloudPrintURLFetcher::OnURLFetchComplete(
// be ignored. // be ignored.
request_->ReceivedContentWasMalformed(); request_->ReceivedContentWasMalformed();
// If we receive error code from the server "Media Type Not Supported",
// there is no reason to retry, request will never succeed.
// In that case we should call OnRequestGiveUp() right away.
if (source->GetResponseCode() == RC_UNSUPPORTED_MEDIA_TYPE)
num_retries_ = source->GetMaxRetries();
++num_retries_; ++num_retries_;
if ((-1 != source->GetMaxRetries()) && if ((-1 != source->GetMaxRetries()) &&
(num_retries_ > source->GetMaxRetries())) { (num_retries_ > source->GetMaxRetries())) {
...@@ -136,8 +145,8 @@ void CloudPrintURLFetcher::StartRequestHelper( ...@@ -136,8 +145,8 @@ void CloudPrintURLFetcher::StartRequestHelper(
// Since we implement our own retry logic, disable the retry in URLFetcher. // Since we implement our own retry logic, disable the retry in URLFetcher.
request_->SetAutomaticallyRetryOn5xx(false); request_->SetAutomaticallyRetryOn5xx(false);
request_->SetMaxRetries(max_retries); request_->SetMaxRetries(max_retries);
SetupRequestHeaders();
delegate_ = delegate; delegate_ = delegate;
SetupRequestHeaders();
if (request_type == content::URLFetcher::POST) { if (request_type == content::URLFetcher::POST) {
request_->SetUploadData(post_data_mime_type, post_data); request_->SetUploadData(post_data_mime_type, post_data);
} }
...@@ -146,14 +155,9 @@ void CloudPrintURLFetcher::StartRequestHelper( ...@@ -146,14 +155,9 @@ void CloudPrintURLFetcher::StartRequestHelper(
} }
void CloudPrintURLFetcher::SetupRequestHeaders() { void CloudPrintURLFetcher::SetupRequestHeaders() {
std::string headers; std::string headers = delegate_->GetAuthHeader();
CloudPrintTokenStore* token_store = CloudPrintTokenStore::current(); if (!headers.empty())
if (token_store) {
headers = token_store->token_is_oauth() ?
"Authorization: OAuth " : "Authorization: GoogleLogin auth=";
headers += token_store->token();
headers += "\r\n"; headers += "\r\n";
}
headers += kChromeCloudPrintProxyHeader; headers += kChromeCloudPrintProxyHeader;
if (!additional_headers_.empty()) { if (!additional_headers_.empty()) {
headers += "\r\n"; headers += "\r\n";
......
...@@ -38,6 +38,7 @@ class CloudPrintURLFetcher ...@@ -38,6 +38,7 @@ class CloudPrintURLFetcher
STOP_PROCESSING, STOP_PROCESSING,
RETRY_REQUEST, RETRY_REQUEST,
}; };
class Delegate { class Delegate {
public: public:
virtual ~Delegate() { } virtual ~Delegate() { }
...@@ -80,10 +81,20 @@ class CloudPrintURLFetcher ...@@ -80,10 +81,20 @@ class CloudPrintURLFetcher
virtual void OnRequestGiveUp() { } virtual void OnRequestGiveUp() { }
// Invoked when the request returns a 403 error (applicable only when // Invoked when the request returns a 403 error (applicable only when
// HandleRawResponse returns CONTINUE_PROCESSING). // HandleRawResponse returns CONTINUE_PROCESSING).
virtual void OnRequestAuthError() = 0; // Returning RETRY_REQUEST will retry current request. (auth information
// may have been updated and new info is available through the
// Authenticator interface).
// Returning CONTINUE_PROCESSING will treat auth error as a network error.
virtual ResponseAction OnRequestAuthError() = 0;
// Authentication information may change between retries.
// CloudPrintURLFetcher will request auth info before sending any request.
virtual std::string GetAuthHeader() = 0;
}; };
CloudPrintURLFetcher(); CloudPrintURLFetcher();
bool IsSameRequest(const content::URLFetcher* source);
void StartGetRequest(const GURL& url, void StartGetRequest(const GURL& url,
Delegate* delegate, Delegate* delegate,
int max_retries, int max_retries,
......
...@@ -84,8 +84,13 @@ class CloudPrintURLFetcherTest : public testing::Test, ...@@ -84,8 +84,13 @@ class CloudPrintURLFetcherTest : public testing::Test,
const net::ResponseCookies& cookies, const net::ResponseCookies& cookies,
const std::string& data); const std::string& data);
virtual void OnRequestAuthError() { virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError() {
ADD_FAILURE(); ADD_FAILURE();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
virtual std::string GetAuthHeader() {
return std::string();
} }
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() { scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() {
......
...@@ -89,7 +89,17 @@ CloudPrintURLFetcher::ResponseAction JobStatusUpdater::HandleJSONData( ...@@ -89,7 +89,17 @@ CloudPrintURLFetcher::ResponseAction JobStatusUpdater::HandleJSONData(
return CloudPrintURLFetcher::STOP_PROCESSING; return CloudPrintURLFetcher::STOP_PROCESSING;
} }
void JobStatusUpdater::OnRequestAuthError() { CloudPrintURLFetcher::ResponseAction JobStatusUpdater::OnRequestAuthError() {
// We got an Auth error and have no idea how long it will take to refresh
// auth information (may take forever). We'll drop current request and
// propagate this error to the upper level. After auth issues will be
// resolved, GCP connector will restart.
if (delegate_) if (delegate_)
delegate_->OnAuthError(); delegate_->OnAuthError();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
std::string JobStatusUpdater::GetAuthHeader() {
return CloudPrintHelpers::GetCloudPrintAuthHeader();
} }
...@@ -50,7 +50,8 @@ class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>, ...@@ -50,7 +50,8 @@ class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>,
const GURL& url, const GURL& url,
base::DictionaryValue* json_data, base::DictionaryValue* json_data,
bool succeeded); bool succeeded);
virtual void OnRequestAuthError(); virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
private: private:
std::string printer_name_; std::string printer_name_;
......
...@@ -33,12 +33,12 @@ class URLFetcher; ...@@ -33,12 +33,12 @@ class URLFetcher;
// | Have Pending tasks // | Have Pending tasks
// | // |
// | // |
// <----Delete Pending -- | ---Update Pending-----> // | ---Update Pending----->
// | | | // | |
// | | | // | |
// | | | // | |
// Delete Printer from server | Update Printer info on server // | Update Printer info on server
// Shutdown | Go to Stop // | Go to Stop
// | // |
// | Job Available // | Job Available
// | // |
...@@ -88,14 +88,10 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, ...@@ -88,14 +88,10 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
public: public:
class Delegate { class Delegate {
public: public:
virtual void OnPrinterJobHandlerShutdown( // Notify delegate about authentication error.
PrinterJobHandler* job_handler, const std::string& printer_id) = 0;
virtual void OnAuthError() = 0; virtual void OnAuthError() = 0;
// Called when the PrinterJobHandler cannot find the printer locally. The // Notify delegate that printer has been deleted.
// delegate returns |delete_from_server| to true if the printer should be virtual void OnPrinterDeleted(const std::string& printer_name) = 0;
// deleted from the server,false otherwise.
virtual void OnPrinterNotFound(const std::string& printer_name,
bool* delete_from_server) = 0;
protected: protected:
virtual ~Delegate() {} virtual ~Delegate() {}
...@@ -115,6 +111,7 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, ...@@ -115,6 +111,7 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
Delegate* delegate); Delegate* delegate);
virtual ~PrinterJobHandler(); virtual ~PrinterJobHandler();
bool Initialize(); bool Initialize();
std::string GetPrinterName() const;
// Requests a job check. |reason| is the reason for fetching the job. Used // Requests a job check. |reason| is the reason for fetching the job. Used
// for logging and diagnostc purposes. // for logging and diagnostc purposes.
void CheckForJobs(const std::string& reason); void CheckForJobs(const std::string& reason);
...@@ -143,7 +140,8 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, ...@@ -143,7 +140,8 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
base::DictionaryValue* json_data, base::DictionaryValue* json_data,
bool succeeded); bool succeeded);
virtual void OnRequestGiveUp(); virtual void OnRequestGiveUp();
virtual void OnRequestAuthError(); virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
// JobStatusUpdater::Delegate implementation // JobStatusUpdater::Delegate implementation
virtual bool OnJobCompleted(JobStatusUpdater* updater); virtual bool OnJobCompleted(JobStatusUpdater* updater);
...@@ -180,12 +178,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, ...@@ -180,12 +178,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
base::DictionaryValue* json_data, base::DictionaryValue* json_data,
bool succeeded); bool succeeded);
CloudPrintURLFetcher::ResponseAction HandlePrinterDeleteResponse(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse( CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse(
const content::URLFetcher* source, const content::URLFetcher* source,
const GURL& url, const GURL& url,
...@@ -288,7 +280,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, ...@@ -288,7 +280,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
// Flags that specify various pending server updates // Flags that specify various pending server updates
bool job_check_pending_; bool job_check_pending_;
bool printer_update_pending_; bool printer_update_pending_;
bool printer_delete_pending_;
// Some task in the state machine is in progress. // Some task in the state machine is in progress.
bool task_in_progress_; bool task_in_progress_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment