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 @@
'service/service_process_prefs.h',
'service/service_utility_process_host.cc',
'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.h',
'service/cloud_print/cloud_print_helpers.cc',
......
ajwong@chromium.org
dmaclach@chromium.org
hclam@chromium.org
sanjeevr@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";
const char kDefaultCloudPrintServerUrl[] = "https://www.google.com/cloudprint";
const char kCloudPrintGaiaServiceId[] = "cloudprint";
const char kSyncGaiaServiceId[] = "chromiumsync";
const char kProxyAuthUserAgent[] = "ChromiumBrowser";
const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com";
// The cloud print server expects the X-Google-CloudPrint-Proxy header for
// certain requests.
......
......@@ -18,6 +18,7 @@ extern const char kPrinterStatusValue[];
extern const char kPrinterTagValue[];
extern const char kPrinterRemoveTagValue[];
extern const char kMessageTextValue[];
// Values in the respone JSON from the cloud print server
extern const char kPrinterListValue[];
extern const char kSuccessValue[];
......@@ -38,6 +39,7 @@ extern const char kTagDryRunFlag[];
extern const char kDefaultCloudPrintServerUrl[];
extern const char kCloudPrintGaiaServiceId[];
extern const char kSyncGaiaServiceId[];
extern const char kProxyAuthUserAgent[];
extern const char kCloudPrintPushNotificationsSource[];
extern const char kChromeCloudPrintProxyHeader[];
extern const char kCloudPrintUserAgent[];
......@@ -56,6 +58,10 @@ extern const char kDefaultCloudPrintOAuthClientSecret[];
const int kJobDataMaxRetryCount = 5;
// Max retry count (infinity) for API fetch requests.
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
// print jobs. We choose a random interval in seconds between these 2 values.
......
......@@ -14,6 +14,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.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"
std::string StringFromJobStatus(cloud_print::PrintJobStatus status) {
......@@ -266,3 +267,20 @@ bool CloudPrintHelpers::IsDryRunJob(const std::vector<std::string>& tags) {
}
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 {
// Returns true is tags indicate a dry run (test) job.
static bool IsDryRunJob(const std::vector<std::string>& tags);
static std::string GetCloudPrintAuthHeader();
private:
CloudPrintHelpers() {
}
......
......@@ -158,7 +158,8 @@ bool CloudPrintProxy::CreateBackend() {
GURL cloud_print_server_url(cloud_print_server_url_str.c_str());
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,
oauth_client_info,
enable_job_poll));
......
......@@ -58,6 +58,7 @@ class CloudPrintProxyBackend {
// use system default settings.
CloudPrintProxyBackend(
CloudPrintProxyFrontend* frontend,
const std::string& proxy_id,
const GURL& cloud_print_server_url,
const base::DictionaryValue* print_sys_settings,
const gaia::OAuthClientInfo& oauth_client_info,
......
......@@ -16,7 +16,7 @@ CloudPrintTokenStore* CloudPrintTokenStore::current() {
return lazy_tls.Pointer()->Get();
}
CloudPrintTokenStore::CloudPrintTokenStore() : token_is_oauth_(false) {
CloudPrintTokenStore::CloudPrintTokenStore() {
lazy_tls.Pointer()->Set(this);
}
......@@ -24,8 +24,7 @@ CloudPrintTokenStore::~CloudPrintTokenStore() {
lazy_tls.Pointer()->Set(NULL);
}
void CloudPrintTokenStore::SetToken(const std::string& token, bool is_oauth) {
void CloudPrintTokenStore::SetToken(const std::string& token) {
DCHECK(CalledOnValidThread());
token_ = token;
token_is_oauth_ = is_oauth;
}
......@@ -23,19 +23,14 @@ class CloudPrintTokenStore : public base::NonThreadSafe {
CloudPrintTokenStore();
~CloudPrintTokenStore();
void SetToken(const std::string& token, bool is_oauth);
void SetToken(const std::string& token);
std::string token() const {
DCHECK(CalledOnValidThread());
return token_;
}
bool token_is_oauth() const {
DCHECK(CalledOnValidThread());
return token_is_oauth_;
}
private:
std::string token_;
bool token_is_oauth_;
DISALLOW_COPY_AND_ASSIGN(CloudPrintTokenStore);
};
......
......@@ -10,12 +10,8 @@ TEST(CloudPrintTokenStoreTest, Basic) {
EXPECT_EQ(NULL, CloudPrintTokenStore::current());
CloudPrintTokenStore* store = new CloudPrintTokenStore;
EXPECT_EQ(store, CloudPrintTokenStore::current());
CloudPrintTokenStore::current()->SetToken("myclientlogintoken", false);
CloudPrintTokenStore::current()->SetToken("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;
EXPECT_EQ(NULL, CloudPrintTokenStore::current());
}
......
......@@ -20,6 +20,10 @@ CloudPrintURLFetcher::CloudPrintURLFetcher()
num_retries_(0) {
}
bool CloudPrintURLFetcher::IsSameRequest(const content::URLFetcher* source) {
return (request_.get() == source);
}
void CloudPrintURLFetcher::StartGetRequest(
const GURL& url,
Delegate* delegate,
......@@ -65,15 +69,14 @@ void CloudPrintURLFetcher::OnURLFetchComplete(
source->GetResponseCode(),
source->GetCookies(),
data);
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;
// 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) {
// We need to retry on all network errors.
if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200))
action = RETRY_REQUEST;
......@@ -105,6 +108,12 @@ void CloudPrintURLFetcher::OnURLFetchComplete(
// be ignored.
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_;
if ((-1 != source->GetMaxRetries()) &&
(num_retries_ > source->GetMaxRetries())) {
......@@ -136,8 +145,8 @@ void CloudPrintURLFetcher::StartRequestHelper(
// Since we implement our own retry logic, disable the retry in URLFetcher.
request_->SetAutomaticallyRetryOn5xx(false);
request_->SetMaxRetries(max_retries);
SetupRequestHeaders();
delegate_ = delegate;
SetupRequestHeaders();
if (request_type == content::URLFetcher::POST) {
request_->SetUploadData(post_data_mime_type, post_data);
}
......@@ -146,14 +155,9 @@ void CloudPrintURLFetcher::StartRequestHelper(
}
void CloudPrintURLFetcher::SetupRequestHeaders() {
std::string headers;
CloudPrintTokenStore* token_store = CloudPrintTokenStore::current();
if (token_store) {
headers = token_store->token_is_oauth() ?
"Authorization: OAuth " : "Authorization: GoogleLogin auth=";
headers += token_store->token();
std::string headers = delegate_->GetAuthHeader();
if (!headers.empty())
headers += "\r\n";
}
headers += kChromeCloudPrintProxyHeader;
if (!additional_headers_.empty()) {
headers += "\r\n";
......
......@@ -38,6 +38,7 @@ class CloudPrintURLFetcher
STOP_PROCESSING,
RETRY_REQUEST,
};
class Delegate {
public:
virtual ~Delegate() { }
......@@ -80,10 +81,20 @@ class CloudPrintURLFetcher
virtual void OnRequestGiveUp() { }
// Invoked when the request returns a 403 error (applicable only when
// 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();
bool IsSameRequest(const content::URLFetcher* source);
void StartGetRequest(const GURL& url,
Delegate* delegate,
int max_retries,
......
......@@ -84,8 +84,13 @@ class CloudPrintURLFetcherTest : public testing::Test,
const net::ResponseCookies& cookies,
const std::string& data);
virtual void OnRequestAuthError() {
virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError() {
ADD_FAILURE();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
virtual std::string GetAuthHeader() {
return std::string();
}
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() {
......
......@@ -89,7 +89,17 @@ CloudPrintURLFetcher::ResponseAction JobStatusUpdater::HandleJSONData(
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_)
delegate_->OnAuthError();
return CloudPrintURLFetcher::STOP_PROCESSING;
}
std::string JobStatusUpdater::GetAuthHeader() {
return CloudPrintHelpers::GetCloudPrintAuthHeader();
}
......@@ -50,7 +50,8 @@ class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
virtual void OnRequestAuthError();
virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
private:
std::string printer_name_;
......
......@@ -33,12 +33,12 @@ class URLFetcher;
// | Have Pending tasks
// |
// |
// <----Delete Pending -- | ---Update Pending----->
// | | |
// | | |
// | | |
// Delete Printer from server | Update Printer info on server
// Shutdown | Go to Stop
// | ---Update Pending----->
// | |
// | |
// | |
// | Update Printer info on server
// | Go to Stop
// |
// | Job Available
// |
......@@ -88,14 +88,10 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
public:
class Delegate {
public:
virtual void OnPrinterJobHandlerShutdown(
PrinterJobHandler* job_handler, const std::string& printer_id) = 0;
// Notify delegate about authentication error.
virtual void OnAuthError() = 0;
// Called when the PrinterJobHandler cannot find the printer locally. The
// delegate returns |delete_from_server| to true if the printer should be
// deleted from the server,false otherwise.
virtual void OnPrinterNotFound(const std::string& printer_name,
bool* delete_from_server) = 0;
// Notify delegate that printer has been deleted.
virtual void OnPrinterDeleted(const std::string& printer_name) = 0;
protected:
virtual ~Delegate() {}
......@@ -115,6 +111,7 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
Delegate* delegate);
virtual ~PrinterJobHandler();
bool Initialize();
std::string GetPrinterName() const;
// Requests a job check. |reason| is the reason for fetching the job. Used
// for logging and diagnostc purposes.
void CheckForJobs(const std::string& reason);
......@@ -143,7 +140,8 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
base::DictionaryValue* json_data,
bool succeeded);
virtual void OnRequestGiveUp();
virtual void OnRequestAuthError();
virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
// JobStatusUpdater::Delegate implementation
virtual bool OnJobCompleted(JobStatusUpdater* updater);
......@@ -180,12 +178,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandlePrinterDeleteResponse(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse(
const content::URLFetcher* source,
const GURL& url,
......@@ -288,7 +280,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
// Flags that specify various pending server updates
bool job_check_pending_;
bool printer_update_pending_;
bool printer_delete_pending_;
// Some task in the state machine is 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