Index: cloud_print/gcp20/prototype/cloud_print_requester.cc |
diff --git a/cloud_print/gcp20/prototype/cloud_print_requester.cc b/cloud_print/gcp20/prototype/cloud_print_requester.cc |
index b0c61695019f0a55d1b13afeb919465c3b8641a2..f0d192618c00243b9ca6a803fe751d536e0b13b8 100644 |
--- a/cloud_print/gcp20/prototype/cloud_print_requester.cc |
+++ b/cloud_print/gcp20/prototype/cloud_print_requester.cc |
@@ -4,18 +4,18 @@ |
#include "cloud_print/gcp20/prototype/cloud_print_requester.h" |
+#include "base/bind.h" |
#include "base/md5.h" |
#include "base/message_loop/message_loop.h" |
#include "base/rand_util.h" |
#include "base/strings/stringprintf.h" |
-#include "cloud_print/gcp20/prototype/cloud_print_response_parser.h" |
#include "google_apis/google_api_keys.h" |
-#include "net/base/load_flags.h" |
#include "net/base/mime_util.h" |
#include "net/base/url_util.h" |
#include "net/proxy/proxy_config_service_fixed.h" |
#include "net/url_request/url_request_context.h" |
#include "net/url_request/url_request_context_builder.h" |
+#include "net/url_request/url_request_context_getter.h" |
#include "url/gurl.h" |
const char kCloudPrintUrl[] = "https://www.google.com/cloudprint"; |
@@ -34,8 +34,23 @@ GURL CreateRegisterUrl() { |
return GURL(std::string(kCloudPrintUrl) + "/register"); |
} |
+GURL CreateFetchUrl(const std::string& device_id) { |
+ GURL url(std::string(kCloudPrintUrl) + "/fetch"); |
+ url = net::AppendQueryParameter(url, "printerid", device_id); |
+ return url; |
+} |
+ |
+GURL CreateControlUrl(const std::string& job_id, const std::string& status) { |
+ GURL url(std::string(kCloudPrintUrl) + "/control"); |
+ url = net::AppendQueryParameter(url, "jobid", job_id); |
+ url = net::AppendQueryParameter(url, "status", status); |
+ return url; |
+} |
+ |
} // namespace |
+using cloud_print_response_parser::Job; |
+ |
// Used to return a dummy context, which lives on the message loop |
// given in the constructor. |
class CloudPrintURLRequestContextGetter : public net::URLRequestContextGetter { |
@@ -89,7 +104,11 @@ CloudPrintRequester::CloudPrintRequester( |
CloudPrintRequester::~CloudPrintRequester() { |
} |
-bool CloudPrintRequester::StartRegistration(const std::string& proxy_id, |
+bool CloudPrintRequester::IsBusy() const { |
+ return request_ || gaia_; |
+} |
+ |
+void CloudPrintRequester::StartRegistration(const std::string& proxy_id, |
const std::string& device_name, |
const std::string& user, |
const std::string& cdd) { |
@@ -100,65 +119,114 @@ bool CloudPrintRequester::StartRegistration(const std::string& proxy_id, |
"---------------------------%08X%08X", r1, r2); |
std::string data; |
- net::AddMultipartValueForUpload(kProxyIdValue, proxy_id, |
- mime_boundary, std::string(), &data); |
- net::AddMultipartValueForUpload(kPrinterNameValue, device_name, |
- mime_boundary, std::string(), &data); |
- net::AddMultipartValueForUpload("use_cdd", "true", |
- mime_boundary, std::string(), &data); |
- net::AddMultipartValueForUpload(kPrinterNameValue, device_name, |
- mime_boundary, std::string(), &data); |
- net::AddMultipartValueForUpload(kPrinterCapsValue, cdd, |
- mime_boundary, "application/json", &data); |
+ std::string data_mimetype; |
+ data_mimetype = "multipart/form-data; boundary=" + mime_boundary; |
+ |
+ net::AddMultipartValueForUpload(kProxyIdValue, proxy_id, mime_boundary, |
+ std::string(), &data); |
+ net::AddMultipartValueForUpload(kPrinterNameValue, device_name, mime_boundary, |
+ std::string(), &data); |
+ net::AddMultipartValueForUpload("use_cdd", "true", mime_boundary, |
+ std::string(), &data); |
+ net::AddMultipartValueForUpload(kPrinterNameValue, device_name, mime_boundary, |
+ std::string(), &data); |
+ net::AddMultipartValueForUpload(kPrinterCapsValue, cdd, mime_boundary, |
+ "application/json", &data); |
net::AddMultipartValueForUpload(kPrinterCapsHashValue, base::MD5String(cdd), |
mime_boundary, std::string(), &data); |
net::AddMultipartValueForUpload(kPrinterUserValue, user, |
mime_boundary, std::string(), &data); |
net::AddMultipartFinalDelimiterForUpload(mime_boundary, &data); |
- std::string mime_type("multipart/form-data; boundary=" + mime_boundary); |
+ request_ = CreatePost( |
+ CreateRegisterUrl(), |
+ data, |
+ data_mimetype, |
+ base::Bind(&CloudPrintRequester::ParseRegisterStart, AsWeakPtr())); |
+ request_->Run(access_token_, context_getter_); |
+} |
+ |
+void CloudPrintRequester::CompleteRegistration() { |
+ request_ = CreateGet( |
+ GURL(polling_url_ + oauth_client_info_.client_id), |
+ base::Bind(&CloudPrintRequester::ParseRegisterComplete, AsWeakPtr())); |
+ request_->Run(access_token_, context_getter_); |
+} |
+ |
+void CloudPrintRequester::FetchPrintJobs(const std::string& refresh_token, |
+ const std::string& device_id) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ if (IsBusy()) |
+ return; |
- if (!CreateRequest( |
- CreateRegisterUrl(), net::URLFetcher::POST, |
- base::Bind(&CloudPrintRequester::ParseRegisterStartResponse, |
- AsWeakPtr()))) { |
- return false; |
+ if (access_token_.empty()) { |
+ UpdateAccesstoken(refresh_token); |
+ return; |
} |
- fetcher_->SetUploadData(mime_type, data); |
- fetcher_->Start(); |
- return true; |
+ VLOG(3) << "Function: " << __FUNCTION__ << |
+ ": request created"; |
+ request_ = CreateGet( |
+ CreateFetchUrl(device_id), |
+ base::Bind(&CloudPrintRequester::ParseFetch, AsWeakPtr())); |
+ request_->Run(access_token_, context_getter_); |
} |
-bool CloudPrintRequester::CompleteRegistration() { |
- if (!CreateRequest( |
- GURL(polling_url_ + oauth_client_info_.client_id), |
- net::URLFetcher::GET, |
- base::Bind(&CloudPrintRequester::ParseRegisterCompleteResponse, |
- AsWeakPtr()))) { |
- return false; |
- } |
- fetcher_->Start(); |
+void CloudPrintRequester::UpdateAccesstoken(const std::string& refresh_token) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ DCHECK(!IsBusy()); |
+ gaia_.reset(new gaia::GaiaOAuthClient(context_getter_.get())); |
+ gaia_->RefreshToken(oauth_client_info_, refresh_token, |
+ std::vector<std::string>(), kGaiaMaxRetries, this); |
+ delegate_->OnServerError("Access token requested."); |
+} |
- return true; |
+void CloudPrintRequester::RequestPrintJob(const Job& job) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ current_print_job_.reset(new Job(job)); |
+ request_ = CreateGet( |
+ CreateControlUrl(current_print_job_->job_id, "IN_PROGRESS"), |
+ base::Bind(&CloudPrintRequester::ParsePrintJobInProgress, AsWeakPtr())); |
+ request_->Run(access_token_, context_getter_); |
} |
-void CloudPrintRequester::OnURLFetchComplete(const net::URLFetcher* source) { |
- std::string response; |
- source->GetResponseAsString(&response); |
- fetcher_.reset(); |
- VLOG(1) << response; |
+void CloudPrintRequester::SendPrintJobDone(const std::string& job_id) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ request_ = CreateGet( |
+ CreateControlUrl(job_id, "DONE"), |
+ base::Bind(&CloudPrintRequester::ParsePrintJobDone, AsWeakPtr())); |
+ request_->Run(access_token_, context_getter_); |
+} |
- // TODO(maksymb): Add |server_http_code| and |server_api| info for errors. |
- if (!parse_response_callback_.is_null()) { |
- parse_response_callback_.Run(response); |
- parse_response_callback_.Reset(); |
- } |
+void CloudPrintRequester::OnFetchComplete(const std::string& response) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ ParserCallback callback = parser_callback_; |
+ EraseRequest(); |
+ callback.Run(response); |
+} |
+ |
+void CloudPrintRequester::OnFetchError(const std::string& server_api, |
+ int server_code, |
+ int server_http_code) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ EraseRequest(); |
+ current_print_job_.reset(); |
+ delegate_->OnServerError("Fetch error"); |
+ NOTIMPLEMENTED(); |
+} |
+ |
+void CloudPrintRequester::OnFetchTimeoutReached() { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ EraseRequest(); |
+ current_print_job_.reset(); |
+ delegate_->OnNetworkError(); |
} |
void CloudPrintRequester::OnGetTokensResponse(const std::string& refresh_token, |
const std::string& access_token, |
int expires_in_seconds) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ gaia_.reset(); |
access_token_ = access_token; |
delegate_->OnGetAuthCodeResponseParsed(refresh_token); |
} |
@@ -166,42 +234,53 @@ void CloudPrintRequester::OnGetTokensResponse(const std::string& refresh_token, |
void CloudPrintRequester::OnRefreshTokenResponse( |
const std::string& access_token, |
int expires_in_seconds) { |
- NOTIMPLEMENTED(); |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ gaia_.reset(); |
+ access_token_ = access_token; |
+ LOG(INFO) << "New accesstoken: " << access_token; |
} |
void CloudPrintRequester::OnOAuthError() { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ gaia_.reset(); |
NOTIMPLEMENTED(); |
} |
void CloudPrintRequester::OnNetworkError(int response_code) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ gaia_.reset(); |
NOTIMPLEMENTED(); |
} |
-bool CloudPrintRequester::CreateRequest(const GURL& url, |
- net::URLFetcher::RequestType method, |
- const ParserCallback& callback) { |
- if (fetcher_) |
- return false; // Only one query is supported. |
- |
- fetcher_.reset(net::URLFetcher::Create(url, method, this)); |
- fetcher_->SetRequestContext(context_getter_); |
- |
- int load_flags = fetcher_->GetLoadFlags(); |
- load_flags |= net::LOAD_DO_NOT_SEND_COOKIES; |
- load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES; |
- fetcher_->SetLoadFlags(load_flags); |
- |
- fetcher_->AddExtraRequestHeader("X-CloudPrint-Proxy: \"\""); |
- if (!access_token_.empty()) |
- fetcher_->AddExtraRequestHeader("Authorization: Bearer " + access_token_); |
+scoped_ptr<CloudPrintRequest> CloudPrintRequester::CreateGet( |
+ const GURL& url, |
+ const ParserCallback& parser_callback) { |
+ DCHECK(!IsBusy()); |
+ DCHECK(parser_callback_.is_null()); |
+ parser_callback_ = parser_callback; |
+ return CloudPrintRequest::CreateGet(url, this); |
+} |
- parse_response_callback_ = callback; |
+scoped_ptr<CloudPrintRequest> CloudPrintRequester::CreatePost( |
+ const GURL& url, |
+ const std::string& content, |
+ const std::string& mimetype, |
+ const ParserCallback& parser_callback) { |
+ DCHECK(!IsBusy()); |
+ DCHECK(parser_callback_.is_null()); |
+ parser_callback_ = parser_callback; |
+ return CloudPrintRequest::CreatePost(url, content, mimetype, this); |
+} |
- return true; |
+void CloudPrintRequester::EraseRequest() { |
+ DCHECK(request_); |
+ DCHECK(!parser_callback_.is_null()); |
+ request_.reset(); |
+ parser_callback_.Reset(); |
} |
-void CloudPrintRequester::ParseRegisterStartResponse( |
- const std::string& response) { |
+void CloudPrintRequester::ParseRegisterStart(const std::string& response) { |
+ std::string error_description; |
std::string polling_url; |
std::string registration_token; |
std::string complete_invite_url; |
@@ -209,36 +288,88 @@ void CloudPrintRequester::ParseRegisterStartResponse( |
bool success = cloud_print_response_parser::ParseRegisterStartResponse( |
response, |
- base::Bind(&CloudPrintRequester::Delegate::OnRegistrationError, |
- base::Unretained(delegate_)), |
+ &error_description, |
&polling_url, |
®istration_token, |
&complete_invite_url, |
&device_id); |
- if (!success) |
- return; |
- |
- polling_url_ = polling_url; |
- delegate_->OnRegistrationStartResponseParsed(registration_token, |
- complete_invite_url, device_id); |
+ if (success) { |
+ polling_url_ = polling_url; |
+ delegate_->OnRegistrationStartResponseParsed(registration_token, |
+ complete_invite_url, |
+ device_id); |
+ } else { |
+ delegate_->OnRegistrationError(error_description); |
+ } |
} |
-void CloudPrintRequester::ParseRegisterCompleteResponse( |
- const std::string& response) { |
+void CloudPrintRequester::ParseRegisterComplete(const std::string& response) { |
+ std::string error_description; |
std::string authorization_code; |
bool success = cloud_print_response_parser::ParseRegisterCompleteResponse( |
response, |
- base::Bind(&CloudPrintRequester::Delegate::OnRegistrationError, |
- base::Unretained(delegate_)), |
+ &error_description, |
&authorization_code); |
- if (!success) |
- return; |
+ if (success) { |
+ gaia_.reset(new gaia::GaiaOAuthClient(context_getter_.get())); |
+ gaia_->GetTokensFromAuthCode(oauth_client_info_, authorization_code, |
+ kGaiaMaxRetries, this); |
+ } else { |
+ delegate_->OnRegistrationError(error_description); |
+ } |
+} |
- gaia_.reset(new gaia::GaiaOAuthClient(context_getter_.get())); |
- gaia_->GetTokensFromAuthCode(oauth_client_info_, authorization_code, |
- kGaiaMaxRetries, this); |
+void CloudPrintRequester::ParseFetch(const std::string& response) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ |
+ std::string error_description; |
+ std::vector<Job> list; |
+ bool success = cloud_print_response_parser::ParseFetchResponse( |
+ response, |
+ &error_description, |
+ &list); |
+ |
+ if (success) { |
+ delegate_->OnPrintJobsAvailable(list); |
+ } else { |
+ delegate_->OnServerError(error_description); |
+ } |
+} |
+ |
+void CloudPrintRequester::ParseGetPrintJobTicket(const std::string& response) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ current_print_job_->ticket = response; |
+ |
+ DCHECK(current_print_job_); |
+ request_ = CreateGet( |
+ GURL(current_print_job_->file_url), |
+ base::Bind(&CloudPrintRequester::ParseGetPrintJobData, AsWeakPtr())); |
+ request_->AddHeader("Accept: \"application/pdf\""); |
+ request_->Run(access_token_, context_getter_); |
+} |
+ |
+void CloudPrintRequester::ParseGetPrintJobData(const std::string& response) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ current_print_job_->file = response; |
+ DCHECK(current_print_job_); |
+ delegate_->OnPrintJobDownloaded(*current_print_job_); |
+} |
+ |
+void CloudPrintRequester::ParsePrintJobDone(const std::string& response) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ current_print_job_.reset(); |
+ delegate_->OnPrintJobDone(); |
+} |
+ |
+void CloudPrintRequester::ParsePrintJobInProgress(const std::string& response) { |
+ VLOG(3) << "Function: " << __FUNCTION__; |
+ DCHECK(current_print_job_); |
+ request_ = CreateGet( |
+ GURL(current_print_job_->ticket_url), |
+ base::Bind(&CloudPrintRequester::ParseGetPrintJobTicket, AsWeakPtr())); |
+ request_->Run(access_token_, context_getter_); |
} |