summaryrefslogtreecommitdiffstats
path: root/chrome/service
diff options
context:
space:
mode:
authorjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-29 08:44:34 +0000
committerjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-29 08:44:34 +0000
commitbdefb73bd8713903bfac8349ffdce7a88615eb38 (patch)
treeab8604065a577c3a91eac171ac9d7eef0b512d4e /chrome/service
parentf7e8432099722f41bd355b55b700ac5280a2127c (diff)
downloadchromium_src-bdefb73bd8713903bfac8349ffdce7a88615eb38.zip
chromium_src-bdefb73bd8713903bfac8349ffdce7a88615eb38.tar.gz
chromium_src-bdefb73bd8713903bfac8349ffdce7a88615eb38.tar.bz2
Revert 64359 - Created a CloudPrintURLFetcher class to wrap URLFetcher. This class implements a consistent retry policy based on URLFetcherProtectEntry and implements the standard error handling mechanism for all cloud print requests. Changed callers.
BUG=None TEST=Unit-tests provided, test cloud print procy request backoff. Review URL: http://codereview.chromium.org/4202006 TBR=sanjeevr@chromium.org Review URL: http://codereview.chromium.org/4089011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64380 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/service')
-rw-r--r--chrome/service/cloud_print/cloud_print_consts.cc4
-rw-r--r--chrome/service/cloud_print/cloud_print_consts.h13
-rw-r--r--chrome/service/cloud_print/cloud_print_helpers.cc42
-rw-r--r--chrome/service/cloud_print/cloud_print_helpers.h23
-rw-r--r--chrome/service/cloud_print/cloud_print_proxy_backend.cc300
-rw-r--r--chrome/service/cloud_print/cloud_print_proxy_backend.h3
-rw-r--r--chrome/service/cloud_print/cloud_print_url_fetcher.cc146
-rw-r--r--chrome/service/cloud_print/cloud_print_url_fetcher.h118
-rw-r--r--chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc342
-rw-r--r--chrome/service/cloud_print/job_status_updater.cc47
-rw-r--r--chrome/service/cloud_print/job_status_updater.h19
-rw-r--r--chrome/service/cloud_print/printer_job_handler.cc402
-rw-r--r--chrome/service/cloud_print/printer_job_handler.h147
13 files changed, 573 insertions, 1033 deletions
diff --git a/chrome/service/cloud_print/cloud_print_consts.cc b/chrome/service/cloud_print/cloud_print_consts.cc
index 6272a6d..7513875 100644
--- a/chrome/service/cloud_print/cloud_print_consts.cc
+++ b/chrome/service/cloud_print/cloud_print_consts.cc
@@ -39,7 +39,3 @@ const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com";
// certain requests.
const char kChromeCloudPrintProxyHeader[] = "X-Google-CloudPrint-Proxy: Chrome";
-// The request retry policy names. These strings are not valid hostnames, they
-// are just string keys.
-const char kCloudPrintAPIRetryPolicy[] = "cloudprint.google.com/api";
-const char kJobDataRetryPolicy[] = "cloudprint.google.com/jobdata";
diff --git a/chrome/service/cloud_print/cloud_print_consts.h b/chrome/service/cloud_print/cloud_print_consts.h
index 3c2fcc8..532f717 100644
--- a/chrome/service/cloud_print/cloud_print_consts.h
+++ b/chrome/service/cloud_print/cloud_print_consts.h
@@ -36,14 +36,11 @@ extern const char kCloudPrintGaiaServiceId[];
extern const char kSyncGaiaServiceId[];
extern const char kCloudPrintPushNotificationsSource[];
extern const char kChromeCloudPrintProxyHeader[];
-extern const char kCloudPrintAPIRetryPolicy[];
-extern const char kJobDataRetryPolicy[];
-
-// Max retry count for job data fetch requests.
-const int kJobDataMaxRetryCount = 5;
-// Look at CloudPrintProxyBackend::Core::CreateDefaultRetryPolicy for default
-// values of the request retry policy.
-
+// Max interval between retrying connection to the server
+const int64 kMaxRetryInterval = 5*60*1000; // 5 minutes in millseconds
+const int64 kBaseRetryInterval = 5*1000; // 5 seconds
+const int kMaxRetryCount = 2;
+const int64 kJobStatusUpdateInterval = 10*1000; // 10 seconds
// 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.
const int kMinJobPollIntervalSecs = 5*60; // 5 minutes in seconds
diff --git a/chrome/service/cloud_print/cloud_print_helpers.cc b/chrome/service/cloud_print/cloud_print_helpers.cc
index d03ddd0..fc132672 100644
--- a/chrome/service/cloud_print/cloud_print_helpers.cc
+++ b/chrome/service/cloud_print/cloud_print_helpers.cc
@@ -14,6 +14,7 @@
#include "base/values.h"
#include "chrome/service/cloud_print/cloud_print_consts.h"
#include "chrome/common/net/url_fetcher.h"
+#include "chrome/service/net/service_url_request_context.h"
#include "chrome/service/service_process.h"
std::string StringFromJobStatus(cloud_print::PrintJobStatus status) {
@@ -137,12 +138,14 @@ bool CloudPrintHelpers::ParseResponseJSON(
const std::string& response_data, bool* succeeded,
DictionaryValue** response_dict) {
scoped_ptr<Value> message_value(base::JSONReader::Read(response_data, false));
- if (!message_value.get())
+ if (!message_value.get()) {
+ NOTREACHED();
return false;
-
- if (!message_value->IsType(Value::TYPE_DICTIONARY))
+ }
+ if (!message_value->IsType(Value::TYPE_DICTIONARY)) {
+ NOTREACHED();
return false;
-
+ }
scoped_ptr<DictionaryValue> response_dict_local(
static_cast<DictionaryValue*>(message_value.release()));
if (succeeded)
@@ -152,6 +155,37 @@ bool CloudPrintHelpers::ParseResponseJSON(
return true;
}
+void CloudPrintHelpers::PrepCloudPrintRequest(URLFetcher* request,
+ const std::string& auth_token) {
+ DCHECK(g_service_process);
+ request->set_request_context(new ServiceURLRequestContextGetter());
+ std::string headers = "Authorization: GoogleLogin auth=";
+ headers += auth_token;
+ headers += "\r\n";
+ headers += kChromeCloudPrintProxyHeader;
+ request->set_extra_request_headers(headers);
+}
+
+void CloudPrintHelpers::HandleServerError(int* error_count, int max_retry_count,
+ int64 max_retry_interval,
+ int64 base_retry_interval,
+ Task* task_to_retry,
+ Task* task_on_give_up) {
+ (*error_count)++;
+ if ((-1 != max_retry_count) && (*error_count > max_retry_count)) {
+ if (task_on_give_up) {
+ MessageLoop::current()->PostTask(FROM_HERE, task_on_give_up);
+ }
+ } else {
+ int64 retry_interval = base_retry_interval * (*error_count);
+ if ((-1 != max_retry_interval) && (retry_interval > max_retry_interval)) {
+ retry_interval = max_retry_interval;
+ }
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, task_to_retry,
+ retry_interval);
+ }
+}
+
void CloudPrintHelpers::AddMultipartValueForUpload(
const std::string& value_name, const std::string& value,
const std::string& mime_boundary, const std::string& content_type,
diff --git a/chrome/service/cloud_print/cloud_print_helpers.h b/chrome/service/cloud_print/cloud_print_helpers.h
index 8e51f7a..c0bd61d 100644
--- a/chrome/service/cloud_print/cloud_print_helpers.h
+++ b/chrome/service/cloud_print/cloud_print_helpers.h
@@ -40,7 +40,28 @@ class CloudPrintHelpers {
// Returns the response as a dictionary value.
static bool ParseResponseJSON(const std::string& response_data,
bool* succeeded, DictionaryValue** response_dict);
-
+ // Sets up common parameters for a cloud print request
+ // (such as the GAIA auth token in the request headers, the request context
+ // etc).
+ static void PrepCloudPrintRequest(URLFetcher* request,
+ const std::string& auth_token);
+ // Strictly speaking, this helper method is not specific to cloud printing.
+ // It handles the logic to retry tasks when the server returns an error.
+ // The parameters are as below:
+ // |error_count| Contains the current number of consecutive failed attempts.
+ // This method increments it (in/out)
+ // |max_retry_count| Number of retries before giving up. -1 implies no limit.
+ // |max_retry_interval| Maximum amount of time (in ms) we are willing to
+ // wait between retries. -1 implies no limit.
+ // |base_retry_interval| Starting value of the retry interval. This
+ // method progressively increases the interval on each retry.
+ // |task_to_retry| The task to be retried.
+ // |task_on_give_up| Task to be performed when we give up. This is only
+ // valid when max_retry_count is not -1. It can be NULL.
+ static void HandleServerError(int* error_count, int max_retry_count,
+ int64 max_retry_interval,
+ int64 base_retry_interval,
+ Task* task_to_retry, Task* task_on_give_up);
// Prepares one value as part of a multi-part upload request.
static void AddMultipartValueForUpload(
const std::string& value_name, const std::string& value,
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
index 99158d3..38fa3d4 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
@@ -14,10 +14,9 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/common/net/url_fetcher_protect.h"
+#include "chrome/common/net/http_return.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_url_fetcher.h"
#include "chrome/service/cloud_print/printer_job_handler.h"
#include "chrome/service/gaia/service_gaia_authenticator.h"
#include "chrome/service/service_process.h"
@@ -30,7 +29,7 @@
// The real guts of CloudPrintProxyBackend, to keep the public client API clean.
class CloudPrintProxyBackend::Core
: public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>,
- public CloudPrintURLFetcherDelegate,
+ public URLFetcherDelegate,
public cloud_print::PrintServerWatcherDelegate,
public PrinterJobHandlerDelegate,
public notifier::TalkMediator::Delegate {
@@ -63,15 +62,12 @@ class CloudPrintProxyBackend::Core
void DoRegisterSelectedPrinters(
const printing::PrinterList& printer_list);
- // CloudPrintURLFetcher::Delegate implementation.
- virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- virtual void OnRequestAuthError();
-
+ // URLFetcher::Delegate implementation.
+ virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
// cloud_print::PrintServerWatcherDelegate implementation
virtual void OnPrinterAdded();
// PrinterJobHandler::Delegate implementation
@@ -86,26 +82,24 @@ class CloudPrintProxyBackend::Core
const IncomingNotificationData& notification_data);
virtual void OnOutgoingNotification();
- private:
+ protected:
// Prototype for a response handler.
- typedef CloudPrintURLFetcher::ResponseAction
- (CloudPrintProxyBackend::Core::*ResponseHandler)(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
+ typedef void (CloudPrintProxyBackend::Core::*ResponseHandler)(
+ const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status, int response_code,
+ const ResponseCookies& cookies, const std::string& data);
// Begin response handlers
- CloudPrintURLFetcher::ResponseAction HandlePrinterListResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- CloudPrintURLFetcher::ResponseAction HandleRegisterPrinterResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
+ void HandlePrinterListResponse(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ void HandleRegisterPrinterResponse(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
// End response handlers
// NotifyXXX is how the Core communicates with the frontend across
@@ -118,8 +112,6 @@ class CloudPrintProxyBackend::Core
const std::string& email);
void NotifyAuthenticationFailed();
- URLFetcherProtectEntry* CreateDefaultRetryPolicy();
-
// Starts a new printer registration process.
void StartRegistration();
// Ends the printer registration process.
@@ -130,6 +122,7 @@ class CloudPrintProxyBackend::Core
// Retrieves the list of registered printers for this user/proxy combination
// from the cloud print server.
void GetRegisteredPrinters();
+ void HandleServerError(Task* task_to_retry);
// Removes the given printer from the list. Returns false if the printer
// did not exist in the list.
bool RemovePrinterFromList(const std::string& printer_name);
@@ -159,14 +152,16 @@ class CloudPrintProxyBackend::Core
// user a chance to further trim the list. When the frontend gives us the
// final list we make a copy into this so that we can start registering.
printing::PrinterList printer_list_;
- // The CloudPrintURLFetcher instance for the current request.
- scoped_refptr<CloudPrintURLFetcher> request_;
+ // The URLFetcher instance for the current request
+ scoped_ptr<URLFetcher> request_;
// The index of the nex printer to be uploaded.
size_t next_upload_index_;
// The unique id for this proxy
std::string proxy_id_;
// The GAIA auth token
std::string auth_token_;
+ // The number of consecutive times that connecting to the server failed.
+ int server_error_count_;
// Cached info about the last printer that we tried to upload. We cache this
// so we won't have to requery the printer if the upload fails and we need
// to retry.
@@ -253,13 +248,10 @@ void CloudPrintProxyBackend::RegisterPrinters(
CloudPrintProxyBackend::Core::Core(CloudPrintProxyBackend* backend,
const GURL& cloud_print_server_url,
const DictionaryValue* print_system_settings)
- : backend_(backend),
- cloud_print_server_url_(cloud_print_server_url),
- next_upload_index_(0),
- next_response_handler_(NULL),
- new_printers_available_(false),
- notifications_enabled_(false),
- job_poll_scheduled_(false) {
+ : backend_(backend), cloud_print_server_url_(cloud_print_server_url),
+ next_upload_index_(0), server_error_count_(0),
+ next_response_handler_(NULL), new_printers_available_(false),
+ notifications_enabled_(false), job_poll_scheduled_(false) {
if (print_system_settings) {
// It is possible to have no print settings specified.
print_system_settings_.reset(
@@ -350,41 +342,14 @@ void CloudPrintProxyBackend::Core::DoInitializeWithToken(
print_server_watcher_->StartWatching(this);
proxy_id_ = proxy_id;
-
- // Register the request retry policies for cloud print APIs and job data
- // requests.
- URLFetcherProtectManager::GetInstance()->Register(
- kCloudPrintAPIRetryPolicy, CreateDefaultRetryPolicy());
- URLFetcherProtectManager::GetInstance()->Register(
- kJobDataRetryPolicy, CreateDefaultRetryPolicy())->SetMaxRetries(
- kJobDataMaxRetryCount);
-
StartRegistration();
}
-URLFetcherProtectEntry*
-CloudPrintProxyBackend::Core::CreateDefaultRetryPolicy() {
- // Times are in milliseconds.
- const int kSlidingWindowPeriod = 2000;
- const int kMaxSendThreshold = 20;
- const int kMaxRetries = -1;
- const int kInitialTimeout = 100;
- const double kMultiplier = 2.0;
- const int kConstantFactor = 100;
- const int kMaximumTimeout = 5*60*1000;
- return new URLFetcherProtectEntry(kSlidingWindowPeriod,
- kMaxSendThreshold,
- kMaxRetries,
- kInitialTimeout,
- kMultiplier,
- kConstantFactor,
- kMaximumTimeout);
-}
-
void CloudPrintProxyBackend::Core::StartRegistration() {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
printer_list_.clear();
print_system_->GetPrintBackend()->EnumeratePrinters(&printer_list_);
+ server_error_count_ = 0;
// Now we need to ask the server about printers that were registered on the
// server so that we can trim this list.
GetRegisteredPrinters();
@@ -392,7 +357,7 @@ void CloudPrintProxyBackend::Core::StartRegistration() {
void CloudPrintProxyBackend::Core::EndRegistration() {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
- request_ = NULL;
+ request_.reset();
if (new_printers_available_) {
new_printers_available_ = false;
StartRegistration();
@@ -415,7 +380,7 @@ void CloudPrintProxyBackend::Core::DoShutdown() {
// Important to delete the TalkMediator on this thread.
talk_mediator_.reset();
notifications_enabled_ = false;
- request_ = NULL;
+ request_.reset();
MessageLoop::current()->QuitNow();
}
@@ -424,6 +389,7 @@ void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters(
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
if (!print_system_.get())
return; // No print system available.
+ server_error_count_ = 0;
printer_list_.assign(printer_list.begin(), printer_list.end());
next_upload_index_ = 0;
RegisterNextPrinter();
@@ -431,14 +397,15 @@ void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters(
void CloudPrintProxyBackend::Core::GetRegisteredPrinters() {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
- GURL printer_list_url =
- CloudPrintHelpers::GetUrlForPrinterList(cloud_print_server_url_,
- proxy_id_);
+ request_.reset(
+ new URLFetcher(
+ CloudPrintHelpers::GetUrlForPrinterList(cloud_print_server_url_,
+ proxy_id_),
+ URLFetcher::GET, this));
+ CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
next_response_handler_ =
&CloudPrintProxyBackend::Core::HandlePrinterListResponse;
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(printer_list_url, this, auth_token_,
- kCloudPrintAPIRetryPolicy);
+ request_->Start();
}
void CloudPrintProxyBackend::Core::RegisterNextPrinter() {
@@ -498,16 +465,16 @@ void CloudPrintProxyBackend::Core::RegisterNextPrinter() {
post_data.append("--" + mime_boundary + "--\r\n");
std::string mime_type("multipart/form-data; boundary=");
mime_type += mime_boundary;
- GURL register_url = CloudPrintHelpers::GetUrlForPrinterRegistration(
- cloud_print_server_url_);
-
+ request_.reset(
+ new URLFetcher(
+ CloudPrintHelpers::GetUrlForPrinterRegistration(
+ cloud_print_server_url_),
+ URLFetcher::POST, this));
+ CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
+ request_->set_upload_data(mime_type, post_data);
next_response_handler_ =
&CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse;
- request_ = new CloudPrintURLFetcher;
- request_->StartPostRequest(register_url, this, auth_token_,
- kCloudPrintAPIRetryPolicy, mime_type,
- post_data);
-
+ request_->Start();
} else {
LOG(ERROR) << "CP_PROXY: Failed to get printer info for: " <<
info.printer_name;
@@ -554,19 +521,23 @@ void CloudPrintProxyBackend::Core::ScheduleJobPoll() {
}
}
-// CloudPrintURLFetcher::Delegate implementation.
-CloudPrintURLFetcher::ResponseAction
-CloudPrintProxyBackend::Core::HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- DCHECK(next_response_handler_);
- return (this->*next_response_handler_)(source, url, json_data, succeeded);
-}
-
-void CloudPrintProxyBackend::Core::OnRequestAuthError() {
- OnAuthError();
+// URLFetcher::Delegate implementation.
+void CloudPrintProxyBackend::Core::OnURLFetchComplete(
+ const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
+ int response_code, const ResponseCookies& cookies,
+ const std::string& data) {
+ DCHECK(source == request_.get());
+ // If we get an auth error, we need to give up right away and notify the
+ // frontend loop.
+ if (RC_FORBIDDEN == response_code) {
+ backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &Core::NotifyAuthenticationFailed));
+ } else {
+ // We need a next response handler
+ DCHECK(next_response_handler_);
+ (this->*next_response_handler_)(source, url, status, response_code,
+ cookies, data);
+ }
}
void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable(
@@ -589,44 +560,53 @@ void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() {
backend_->frontend_->OnAuthenticationFailed();
}
-CloudPrintURLFetcher::ResponseAction
-CloudPrintProxyBackend::Core::HandlePrinterListResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
+void CloudPrintProxyBackend::Core::HandlePrinterListResponse(
+ const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
+ int response_code, const ResponseCookies& cookies,
+ const std::string& data) {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
- if (!succeeded) {
- NOTREACHED();
- return CloudPrintURLFetcher::RETRY_REQUEST;
- }
- ListValue* printer_list = NULL;
- json_data->GetList(kPrinterListValue, &printer_list);
- // There may be no "printers" value in the JSON
- if (printer_list) {
- for (size_t index = 0; index < printer_list->GetSize(); index++) {
- DictionaryValue* printer_data = NULL;
- if (printer_list->GetDictionary(index, &printer_data)) {
- std::string printer_name;
- printer_data->GetString(kNameValue, &printer_name);
- RemovePrinterFromList(printer_name);
- InitJobHandlerForPrinter(printer_data);
+ bool succeeded = false;
+ if (status.is_success() && response_code == 200) {
+ server_error_count_ = 0;
+ // Parse the response JSON for the list of printers already registered.
+ DictionaryValue* response_dict_temp = NULL;
+ CloudPrintHelpers::ParseResponseJSON(data, &succeeded,
+ &response_dict_temp);
+ scoped_ptr<DictionaryValue> response_dict;
+ response_dict.reset(response_dict_temp);
+ if (succeeded) {
+ DCHECK(response_dict.get());
+ ListValue* printer_list = NULL;
+ response_dict->GetList(kPrinterListValue, &printer_list);
+ // There may be no "printers" value in the JSON
+ if (printer_list) {
+ for (size_t index = 0; index < printer_list->GetSize(); index++) {
+ DictionaryValue* printer_data = NULL;
+ if (printer_list->GetDictionary(index, &printer_data)) {
+ std::string printer_name;
+ printer_data->GetString(kNameValue, &printer_name);
+ RemovePrinterFromList(printer_name);
+ InitJobHandlerForPrinter(printer_data);
+ } else {
+ NOTREACHED();
+ }
+ }
+ }
+ MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release());
+ if (!printer_list_.empty()) {
+ // Let the frontend know that we have a list of printers available.
+ backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &Core::NotifyPrinterListAvailable, printer_list_));
} else {
- NOTREACHED();
+ // No more work to be done here.
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &Core::EndRegistration));
}
}
}
- request_ = NULL;
- if (!printer_list_.empty()) {
- // Let the frontend know that we have a list of printers available.
- backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
- &Core::NotifyPrinterListAvailable, printer_list_));
- } else {
- // No more work to be done here.
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &Core::EndRegistration));
- }
- return CloudPrintURLFetcher::STOP_PROCESSING;
+
+ if (!succeeded)
+ HandleServerError(NewRunnableMethod(this, &Core::GetRegisteredPrinters));
}
void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter(
@@ -675,30 +655,46 @@ void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter(
}
}
-CloudPrintURLFetcher::ResponseAction
-CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
+void CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse(
+ const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
+ int response_code, const ResponseCookies& cookies,
+ const std::string& data) {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
- if (succeeded) {
- ListValue* printer_list = NULL;
- json_data->GetList(kPrinterListValue, &printer_list);
- // There should be a "printers" value in the JSON
- DCHECK(printer_list);
- if (printer_list) {
- DictionaryValue* printer_data = NULL;
- if (printer_list->GetDictionary(0, &printer_data))
- InitJobHandlerForPrinter(printer_data);
+ VLOG(1) << "CP_PROXY: Handle register printer response, code: "
+ << response_code;
+ Task* next_task =
+ NewRunnableMethod(this,
+ &CloudPrintProxyBackend::Core::RegisterNextPrinter);
+ if (status.is_success() && (response_code == 200)) {
+ bool succeeded = false;
+ DictionaryValue* response_dict = NULL;
+ CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
+ if (succeeded) {
+ DCHECK(response_dict);
+ ListValue* printer_list = NULL;
+ response_dict->GetList(kPrinterListValue, &printer_list);
+ // There should be a "printers" value in the JSON
+ DCHECK(printer_list);
+ if (printer_list) {
+ DictionaryValue* printer_data = NULL;
+ if (printer_list->GetDictionary(0, &printer_data))
+ InitJobHandlerForPrinter(printer_data);
+ }
}
+ server_error_count_ = 0;
+ next_upload_index_++;
+ MessageLoop::current()->PostTask(FROM_HERE, next_task);
+ } else {
+ HandleServerError(next_task);
}
- next_upload_index_++;
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &CloudPrintProxyBackend::Core::RegisterNextPrinter));
- return CloudPrintURLFetcher::STOP_PROCESSING;
+}
+
+void CloudPrintProxyBackend::Core::HandleServerError(Task* task_to_retry) {
+ DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
+ VLOG(1) << "CP_PROXY: Server error.";
+ CloudPrintHelpers::HandleServerError(
+ &server_error_count_, -1, kMaxRetryInterval, kBaseRetryInterval,
+ task_to_retry, NULL);
}
bool CloudPrintProxyBackend::Core::RemovePrinterFromList(
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.h b/chrome/service/cloud_print/cloud_print_proxy_backend.h
index 7e82190..931fd91 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.h
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.h
@@ -9,10 +9,11 @@
#include <string>
#include "base/thread.h"
+#include "chrome/common/net/url_fetcher.h"
+#include "googleurl/src/gurl.h"
#include "printing/backend/print_backend.h"
class CloudPrintProxyService;
-class GURL;
class DictionaryValue;
// CloudPrintProxyFrontend is the interface used by CloudPrintProxyBackend to
diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher.cc b/chrome/service/cloud_print/cloud_print_url_fetcher.cc
deleted file mode 100644
index ff560d8..0000000
--- a/chrome/service/cloud_print/cloud_print_url_fetcher.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2010 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_url_fetcher.h"
-
-#include "base/values.h"
-#include "chrome/common/net/http_return.h"
-#include "chrome/common/net/url_fetcher_protect.h"
-#include "chrome/service/cloud_print/cloud_print_consts.h"
-#include "chrome/service/cloud_print/cloud_print_helpers.h"
-#include "chrome/service/net/service_url_request_context.h"
-#include "googleurl/src/gurl.h"
-#include "net/url_request/url_request_status.h"
-
-CloudPrintURLFetcher::CloudPrintURLFetcher()
- : protect_entry_(NULL), num_retries_(0) {
-}
-
-void CloudPrintURLFetcher::StartGetRequest(const GURL& url,
- Delegate* delegate,
- const std::string& auth_token,
- const std::string& retry_policy) {
- StartRequestHelper(url, URLFetcher::GET, delegate, auth_token, retry_policy,
- std::string(), std::string());
-}
-
-void CloudPrintURLFetcher::StartPostRequest(
- const GURL& url,
- Delegate* delegate,
- const std::string& auth_token,
- const std::string& retry_policy,
- const std::string& post_data_mime_type,
- const std::string& post_data) {
- StartRequestHelper(url, URLFetcher::POST, delegate, auth_token, retry_policy,
- post_data_mime_type, post_data);
-}
-
- // URLFetcher::Delegate implementation.
-void CloudPrintURLFetcher::OnURLFetchComplete(
- const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data) {
- VLOG(1) << "CP_PROXY: OnURLFetchComplete, url: " << url
- << ", response code: " << response_code;
- // Make sure we stay alive through the body of this function.
- scoped_refptr<CloudPrintURLFetcher> keep_alive(this);
- ResponseAction action = delegate_->HandleRawResponse(source,
- url,
- status,
- response_code,
- cookies,
- data);
- if (action == CONTINUE_PROCESSING) {
- // If there was an auth error, we are done.
- if (RC_FORBIDDEN == response_code) {
- delegate_->OnRequestAuthError();
- return;
- }
- // We need to retry on all network errors.
- if (!status.is_success() || (response_code != 200))
- action = RETRY_REQUEST;
- else
- action = delegate_->HandleRawData(source, url, data);
-
- if (action == CONTINUE_PROCESSING) {
- // If the delegate is not interested in handling the raw response data,
- // we assume that a JSON response is expected. If we do not get a JSON
- // response, we will retry (to handle the case where we got redirected
- // to a non-cloudprint-server URL eg. for authentication).
- bool succeeded = false;
- DictionaryValue* response_dict = NULL;
- CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
- if (response_dict)
- action = delegate_->HandleJSONData(source,
- url,
- response_dict,
- succeeded);
- else
- action = RETRY_REQUEST;
- }
- }
- // Retry the request if needed.
- if (action == RETRY_REQUEST) {
- int64 back_off_time =
- protect_entry_->UpdateBackoff(URLFetcherProtectEntry::FAILURE);
- ++num_retries_;
- int max_retries = protect_entry_->max_retries();
- if ((-1 != max_retries) && (num_retries_ > max_retries)) {
- // Retry limit reached. Give up.
- delegate_->OnRequestGiveUp();
- } else {
- // Either no retry limit specified or retry limit has not yet been
- // reached. Try again.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- NewRunnableMethod(this, &CloudPrintURLFetcher::StartRequestNow),
- back_off_time);
- }
- } else {
- protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SUCCESS);
- }
-}
-
-void CloudPrintURLFetcher::StartRequestHelper(
- const GURL& url,
- URLFetcher::RequestType request_type,
- Delegate* delegate,
- const std::string& auth_token,
- const std::string& retry_policy,
- const std::string& post_data_mime_type,
- const std::string& post_data) {
- DCHECK(delegate);
- request_.reset(new URLFetcher(url, request_type, this));
- request_->set_request_context(GetRequestContextGetter());
- // Since we implement our own retry logic, disable the retry in URLFetcher.
- request_->set_automatically_retry_on_5xx(false);
- delegate_ = delegate;
- std::string headers = "Authorization: GoogleLogin auth=";
- headers += auth_token;
- headers += "\r\n";
- headers += kChromeCloudPrintProxyHeader;
- request_->set_extra_request_headers(headers);
- if (request_type == URLFetcher::POST) {
- request_->set_upload_data(post_data_mime_type, post_data);
- }
- // Initialize the retry policy for this request.
- protect_entry_ =
- URLFetcherProtectManager::GetInstance()->Register(retry_policy);
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- NewRunnableMethod(this, &CloudPrintURLFetcher::StartRequestNow),
- protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SEND));
-}
-
-void CloudPrintURLFetcher::StartRequestNow() {
- request_->Start();
-}
-
-URLRequestContextGetter* CloudPrintURLFetcher::GetRequestContextGetter() {
- return new ServiceURLRequestContextGetter();
-}
-
diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher.h b/chrome/service/cloud_print/cloud_print_url_fetcher.h
deleted file mode 100644
index 5ed69fc..0000000
--- a/chrome/service/cloud_print/cloud_print_url_fetcher.h
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2010 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_URL_FETCHER_H_
-#define CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_URL_FETCHER_H_
-#pragma once
-
-#include <string>
-
-#include "chrome/common/net/url_fetcher.h"
-
-class DictionaryValue;
-class GURL;
-class URLFetcherProtectEntry;
-class URLRequestStatus;
-
-// A wrapper around URLFetcher for CloudPrint. URLFetcher applies retry logic
-// only on HTTP response codes >= 500. In the cloud print case, we want to
-// retry on all network errors. In addition, we want to treat non-JSON responses
-// (for all CloudPrint APIs that expect JSON responses) as errors and they
-// must also be retried. Also URLFetcher uses the host name of the URL as the
-// key for applying the retry policy. In our case, we want to apply one global
-// policy for many requests (not necessarily scoped by hostname).
-class CloudPrintURLFetcher
- : public base::RefCountedThreadSafe<CloudPrintURLFetcher>,
- public URLFetcher::Delegate {
- public:
- enum ResponseAction {
- CONTINUE_PROCESSING,
- STOP_PROCESSING,
- RETRY_REQUEST,
- };
- class Delegate {
- public:
- virtual ~Delegate() { }
- // Override this to handle the raw response as it is available. No response
- // error checking is done before this method is called. If the delegate
- // returns CONTINUE_PROCESSING, we will then check for network
- // errors. Most implementations will not override this.
- virtual ResponseAction HandleRawResponse(const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data) {
- return CONTINUE_PROCESSING;
- }
- // This will be invoked only if HandleRawResponse returns
- // CONTINUE_PROCESSING AND if there are no network errors and the HTTP
- // response code is 200. The delegate implementation returns
- // CONTINUE_PROCESSING if it does not want to handle the raw data itself.
- // Handling the raw data is needed when the expected response is NOT JSON
- // (like in the case of a print ticket response or a print job download
- // response).
- virtual ResponseAction HandleRawData(const URLFetcher* source,
- const GURL& url,
- const std::string& data) {
- return CONTINUE_PROCESSING;
- }
- // This will be invoked only if HandleRawResponse and HandleRawData return
- // CONTINUE_PROCESSING AND if the response contains a valid JSON dictionary.
- // |succeeded| is the value of the "success" field in the response JSON.
- virtual ResponseAction HandleJSONData(const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- return CONTINUE_PROCESSING;
- }
- // Invoked when the retry limit for this request has been reached (if there
- // was a retry limit - a limit of -1 implies no limit).
- virtual void OnRequestGiveUp() { }
- // Invoked when the request returns a 403 error (applicable only when
- // HandleRawResponse returns CONTINUE_PROCESSING)
- virtual void OnRequestAuthError() = 0;
- };
- CloudPrintURLFetcher();
-
- void StartGetRequest(const GURL& url,
- Delegate* delegate,
- const std::string& auth_token,
- const std::string& retry_policy);
- void StartPostRequest(const GURL& url,
- Delegate* delegate,
- const std::string& auth_token,
- const std::string& retry_policy,
- const std::string& post_data_mime_type,
- const std::string& post_data);
-
- // URLFetcher::Delegate implementation.
- virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data);
- protected:
- // Virtual for testing.
- virtual URLRequestContextGetter* GetRequestContextGetter();
-
- private:
- void StartRequestHelper(const GURL& url,
- URLFetcher::RequestType request_type,
- Delegate* delegate,
- const std::string& auth_token,
- const std::string& retry_policy,
- const std::string& post_data_mime_type,
- const std::string& post_data);
- void StartRequestNow();
-
- scoped_ptr<URLFetcher> request_;
- Delegate* delegate_;
- URLFetcherProtectEntry* protect_entry_;
- int num_retries_;
-};
-
-typedef CloudPrintURLFetcher::Delegate CloudPrintURLFetcherDelegate;
-
-#endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_URL_FETCHER_H_
diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc
deleted file mode 100644
index 18577e6..0000000
--- a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright (c) 2010 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 "base/command_line.h"
-#include "base/message_loop_proxy.h"
-#include "base/ref_counted.h"
-#include "base/thread.h"
-#include "base/waitable_event.h"
-#include "chrome/common/net/url_fetcher_protect.h"
-#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/service/service_process.h"
-#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
-#include "googleurl/src/gurl.h"
-#include "net/test/test_server.h"
-#include "net/url_request/url_request_unittest.h"
-#include "net/url_request/url_request_status.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::Time;
-using base::TimeDelta;
-
-namespace {
-
-const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
-
-class TestURLRequestContextGetter : public URLRequestContextGetter {
- public:
- explicit TestURLRequestContextGetter(
- base::MessageLoopProxy* io_message_loop_proxy)
- : io_message_loop_proxy_(io_message_loop_proxy) {
- }
- virtual URLRequestContext* GetURLRequestContext() {
- if (!context_)
- context_ = new TestURLRequestContext();
- return context_;
- }
- virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const {
- return io_message_loop_proxy_;
- }
-
- protected:
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
-
- private:
- ~TestURLRequestContextGetter() {}
-
- scoped_refptr<URLRequestContext> context_;
-};
-
-class TestCloudPrintURLFetcher : public CloudPrintURLFetcher {
- public:
- explicit TestCloudPrintURLFetcher(
- base::MessageLoopProxy* io_message_loop_proxy)
- : io_message_loop_proxy_(io_message_loop_proxy) {
- }
-
- virtual URLRequestContextGetter* GetRequestContextGetter() {
- return new TestURLRequestContextGetter(io_message_loop_proxy_.get());
- }
- private:
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
-};
-
-class CloudPrintURLFetcherTest : public testing::Test,
- public CloudPrintURLFetcher::Delegate {
- public:
- CloudPrintURLFetcherTest() : fetcher_(NULL) { }
-
- // Creates a URLFetcher, using the program's main thread to do IO.
- virtual void CreateFetcher(const GURL& url, const std::string& retry_policy);
-
- // CloudPrintURLFetcher::Delegate
- virtual CloudPrintURLFetcher::ResponseAction HandleRawResponse(
- const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data);
-
- virtual void OnRequestAuthError() {
- ADD_FAILURE();
- }
-
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() {
- return io_message_loop_proxy_;
- }
-
- protected:
- virtual void SetUp() {
- testing::Test::SetUp();
-
- io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
- }
-
- // URLFetcher is designed to run on the main UI thread, but in our tests
- // we assume that the current thread is the IO thread where the URLFetcher
- // dispatches its requests to. When we wish to simulate being used from
- // a UI thread, we dispatch a worker thread to do so.
- MessageLoopForIO io_loop_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
- std::string retry_policy_;
- Time start_time_;
- scoped_refptr<CloudPrintURLFetcher> fetcher_;
-};
-
-class CloudPrintURLFetcherBasicTest : public CloudPrintURLFetcherTest {
- public:
- CloudPrintURLFetcherBasicTest()
- : handle_raw_response_(false), handle_raw_data_(false) { }
- // CloudPrintURLFetcher::Delegate
- virtual CloudPrintURLFetcher::ResponseAction HandleRawResponse(
- const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data);
-
- virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data);
-
- virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- void SetHandleRawResponse(bool handle_raw_response) {
- handle_raw_response_ = handle_raw_response;
- }
- void SetHandleRawData(bool handle_raw_data) {
- handle_raw_data_ = handle_raw_data;
- }
- private:
- bool handle_raw_response_;
- bool handle_raw_data_;
-};
-
-// Version of CloudPrintURLFetcherTest that tests overload protection.
-class CloudPrintURLFetcherOverloadTest : public CloudPrintURLFetcherTest {
- public:
- CloudPrintURLFetcherOverloadTest() : response_count_(0) {
- }
-
- // CloudPrintURLFetcher::Delegate
- virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data);
-
- private:
- int response_count_;
-};
-
-// Version of CloudPrintURLFetcherTest that tests backoff protection.
-class CloudPrintURLFetcherRetryBackoffTest : public CloudPrintURLFetcherTest {
- public:
- CloudPrintURLFetcherRetryBackoffTest() : response_count_(0) {
- }
-
- // CloudPrintURLFetcher::Delegate
- virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data);
-
- virtual void OnRequestGiveUp();
-
- private:
- int response_count_;
-};
-
-
-void CloudPrintURLFetcherTest::CreateFetcher(const GURL& url,
- const std::string& retry_policy) {
- fetcher_ = new TestCloudPrintURLFetcher(io_message_loop_proxy());
- retry_policy_ = retry_policy;
- start_time_ = Time::Now();
- fetcher_->StartGetRequest(url, this, "", retry_policy_);
-}
-
-CloudPrintURLFetcher::ResponseAction
-CloudPrintURLFetcherTest::HandleRawResponse(
- const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data) {
- EXPECT_TRUE(status.is_success());
- EXPECT_EQ(200, response_code); // HTTP OK
- EXPECT_FALSE(data.empty());
- return CloudPrintURLFetcher::CONTINUE_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-CloudPrintURLFetcherBasicTest::HandleRawResponse(
- const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data) {
- EXPECT_TRUE(status.is_success());
- EXPECT_EQ(200, response_code); // HTTP OK
- EXPECT_FALSE(data.empty());
-
- fetcher_ = NULL;
-
- if (handle_raw_response_) {
- // If the current message loop is not the IO loop, it will be shut down when
- // the main loop returns and this thread subsequently goes out of scope.
- io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- return CloudPrintURLFetcher::STOP_PROCESSING;
- }
- return CloudPrintURLFetcher::CONTINUE_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-CloudPrintURLFetcherBasicTest::HandleRawData(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data) {
- // We should never get here if we returned true in HandleRawResponse
- EXPECT_FALSE(handle_raw_response_);
- if (handle_raw_data_) {
- io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- return CloudPrintURLFetcher::STOP_PROCESSING;
- }
- return CloudPrintURLFetcher::CONTINUE_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-CloudPrintURLFetcherBasicTest::HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- // We should never get here if we returned true in one of the above methods.
- EXPECT_FALSE(handle_raw_response_);
- EXPECT_FALSE(handle_raw_data_);
- io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- return CloudPrintURLFetcher::STOP_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-CloudPrintURLFetcherOverloadTest::HandleRawData(const URLFetcher* source,
- const GURL& url,
- const std::string& data) {
- const TimeDelta one_second = TimeDelta::FromMilliseconds(1000);
- response_count_++;
- if (response_count_ < 20) {
- fetcher_->StartGetRequest(url, this, "", retry_policy_);
- } else {
- // We have already sent 20 requests continuously. And we expect that
- // it takes more than 1 second due to the overload pretection settings.
- EXPECT_TRUE(Time::Now() - start_time_ >= one_second);
- io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- }
- return CloudPrintURLFetcher::STOP_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-CloudPrintURLFetcherRetryBackoffTest::HandleRawData(const URLFetcher* source,
- const GURL& url,
- const std::string& data) {
- response_count_++;
- // First attempt + 11 retries = 12 total responses.
- EXPECT_LE(response_count_, 12);
- return CloudPrintURLFetcher::RETRY_REQUEST;
-}
-
-void CloudPrintURLFetcherRetryBackoffTest::OnRequestGiveUp() {
- const TimeDelta one_second = TimeDelta::FromMilliseconds(1000);
- // It takes more than 1 second to finish all 11 requests.
- EXPECT_TRUE(Time::Now() - start_time_ >= one_second);
- io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
-}
-
-TEST_F(CloudPrintURLFetcherBasicTest, HandleRawResponse) {
- net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
- ASSERT_TRUE(test_server.Start());
- SetHandleRawResponse(true);
-
- CreateFetcher(test_server.GetURL("echo"), "DummyRetryPolicy");
- MessageLoop::current()->Run();
-}
-
-TEST_F(CloudPrintURLFetcherBasicTest, HandleRawData) {
- net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
- ASSERT_TRUE(test_server.Start());
-
- SetHandleRawData(true);
- CreateFetcher(test_server.GetURL("echo"), "DummyRetryPolicy");
- MessageLoop::current()->Run();
-}
-
-TEST_F(CloudPrintURLFetcherOverloadTest, Protect) {
- net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
- ASSERT_TRUE(test_server.Start());
-
- GURL url(test_server.GetURL("defaultresponse"));
-
- // Registers an entry for test url. It only allows 3 requests to be sent
- // in 200 milliseconds.
- std::string retry_policy = "OverloadTestPolicy";
- URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance();
- URLFetcherProtectEntry* entry =
- new URLFetcherProtectEntry(200, 3, 11, 1, 2.0, 0, 256);
- manager->Register(retry_policy, entry);
-
- CreateFetcher(url, retry_policy);
-
- MessageLoop::current()->Run();
-}
-
-TEST_F(CloudPrintURLFetcherRetryBackoffTest, GiveUp) {
- net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
- ASSERT_TRUE(test_server.Start());
-
- GURL url(test_server.GetURL("defaultresponse"));
-
- // Registers an entry for test url. The backoff time is calculated by:
- // new_backoff = 2.0 * old_backoff + 0
- // and maximum backoff time is 256 milliseconds.
- // Maximum retries allowed is set to 11.
- std::string retry_policy = "BackoffTestPolicy";
- URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance();
- URLFetcherProtectEntry* entry =
- new URLFetcherProtectEntry(200, 3, 11, 1, 2.0, 0, 256);
- manager->Register(retry_policy, entry);
-
- CreateFetcher(url, retry_policy);
-
- MessageLoop::current()->Run();
-}
-
-} // namespace.
diff --git a/chrome/service/cloud_print/job_status_updater.cc b/chrome/service/cloud_print/job_status_updater.cc
index 4719a6d..1f36b2a 100644
--- a/chrome/service/cloud_print/job_status_updater.cc
+++ b/chrome/service/cloud_print/job_status_updater.cc
@@ -58,36 +58,45 @@ void JobStatusUpdater::UpdateStatus() {
}
}
if (need_update) {
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(
- CloudPrintHelpers::GetUrlForJobStatusUpdate(
- cloud_print_server_url_, job_id_, last_job_details_),
- this, auth_token_, kCloudPrintAPIRetryPolicy);
+ GURL update_url = CloudPrintHelpers::GetUrlForJobStatusUpdate(
+ cloud_print_server_url_, job_id_, last_job_details_);
+ request_.reset(new URLFetcher(update_url, URLFetcher::GET, this));
+ CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
+ request_->Start();
}
}
}
void JobStatusUpdater::Stop() {
- request_ = NULL;
+ request_.reset();
DCHECK(delegate_);
stopped_ = true;
delegate_->OnJobCompleted(this);
}
-// CloudPrintURLFetcher::Delegate implementation.
-CloudPrintURLFetcher::ResponseAction JobStatusUpdater::HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- if (last_job_details_.status == cloud_print::PRINT_JOB_STATUS_COMPLETED) {
+// URLFetcher::Delegate implementation.
+void JobStatusUpdater::OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ // If there was an auth error, we are done.
+ if (RC_FORBIDDEN == response_code) {
+ if (delegate_) {
+ delegate_->OnAuthError();
+ }
+ return;
+ }
+ int64 next_update_interval = kJobStatusUpdateInterval;
+ if (!status.is_success() || (response_code != 200)) {
+ next_update_interval *= 10;
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, NewRunnableMethod(this, &JobStatusUpdater::UpdateStatus),
+ next_update_interval);
+ } else if (last_job_details_.status ==
+ cloud_print::PRINT_JOB_STATUS_COMPLETED) {
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableMethod(this, &JobStatusUpdater::Stop));
}
- return CloudPrintURLFetcher::STOP_PROCESSING;
-}
-
-void JobStatusUpdater::OnRequestAuthError() {
- if (delegate_)
- delegate_->OnAuthError();
}
diff --git a/chrome/service/cloud_print/job_status_updater.h b/chrome/service/cloud_print/job_status_updater.h
index 1cf4c0b..6e111cd 100644
--- a/chrome/service/cloud_print/job_status_updater.h
+++ b/chrome/service/cloud_print/job_status_updater.h
@@ -11,8 +11,8 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
-#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
#include "chrome/service/cloud_print/print_system.h"
+#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_status.h"
@@ -21,7 +21,7 @@
// object releases the reference to itself which should cause it to
// self-destruct.
class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>,
- public CloudPrintURLFetcherDelegate {
+ public URLFetcher::Delegate {
public:
class Delegate {
public:
@@ -45,20 +45,19 @@ class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>,
void UpdateStatus();
void Stop();
- // CloudPrintURLFetcher::Delegate implementation.
- virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
- virtual void OnRequestAuthError();
+ // URLFetcher::Delegate implementation.
+ virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
private:
std::string printer_name_;
std::string job_id_;
cloud_print::PlatformJobId local_job_id_;
cloud_print::PrintJobDetails last_job_details_;
- scoped_refptr<CloudPrintURLFetcher> request_;
+ scoped_ptr<URLFetcher> request_;
std::string auth_token_;
GURL cloud_print_server_url_;
scoped_refptr<cloud_print::PrintSystem> print_system_;
diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc
index f351c5c..9d4f46f 100644
--- a/chrome/service/cloud_print/printer_job_handler.cc
+++ b/chrome/service/cloud_print/printer_job_handler.cc
@@ -31,8 +31,8 @@ PrinterJobHandler::PrinterJobHandler(
cloud_print_server_url_(cloud_print_server_url),
delegate_(delegate),
local_job_id_(-1),
- next_json_data_handler_(NULL),
- next_data_handler_(NULL),
+ next_response_handler_(NULL),
+ next_failure_handler_(NULL),
server_error_count_(0),
print_thread_("Chrome_CloudPrintJobPrintThread"),
job_handler_message_loop_proxy_(
@@ -66,7 +66,7 @@ PrinterJobHandler::~PrinterJobHandler() {
void PrinterJobHandler::Reset() {
print_data_url_.clear();
job_details_.Clear();
- request_ = NULL;
+ request_.reset();
print_thread_.Stop();
}
@@ -86,12 +86,11 @@ void PrinterJobHandler::Start() {
if (printer_delete_pending_) {
printer_delete_pending_ = false;
task_in_progress_ = true;
- SetNextJSONHandler(&PrinterJobHandler::HandlePrinterDeleteResponse);
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(
+ MakeServerRequest(
CloudPrintHelpers::GetUrlForPrinterDelete(
cloud_print_server_url_, printer_info_cloud_.printer_id),
- this, auth_token_, kCloudPrintAPIRetryPolicy);
+ &PrinterJobHandler::HandlePrinterDeleteResponse,
+ &PrinterJobHandler::Stop);
}
if (!task_in_progress_ && printer_update_pending_) {
printer_update_pending_ = false;
@@ -101,12 +100,11 @@ void PrinterJobHandler::Start() {
task_in_progress_ = true;
server_job_available_ = false;
// We need to fetch any pending jobs for this printer
- SetNextJSONHandler(&PrinterJobHandler::HandleJobMetadataResponse);
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(
+ MakeServerRequest(
CloudPrintHelpers::GetUrlForJobFetch(
cloud_print_server_url_, printer_info_cloud_.printer_id),
- this, auth_token_, kCloudPrintAPIRetryPolicy);
+ &PrinterJobHandler::HandleJobMetadataResponse,
+ &PrinterJobHandler::Stop);
}
}
}
@@ -201,47 +199,50 @@ bool PrinterJobHandler::UpdatePrinterInfo() {
post_data.append("--" + mime_boundary + "--\r\n");
std::string mime_type("multipart/form-data; boundary=");
mime_type += mime_boundary;
- SetNextJSONHandler(&PrinterJobHandler::HandlePrinterUpdateResponse);
- request_ = new CloudPrintURLFetcher;
- request_->StartPostRequest(
- CloudPrintHelpers::GetUrlForPrinterUpdate(
- cloud_print_server_url_, printer_info_cloud_.printer_id),
- this, auth_token_, kCloudPrintAPIRetryPolicy, mime_type, post_data);
+ request_.reset(
+ new URLFetcher(CloudPrintHelpers::GetUrlForPrinterUpdate(
+ cloud_print_server_url_,
+ printer_info_cloud_.printer_id),
+ URLFetcher::POST, this));
+ CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
+ request_->set_upload_data(mime_type, post_data);
+ next_response_handler_ = &PrinterJobHandler::HandlePrinterUpdateResponse;
+ next_failure_handler_ = &PrinterJobHandler::Stop;
+ request_->Start();
ret = true;
}
return ret;
}
-// CloudPrintURLFetcher::Delegate implementation.
-CloudPrintURLFetcher::ResponseAction PrinterJobHandler::HandleRawData(
+// URLFetcher::Delegate implementation.
+void PrinterJobHandler::OnURLFetchComplete(
const URLFetcher* source,
const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
const std::string& data) {
- if (!next_data_handler_)
- return CloudPrintURLFetcher::CONTINUE_PROCESSING;
- return (this->*next_data_handler_)(source, url, data);
-}
-
-CloudPrintURLFetcher::ResponseAction PrinterJobHandler::HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- DCHECK(next_json_data_handler_);
- return (this->*next_json_data_handler_)(source,
- url,
- json_data,
- succeeded);
-}
-
-void PrinterJobHandler::OnRequestGiveUp() {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PrinterJobHandler::Stop));
-}
-
-void PrinterJobHandler::OnRequestAuthError() {
- OnAuthError();
+ VLOG(1) << "CP_PROXY: Printer job handler, OnURLFetchComplete, url: " << url
+ << ", response code: " << response_code;
+ // If there was an auth error, we are done.
+ if (RC_FORBIDDEN == response_code) {
+ OnAuthError();
+ return;
+ }
+ if (!shutting_down_) {
+ DCHECK(source == request_.get());
+ // We need a next response handler because we are strictly a sequential
+ // state machine. We need each response handler to tell us which state to
+ // advance to next.
+ DCHECK(next_response_handler_);
+ if (!(this->*next_response_handler_)(source, url, status,
+ response_code, cookies, data)) {
+ // By contract, if the response handler returns false, it wants us to
+ // retry the request (upto the usual limit after which we give up and
+ // send the state machine to the Stop state);
+ HandleServerError(url);
+ }
+ }
}
// JobStatusUpdater::Delegate implementation
@@ -290,101 +291,163 @@ void PrinterJobHandler::OnJobChanged() {
}
}
-// Begin Response handlers
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandlePrinterUpdateResponse(
+bool PrinterJobHandler::HandlePrinterUpdateResponse(
const URLFetcher* source,
const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ bool ret = false;
VLOG(1) << "CP_PROXY: Handle printer update response, id: "
<< printer_info_cloud_.printer_id;
- // We are done here. Go to the Stop state
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
- return CloudPrintURLFetcher::STOP_PROCESSING;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (status.is_success() && (response_code == 200)) {
+ bool succeeded = false;
+ DictionaryValue* response_dict = NULL;
+ CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
+ // If we get valid JSON back, we are done.
+ if (NULL != response_dict) {
+ ret = true;
+ }
+ }
+ if (ret) {
+ // We are done here. Go to the Stop state
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
+ } else {
+ // Since we failed to update the server, set the flag again.
+ printer_update_pending_ = true;
+ }
+ return ret;
}
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandlePrinterDeleteResponse(
+bool PrinterJobHandler::HandlePrinterDeleteResponse(
const URLFetcher* source,
const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ bool ret = false;
VLOG(1) << "CP_PROXY: Handler printer delete response, id: "
<< printer_info_cloud_.printer_id;
- // The printer has been deleted. Shutdown the handler class.
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Shutdown));
- return CloudPrintURLFetcher::STOP_PROCESSING;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (status.is_success() && (response_code == 200)) {
+ bool succeeded = false;
+ DictionaryValue* response_dict = NULL;
+ CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
+ // If we get valid JSON back, we are done.
+ if (NULL != response_dict) {
+ ret = true;
+ }
+ }
+ if (ret) {
+ // The printer has been deleted. Shutdown the handler class.
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Shutdown));
+ } else {
+ // Since we failed to update the server, set the flag again.
+ printer_delete_pending_ = true;
+ }
+ return ret;
}
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandleJobMetadataResponse(
+bool PrinterJobHandler::HandleJobMetadataResponse(
const URLFetcher* source,
const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
VLOG(1) << "CP_PROXY: Handle job metadata response, id: "
<< printer_info_cloud_.printer_id;
- bool job_available = false;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (!status.is_success() || (response_code != 200)) {
+ return false;
+ }
+ bool succeeded = false;
+ DictionaryValue* response_dict = NULL;
+ CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
+ if (NULL == response_dict) {
+ // If we did not get a valid JSON response, we need to retry.
+ return false;
+ }
+ Task* next_task = NULL;
if (succeeded) {
ListValue* job_list = NULL;
- json_data->GetList(kJobListValue, &job_list);
+ response_dict->GetList(kJobListValue, &job_list);
if (job_list) {
// Even though it is a job list, for now we are only interested in the
// first job
DictionaryValue* job_data = NULL;
if (job_list->GetDictionary(0, &job_data)) {
- job_available = true;
job_data->GetString(kIdValue, &job_details_.job_id_);
job_data->GetString(kTitleValue, &job_details_.job_title_);
std::string print_ticket_url;
job_data->GetString(kTicketUrlValue, &print_ticket_url);
job_data->GetString(kFileUrlValue, &print_data_url_);
- SetNextDataHandler(&PrinterJobHandler::HandlePrintTicketResponse);
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(GURL(print_ticket_url.c_str()),
- this,
- auth_token_,
- kCloudPrintAPIRetryPolicy);
+ next_task = NewRunnableMethod(
+ this, &PrinterJobHandler::MakeServerRequest,
+ GURL(print_ticket_url.c_str()),
+ &PrinterJobHandler::HandlePrintTicketResponse,
+ &PrinterJobHandler::FailedFetchingJobData);
}
}
}
- // If no jobs are available, go to the Stop state.
- if (!job_available)
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
- return CloudPrintURLFetcher::STOP_PROCESSING;
+ if (!next_task) {
+ // If we got a valid JSON but there were no jobs, we are done
+ next_task = NewRunnableMethod(this, &PrinterJobHandler::Stop);
+ }
+ delete response_dict;
+ DCHECK(next_task);
+ MessageLoop::current()->PostTask(FROM_HERE, next_task);
+ return true;
}
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandlePrintTicketResponse(const URLFetcher* source,
- const GURL& url,
- const std::string& data) {
+bool PrinterJobHandler::HandlePrintTicketResponse(
+ const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
+ int response_code, const ResponseCookies& cookies,
+ const std::string& data) {
VLOG(1) << "CP_PROXY: Handle print ticket response, id: "
<< printer_info_cloud_.printer_id;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (!status.is_success() || (response_code != 200)) {
+ return false;
+ }
if (print_system_->ValidatePrintTicket(printer_info_.printer_name, data)) {
job_details_.print_ticket_ = data;
- SetNextDataHandler(&PrinterJobHandler::HandlePrintDataResponse);
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(GURL(print_data_url_.c_str()),
- this,
- auth_token_,
- kJobDataRetryPolicy);
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &PrinterJobHandler::MakeServerRequest,
+ GURL(print_data_url_.c_str()),
+ &PrinterJobHandler::HandlePrintDataResponse,
+ &PrinterJobHandler::FailedFetchingJobData));
} else {
// The print ticket was not valid. We are done here.
FailedFetchingJobData();
}
- return CloudPrintURLFetcher::STOP_PROCESSING;
+ return true;
}
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandlePrintDataResponse(const URLFetcher* source,
- const GURL& url,
- const std::string& data) {
+bool PrinterJobHandler::HandlePrintDataResponse(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
VLOG(1) << "CP_PROXY: Handle print data response, id: "
<< printer_info_cloud_.printer_id;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (!status.is_success() || (response_code != 200)) {
+ return false;
+ }
Task* next_task = NULL;
if (file_util::CreateTemporaryFile(&job_details_.print_data_file_path_)) {
int ret = file_util::WriteFile(job_details_.print_data_file_path_,
@@ -404,54 +467,13 @@ PrinterJobHandler::HandlePrintDataResponse(const URLFetcher* source,
JOB_DOWNLOAD_FAILED);
}
MessageLoop::current()->PostTask(FROM_HERE, next_task);
- return CloudPrintURLFetcher::STOP_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandleSuccessStatusUpdateResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- VLOG(1) << "CP_PROXY: Handle success status update response, id: "
- << printer_info_cloud_.printer_id;
- // The print job has been spooled locally. We now need to create an object
- // that monitors the status of the job and updates the server.
- scoped_refptr<JobStatusUpdater> job_status_updater =
- new JobStatusUpdater(printer_info_.printer_name, job_details_.job_id_,
- local_job_id_, auth_token_, cloud_print_server_url_,
- print_system_.get(), this);
- job_status_updater_list_.push_back(job_status_updater);
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(job_status_updater.get(),
- &JobStatusUpdater::UpdateStatus));
- if (succeeded) {
- // Since we just printed successfully, we want to look for more jobs.
- server_job_available_ = true;
- }
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
- return CloudPrintURLFetcher::STOP_PROCESSING;
-}
-
-CloudPrintURLFetcher::ResponseAction
-PrinterJobHandler::HandleFailureStatusUpdateResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded) {
- VLOG(1) << "CP_PROXY: Handle failure status update response, id: "
- << printer_info_cloud_.printer_id;
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
- return CloudPrintURLFetcher::STOP_PROCESSING;
+ return true;
}
-// End Response handlers
void PrinterJobHandler::StartPrinting() {
VLOG(1) << "CP_PROXY: Start printing, id: " << printer_info_cloud_.printer_id;
// We are done with the request object for now.
- request_ = NULL;
+ request_.reset();
if (!shutting_down_) {
if (!print_thread_.Start()) {
JobFailed(PRINT_FAILED);
@@ -497,6 +519,17 @@ void PrinterJobHandler::Shutdown() {
}
}
+void PrinterJobHandler::HandleServerError(const GURL& url) {
+ VLOG(1) << "CP_PROXY: Handle server error, printer id: "
+ << printer_info_cloud_.printer_id << ", url: " << url;
+ Task* task_to_retry = NewRunnableMethod(this,
+ &PrinterJobHandler::FetchURL, url);
+ Task* task_on_give_up = NewRunnableMethod(this, next_failure_handler_);
+ CloudPrintHelpers::HandleServerError(&server_error_count_, kMaxRetryCount,
+ -1, kBaseRetryInterval, task_to_retry,
+ task_on_give_up);
+}
+
void PrinterJobHandler::UpdateJobStatus(cloud_print::PrintJobStatus status,
PrintJobError error) {
VLOG(1) << "CP_PROXY: Update job status, id: "
@@ -505,33 +538,98 @@ void PrinterJobHandler::UpdateJobStatus(cloud_print::PrintJobStatus status,
if (!job_details_.job_id_.empty()) {
VLOG(1) << "CP_PROXY: Updating status, job id: " << job_details_.job_id_
<< ", status: " << status;
+
+ ResponseHandler response_handler = NULL;
if (error == SUCCESS) {
- SetNextJSONHandler(
- &PrinterJobHandler::HandleSuccessStatusUpdateResponse);
+ response_handler =
+ &PrinterJobHandler::HandleSuccessStatusUpdateResponse;
} else {
- SetNextJSONHandler(
- &PrinterJobHandler::HandleFailureStatusUpdateResponse);
+ response_handler =
+ &PrinterJobHandler::HandleFailureStatusUpdateResponse;
}
- request_ = new CloudPrintURLFetcher;
- request_->StartGetRequest(
+ MakeServerRequest(
CloudPrintHelpers::GetUrlForJobStatusUpdate(cloud_print_server_url_,
job_details_.job_id_,
status),
- this,
- auth_token_,
- kCloudPrintAPIRetryPolicy);
+ response_handler,
+ &PrinterJobHandler::Stop);
}
}
}
-void PrinterJobHandler::SetNextJSONHandler(JSONDataHandler handler) {
- next_json_data_handler_ = handler;
- next_data_handler_ = NULL;
+bool PrinterJobHandler::HandleSuccessStatusUpdateResponse(
+ const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ VLOG(1) << "CP_PROXY: Handle success status update response, id: "
+ << printer_info_cloud_.printer_id;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (!status.is_success() || (response_code != 200)) {
+ return false;
+ }
+ // The print job has been spooled locally. We now need to create an object
+ // that monitors the status of the job and updates the server.
+ scoped_refptr<JobStatusUpdater> job_status_updater =
+ new JobStatusUpdater(printer_info_.printer_name, job_details_.job_id_,
+ local_job_id_, auth_token_, cloud_print_server_url_,
+ print_system_.get(), this);
+ job_status_updater_list_.push_back(job_status_updater);
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(job_status_updater.get(),
+ &JobStatusUpdater::UpdateStatus));
+ bool succeeded = false;
+ CloudPrintHelpers::ParseResponseJSON(data, &succeeded, NULL);
+ if (succeeded) {
+ // Since we just printed successfully, we want to look for more jobs.
+ server_job_available_ = true;
+ }
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
+ return true;
+}
+
+bool PrinterJobHandler::HandleFailureStatusUpdateResponse(
+ const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ VLOG(1) << "CP_PROXY: Handle failure status update response, id: "
+ << printer_info_cloud_.printer_id;
+ // If there was a network error or a non-200 response (which, for our purposes
+ // is the same as a network error), we want to retry.
+ if (!status.is_success() || (response_code != 200)) {
+ return false;
+ }
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
+ return true;
+}
+
+void PrinterJobHandler::MakeServerRequest(const GURL& url,
+ ResponseHandler response_handler,
+ FailureHandler failure_handler) {
+ VLOG(1) << "CP_PROXY: Printer job handle, make server request, id: "
+ << printer_info_cloud_.printer_id << ", url: " << url;
+ if (!shutting_down_) {
+ server_error_count_ = 0;
+ // Set up the next response handler
+ next_response_handler_ = response_handler;
+ next_failure_handler_ = failure_handler;
+ FetchURL(url);
+ }
}
-void PrinterJobHandler::SetNextDataHandler(DataHandler handler) {
- next_data_handler_ = handler;
- next_json_data_handler_ = NULL;
+void PrinterJobHandler::FetchURL(const GURL& url) {
+ VLOG(1) << "CP_PROXY: PrinterJobHandler::FetchURL, url: " << url;
+ request_.reset(new URLFetcher(url, URLFetcher::GET, this));
+ CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
+ request_->Start();
}
bool PrinterJobHandler::HavePendingTasks() {
diff --git a/chrome/service/cloud_print/printer_job_handler.h b/chrome/service/cloud_print/printer_job_handler.h
index 3290581..02c7be3 100644
--- a/chrome/service/cloud_print/printer_job_handler.h
+++ b/chrome/service/cloud_print/printer_job_handler.h
@@ -13,13 +13,12 @@
#include "base/ref_counted.h"
#include "base/message_loop_proxy.h"
#include "base/thread.h"
-#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
#include "chrome/service/cloud_print/job_status_updater.h"
+#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_status.h"
#include "printing/backend/print_backend.h"
-class URLFetcher;
// A class that handles cloud print jobs for a particular printer. This class
// imlements a state machine that transitions from Start to various states. The
// various states are shown in the below diagram.
@@ -59,8 +58,10 @@ class URLFetcher;
// Stop
// (If there are pending tasks go back to Start)
+typedef URLFetcher::Delegate URLFetcherDelegate;
+
class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
- public CloudPrintURLFetcherDelegate,
+ public URLFetcherDelegate,
public JobStatusUpdaterDelegate,
public cloud_print::PrinterWatcherDelegate,
public cloud_print::JobSpoolerDelegate {
@@ -119,19 +120,12 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
// Begin Delegate implementations
- // CloudPrintURLFetcher::Delegate implementation.
- virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data);
- virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
- virtual void OnRequestGiveUp();
- virtual void OnRequestAuthError();
-
+ // URLFetcher::Delegate implementation.
+ virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
// JobStatusUpdater::Delegate implementation
virtual bool OnJobCompleted(JobStatusUpdater* updater);
virtual void OnAuthError();
@@ -149,57 +143,55 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
// End Delegate implementations
private:
- // Prototype for a JSON data handler.
- typedef CloudPrintURLFetcher::ResponseAction
- (PrinterJobHandler::*JSONDataHandler)(const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
- // Prototype for a data handler.
- typedef CloudPrintURLFetcher::ResponseAction
- (PrinterJobHandler::*DataHandler)(const URLFetcher* source,
- const GURL& url,
- const std::string& data);
+ // Prototype for a response handler. The return value indicates whether the
+ // request should be retried, false means "retry", true means "do not retry"
+ typedef bool (PrinterJobHandler::*ResponseHandler)(
+ const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status, int response_code,
+ const ResponseCookies& cookies, const std::string& data);
+ // Prototype for a failure handler. This handler will be executed if all
+ // attempts to fetch url failed.
+ typedef void (PrinterJobHandler::*FailureHandler)();
// Begin request handlers for each state in the state machine
- CloudPrintURLFetcher::ResponseAction HandlePrinterUpdateResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- CloudPrintURLFetcher::ResponseAction HandlePrinterDeleteResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- CloudPrintURLFetcher::ResponseAction HandlePrintTicketResponse(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data);
-
- CloudPrintURLFetcher::ResponseAction HandlePrintDataResponse(
- const URLFetcher* source,
- const GURL& url,
- const std::string& data);
-
- CloudPrintURLFetcher::ResponseAction HandleSuccessStatusUpdateResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
-
- CloudPrintURLFetcher::ResponseAction HandleFailureStatusUpdateResponse(
- const URLFetcher* source,
- const GURL& url,
- DictionaryValue* json_data,
- bool succeeded);
+ bool HandlePrinterUpdateResponse(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ bool HandlePrinterDeleteResponse(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ bool HandleJobMetadataResponse(const URLFetcher* source, const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ bool HandlePrintTicketResponse(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ bool HandlePrintDataResponse(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ bool HandleSuccessStatusUpdateResponse(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+ bool HandleFailureStatusUpdateResponse(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
// End request handlers for each state in the state machine
// Start the state machine. Based on the flags set this could mean updating
@@ -216,10 +208,16 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
void Reset();
void UpdateJobStatus(cloud_print::PrintJobStatus status, PrintJobError error);
- // Sets the next response handler to the specifed JSON data handler.
- void SetNextJSONHandler(JSONDataHandler handler);
- // Sets the next response handler to the specifed data handler.
- void SetNextDataHandler(DataHandler handler);
+ // This function should be used to go from one state to another. It will
+ // retry to fetch url (up to a limit) if response handler will return false.
+ // Calling this function will zero failure counter.
+ void MakeServerRequest(const GURL& url,
+ ResponseHandler response_handler,
+ FailureHandler failure_handler);
+ // This function should be used ONLY from MakeServerRequest and
+ // HandleServerError. It is using stored handlers and failure counter
+ // to decide which handler to call.
+ void FetchURL(const GURL& url);
void JobFailed(PrintJobError error);
void JobSpooled(cloud_print::PlatformJobId local_job_id);
@@ -232,7 +230,7 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
void DoPrint(const JobDetails& job_details,
const std::string& printer_name);
- scoped_refptr<CloudPrintURLFetcher> request_;
+ scoped_ptr<URLFetcher> request_;
scoped_refptr<cloud_print::PrintSystem> print_system_;
printing::PrinterBasicInfo printer_info_;
PrinterInfoFromCloud printer_info_cloud_;
@@ -244,11 +242,8 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
// Once the job has been spooled to the local spooler, this specifies the
// job id of the job on the local spooler.
cloud_print::PlatformJobId local_job_id_;
-
- // The next response handler can either be a JSONDataHandler or a
- // DataHandler (depending on the current request being made).
- JSONDataHandler next_json_data_handler_;
- DataHandler next_data_handler_;
+ ResponseHandler next_response_handler_;
+ FailureHandler next_failure_handler_;
// The number of consecutive times that connecting to the server failed.
int server_error_count_;
// The thread on which the actual print operation happens