blob: f73c6d756d6bed4839b90a266763aa67d3368878 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/local_discovery/privet_http_impl.h"
#include <algorithm>
#include <vector>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/local_discovery/privet_constants.h"
#include "components/cloud_devices/common/printer_description.h"
#include "net/base/url_util.h"
#include "printing/pwg_raster_settings.h"
#include "printing/units.h"
#include "ui/gfx/text_elider.h"
#include "url/gurl.h"
using namespace cloud_devices::printer;
namespace cloud_print {
extern const char kContentTypeJSON[];
}
namespace local_discovery {
namespace {
const char kUrlPlaceHolder[] = "http://host/";
const char kPrivetRegisterActionArgName[] = "action";
const char kPrivetRegisterUserArgName[] = "user";
const char kPrivetURLKeyUserName[] = "user_name";
const char kPrivetURLKeyClientName[] = "client_name";
const char kPrivetURLKeyJobname[] = "job_name";
const char kPrivetURLKeyOffline[] = "offline";
const char kPrivetURLValueOffline[] = "1";
const char kPrivetURLValueClientName[] = "Chrome";
const char kPrivetContentTypePDF[] = "application/pdf";
const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
const char kPrivetContentTypeAny[] = "*/*";
const char kPrivetStorageListPath[] = "/privet/storage/list";
const char kPrivetStorageContentPath[] = "/privet/storage/content";
const char kPrivetStorageParamPathFormat[] = "path=%s";
const char kPrivetKeyJobID[] = "job_id";
const int kPrivetCancelationTimeoutSeconds = 3;
const int kPrivetLocalPrintMaxRetries = 2;
const int kPrivetLocalPrintDefaultTimeout = 5;
const size_t kPrivetLocalPrintMaxJobNameLength = 64;
GURL CreatePrivetURL(const std::string& path) {
GURL url(kUrlPlaceHolder);
GURL::Replacements replacements;
replacements.SetPathStr(path);
return url.ReplaceComponents(replacements);
}
GURL CreatePrivetRegisterURL(const std::string& action,
const std::string& user) {
GURL url = CreatePrivetURL(kPrivetRegisterPath);
url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action);
return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user);
}
GURL CreatePrivetParamURL(const std::string& path,
const std::string& query_params) {
GURL url(kUrlPlaceHolder);
GURL::Replacements replacements;
replacements.SetPathStr(path);
if (!query_params.empty()) {
replacements.SetQueryStr(query_params);
}
return url.ReplaceComponents(replacements);
}
} // namespace
PrivetInfoOperationImpl::PrivetInfoOperationImpl(
PrivetHTTPClient* privet_client,
const PrivetJSONOperation::ResultCallback& callback)
: privet_client_(privet_client), callback_(callback) {
}
PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
}
void PrivetInfoOperationImpl::Start() {
url_fetcher_ = privet_client_->CreateURLFetcher(
CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this);
url_fetcher_->DoNotRetryOnTransientError();
url_fetcher_->SendEmptyPrivetToken();
url_fetcher_->Start();
}
PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() {
return privet_client_;
}
void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
PrivetURLFetcher::ErrorType error) {
callback_.Run(NULL);
}
void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher,
const base::DictionaryValue* value,
bool has_error) {
callback_.Run(value);
}
PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
PrivetHTTPClient* privet_client,
const std::string& user,
PrivetRegisterOperation::Delegate* delegate)
: user_(user),
delegate_(delegate),
privet_client_(privet_client),
ongoing_(false) {
}
PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
}
void PrivetRegisterOperationImpl::Start() {
ongoing_ = true;
next_response_handler_ =
base::Bind(&PrivetRegisterOperationImpl::StartResponse,
base::Unretained(this));
SendRequest(kPrivetActionStart);
}
void PrivetRegisterOperationImpl::Cancel() {
url_fetcher_.reset();
if (ongoing_) {
// Owned by the message loop.
Cancelation* cancelation = new Cancelation(privet_client_, user_);
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup,
base::Owned(cancelation)),
base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds));
ongoing_ = false;
}
}
void PrivetRegisterOperationImpl::CompleteRegistration() {
next_response_handler_ =
base::Bind(&PrivetRegisterOperationImpl::CompleteResponse,
base::Unretained(this));
SendRequest(kPrivetActionComplete);
}
PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
return privet_client_;
}
void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
PrivetURLFetcher::ErrorType error) {
ongoing_ = false;
int visible_http_code = -1;
FailureReason reason = FAILURE_NETWORK;
if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
visible_http_code = fetcher->response_code();
reason = FAILURE_HTTP_ERROR;
} else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
reason = FAILURE_MALFORMED_RESPONSE;
} else if (error == PrivetURLFetcher::TOKEN_ERROR) {
reason = FAILURE_TOKEN;
} else if (error == PrivetURLFetcher::RETRY_ERROR) {
reason = FAILURE_RETRY;
}
delegate_->OnPrivetRegisterError(this,
current_action_,
reason,
visible_http_code,
NULL);
}
void PrivetRegisterOperationImpl::OnParsedJson(
PrivetURLFetcher* fetcher,
const base::DictionaryValue* value,
bool has_error) {
if (has_error) {
std::string error;
value->GetString(kPrivetKeyError, &error);
ongoing_ = false;
delegate_->OnPrivetRegisterError(this,
current_action_,
FAILURE_JSON_ERROR,
fetcher->response_code(),
value);
return;
}
// TODO(noamsml): Match the user&action with the user&action in the object,
// and fail if different.
next_response_handler_.Run(*value);
}
void PrivetRegisterOperationImpl::OnNeedPrivetToken(
PrivetURLFetcher* fetcher,
const PrivetURLFetcher::TokenCallback& callback) {
privet_client_->RefreshPrivetToken(callback);
}
void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
current_action_ = action;
url_fetcher_ = privet_client_->CreateURLFetcher(
CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
url_fetcher_->Start();
}
void PrivetRegisterOperationImpl::StartResponse(
const base::DictionaryValue& value) {
next_response_handler_ =
base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse,
base::Unretained(this));
SendRequest(kPrivetActionGetClaimToken);
}
void PrivetRegisterOperationImpl::GetClaimTokenResponse(
const base::DictionaryValue& value) {
std::string claimUrl;
std::string claimToken;
bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
if (got_url || got_token) {
delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
} else {
delegate_->OnPrivetRegisterError(this,
current_action_,
FAILURE_MALFORMED_RESPONSE,
-1,
NULL);
}
}
void PrivetRegisterOperationImpl::CompleteResponse(
const base::DictionaryValue& value) {
std::string id;
value.GetString(kPrivetKeyDeviceID, &id);
ongoing_ = false;
expected_id_ = id;
StartInfoOperation();
}
void PrivetRegisterOperationImpl::OnPrivetInfoDone(
const base::DictionaryValue* value) {
// TODO(noamsml): Simplify error case and depracate HTTP error value in
// OnPrivetRegisterError.
if (!value) {
delegate_->OnPrivetRegisterError(this,
kPrivetActionNameInfo,
FAILURE_NETWORK,
-1,
NULL);
return;
}
if (!value->HasKey(kPrivetInfoKeyID)) {
if (value->HasKey(kPrivetKeyError)) {
delegate_->OnPrivetRegisterError(this,
kPrivetActionNameInfo,
FAILURE_JSON_ERROR,
-1,
value);
} else {
delegate_->OnPrivetRegisterError(this,
kPrivetActionNameInfo,
FAILURE_MALFORMED_RESPONSE,
-1,
NULL);
}
return;
}
std::string id;
if (!value->GetString(kPrivetInfoKeyID, &id) ||
id != expected_id_) {
delegate_->OnPrivetRegisterError(this,
kPrivetActionNameInfo,
FAILURE_MALFORMED_RESPONSE,
-1,
NULL);
} else {
delegate_->OnPrivetRegisterDone(this, id);
}
}
void PrivetRegisterOperationImpl::StartInfoOperation() {
info_operation_ = privet_client_->CreateInfoOperation(
base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone,
base::Unretained(this)));
info_operation_->Start();
}
PrivetRegisterOperationImpl::Cancelation::Cancelation(
PrivetHTTPClient* privet_client,
const std::string& user) {
url_fetcher_ =
privet_client->CreateURLFetcher(
CreatePrivetRegisterURL(kPrivetActionCancel, user),
net::URLFetcher::POST, this);
url_fetcher_->DoNotRetryOnTransientError();
url_fetcher_->Start();
}
PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
}
void PrivetRegisterOperationImpl::Cancelation::OnError(
PrivetURLFetcher* fetcher,
PrivetURLFetcher::ErrorType error) {
}
void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
PrivetURLFetcher* fetcher,
const base::DictionaryValue* value,
bool has_error) {
}
void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
// Nothing needs to be done, as base::Owned will delete this object,
// this callback is just here to pass ownership of the Cancelation to
// the message loop.
}
PrivetJSONOperationImpl::PrivetJSONOperationImpl(
PrivetHTTPClient* privet_client,
const std::string& path,
const std::string& query_params,
const PrivetJSONOperation::ResultCallback& callback)
: privet_client_(privet_client),
path_(path),
query_params_(query_params),
callback_(callback) {
}
PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
}
void PrivetJSONOperationImpl::Start() {
url_fetcher_ = privet_client_->CreateURLFetcher(
CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
url_fetcher_->DoNotRetryOnTransientError();
url_fetcher_->Start();
}
PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() {
return privet_client_;
}
void PrivetJSONOperationImpl::OnError(
PrivetURLFetcher* fetcher,
PrivetURLFetcher::ErrorType error) {
callback_.Run(NULL);
}
void PrivetJSONOperationImpl::OnParsedJson(
PrivetURLFetcher* fetcher,
const base::DictionaryValue* value,
bool has_error) {
callback_.Run(value);
}
void PrivetJSONOperationImpl::OnNeedPrivetToken(
PrivetURLFetcher* fetcher,
const PrivetURLFetcher::TokenCallback& callback) {
privet_client_->RefreshPrivetToken(callback);
}
PrivetDataReadOperationImpl::PrivetDataReadOperationImpl(
PrivetHTTPClient* privet_client,
const std::string& path,
const std::string& query_params,
const PrivetDataReadOperation::ResultCallback& callback)
: privet_client_(privet_client),
path_(path),
query_params_(query_params),
callback_(callback),
has_range_(false),
save_to_file_(false) {
}
PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() {
}
void PrivetDataReadOperationImpl::Start() {
url_fetcher_ = privet_client_->CreateURLFetcher(
CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
url_fetcher_->DoNotRetryOnTransientError();
if (has_range_) {
url_fetcher_->SetByteRange(range_start_, range_end_);
}
if (save_to_file_) {
url_fetcher_->SaveResponseToFile();
}
url_fetcher_->Start();
}
void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) {
has_range_ = true;
range_start_ = range_start;
range_end_ = range_end;
}
void PrivetDataReadOperationImpl::SaveDataToFile() {
save_to_file_ = false;
}
PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() {
return privet_client_;
}
void PrivetDataReadOperationImpl::OnError(
PrivetURLFetcher* fetcher,
PrivetURLFetcher::ErrorType error) {
callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath());
}
void PrivetDataReadOperationImpl::OnParsedJson(
PrivetURLFetcher* fetcher,
const base::DictionaryValue* value,
bool has_error) {
NOTREACHED();
}
void PrivetDataReadOperationImpl::OnNeedPrivetToken(
PrivetURLFetcher* fetcher,
const PrivetURLFetcher::TokenCallback& callback) {
privet_client_->RefreshPrivetToken(callback);
}
bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher* fetcher,
bool is_file,
const std::string& data_str,
const base::FilePath& file_path) {
ResponseType type = (is_file) ? RESPONSE_TYPE_FILE : RESPONSE_TYPE_STRING;
callback_.Run(type, data_str, file_path);
return true;
}
PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
PrivetHTTPClient* privet_client,
PrivetLocalPrintOperation::Delegate* delegate)
: privet_client_(privet_client),
delegate_(delegate),
use_pdf_(false),
has_extended_workflow_(false),
started_(false),
offline_(false),
dpi_(printing::kDefaultPdfDpi),
invalid_job_retries_(0),
weak_factory_(this) {
}
PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
}
void PrivetLocalPrintOperationImpl::Start() {
DCHECK(!started_);
// We need to get the /info response so we can know which APIs are available.
// TODO(noamsml): Use cached info when available.
info_operation_ = privet_client_->CreateInfoOperation(
base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone,
base::Unretained(this)));
info_operation_->Start();
started_ = true;
}
void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
const base::DictionaryValue* value) {
if (value && !value->HasKey(kPrivetKeyError)) {
has_extended_workflow_ = false;
bool has_printing = false;
const base::ListValue* api_list;
if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
for (size_t i = 0; i < api_list->GetSize(); i++) {
std::string api;
api_list->GetString(i, &api);
if (api == kPrivetSubmitdocPath) {
has_printing = true;
} else if (api == kPrivetCreatejobPath) {
has_extended_workflow_ = true;
}
}
}
if (!has_printing) {
delegate_->OnPrivetPrintingError(this, -1);
return;
}
StartInitialRequest();
} else {
delegate_->OnPrivetPrintingError(this, -1);
}
}
void PrivetLocalPrintOperationImpl::StartInitialRequest() {
use_pdf_ = false;
ContentTypesCapability content_types;
if (content_types.LoadFrom(capabilities_)) {
use_pdf_ = content_types.Contains(kPrivetContentTypePDF) ||
content_types.Contains(kPrivetContentTypeAny);
}
if (use_pdf_) {
StartPrinting();
} else {
DpiCapability dpis;
if (dpis.LoadFrom(capabilities_)) {
dpi_ = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical);
}
StartConvertToPWG();
}
}
void PrivetLocalPrintOperationImpl::DoCreatejob() {
current_response_ = base::Bind(
&PrivetLocalPrintOperationImpl::OnCreatejobResponse,
base::Unretained(this));
url_fetcher_= privet_client_->CreateURLFetcher(
CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this);
url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON,
ticket_.ToString());
url_fetcher_->Start();
}
void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
current_response_ = base::Bind(
&PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
base::Unretained(this));
GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
url = net::AppendQueryParameter(url,
kPrivetURLKeyClientName,
kPrivetURLValueClientName);
if (!user_.empty()) {
url = net::AppendQueryParameter(url,
kPrivetURLKeyUserName,
user_);
}
base::string16 shortened_jobname;
gfx::ElideString(base::UTF8ToUTF16(jobname_),
kPrivetLocalPrintMaxJobNameLength,
&shortened_jobname);
if (!jobname_.empty()) {
url = net::AppendQueryParameter(
url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname));
}
if (!jobid_.empty()) {
url = net::AppendQueryParameter(url,
kPrivetKeyJobID,
jobid_);
}
if (offline_) {
url = net::AppendQueryParameter(url,
kPrivetURLKeyOffline,
kPrivetURLValueOffline);
}
url_fetcher_= privet_client_->CreateURLFetcher(
url, net::URLFetcher::POST, this);
if (!use_pdf_) {
url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster,
pwg_file_path_);
} else {
// TODO(noamsml): Move to file-based upload data?
std::string data_str((const char*)data_->front(), data_->size());
url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str);
}
url_fetcher_->Start();
}
void PrivetLocalPrintOperationImpl::StartPrinting() {
if (has_extended_workflow_ && jobid_.empty()) {
DoCreatejob();
} else {
DoSubmitdoc();
}
}
void PrivetLocalPrintOperationImpl::FillPwgRasterSettings(
printing::PwgRasterSettings* transform_settings) {
PwgRasterConfigCapability raster_capability;
// If the raster capability fails to load, raster_capability will contain
// the default value.
raster_capability.LoadFrom(capabilities_);
DuplexTicketItem duplex_item;
DuplexType duplex_value = NO_DUPLEX;
DocumentSheetBack document_sheet_back =
raster_capability.value().document_sheet_back;
if (duplex_item.LoadFrom(ticket_)) {
duplex_value = duplex_item.value();
}
transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
switch (duplex_value) {
case NO_DUPLEX:
transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
break;
case LONG_EDGE:
if (document_sheet_back == ROTATED) {
transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
} else if (document_sheet_back == FLIPPED) {
transform_settings->odd_page_transform =
printing::TRANSFORM_FLIP_VERTICAL;
}
break;
case SHORT_EDGE:
if (document_sheet_back == MANUAL_TUMBLE) {
transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
} else if (document_sheet_back == FLIPPED) {
transform_settings->odd_page_transform =
printing::TRANSFORM_FLIP_HORIZONTAL;
}
}
transform_settings->rotate_all_pages =
raster_capability.value().rotate_all_pages;
transform_settings->reverse_page_order =
raster_capability.value().reverse_order_streaming;
}
void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
printing::PwgRasterSettings transform_settings;
FillPwgRasterSettings(&transform_settings);
if (!pwg_raster_converter_)
pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
double scale = dpi_;
scale /= printing::kPointsPerInch;
// Make vertical rectangle to optimize streaming to printer. Fix orientation
// by autorotate.
gfx::Rect area(std::min(page_size_.width(), page_size_.height()) * scale,
std::max(page_size_.width(), page_size_.height()) * scale);
pwg_raster_converter_->Start(
data_,
printing::PdfRenderSettings(area, dpi_, true),
transform_settings,
base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted,
base::Unretained(this)));
}
void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
bool has_error,
const base::DictionaryValue* value) {
std::string error;
// This error is only relevant in the case of extended workflow:
// If the print job ID is invalid, retry createjob and submitdoc,
// rather than simply retrying the current request.
if (has_error && value->GetString(kPrivetKeyError, &error)) {
if (has_extended_workflow_ &&
error == kPrivetErrorInvalidPrintJob &&
invalid_job_retries_ < kPrivetLocalPrintMaxRetries) {
invalid_job_retries_++;
int timeout = kPrivetLocalPrintDefaultTimeout;
value->GetInteger(kPrivetKeyTimeout, &timeout);
double random_scaling_factor =
1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
timeout = static_cast<int>(timeout * random_scaling_factor);
timeout = std::max(timeout, kPrivetMinimumTimeout);
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(timeout));
} else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) {
use_pdf_ = false;
StartConvertToPWG();
} else {
delegate_->OnPrivetPrintingError(this, 200);
}
return;
}
// If we've gotten this far, there are no errors, so we've effectively
// succeeded.
delegate_->OnPrivetPrintingDone(this);
}
void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
bool has_error,
const base::DictionaryValue* value) {
if (has_error) {
delegate_->OnPrivetPrintingError(this, 200);
return;
}
// Try to get job ID from value. If not, jobid_ will be empty and we will use
// simple printing.
value->GetString(kPrivetKeyJobID, &jobid_);
DoSubmitdoc();
}
void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
bool success,
const base::FilePath& pwg_file_path) {
if (!success) {
delegate_->OnPrivetPrintingError(this, -1);
return;
}
DCHECK(!pwg_file_path.empty());
pwg_file_path_ = pwg_file_path;
StartPrinting();
}
PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
return privet_client_;
}
void PrivetLocalPrintOperationImpl::OnError(
PrivetURLFetcher* fetcher,
PrivetURLFetcher::ErrorType error) {
delegate_->OnPrivetPrintingError(this, -1);
}
void PrivetLocalPrintOperationImpl::OnParsedJson(
PrivetURLFetcher* fetcher,
const base::DictionaryValue* value,
bool has_error) {
DCHECK(!current_response_.is_null());
current_response_.Run(has_error, value);
}
void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
PrivetURLFetcher* fetcher,
const PrivetURLFetcher::TokenCallback& callback) {
privet_client_->RefreshPrivetToken(callback);
}
void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) {
DCHECK(!started_);
data_ = data;
}
void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
DCHECK(!started_);
ticket_.InitFromString(ticket);
}
void PrivetLocalPrintOperationImpl::SetCapabilities(
const std::string& capabilities) {
DCHECK(!started_);
capabilities_.InitFromString(capabilities);
}
void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
DCHECK(!started_);
user_= user;
}
void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
DCHECK(!started_);
jobname_ = jobname;
}
void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
DCHECK(!started_);
offline_ = offline;
}
void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) {
DCHECK(!started_);
page_size_ = page_size;
}
void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
scoped_ptr<PWGRasterConverter> pwg_raster_converter) {
pwg_raster_converter_ = pwg_raster_converter.Pass();
}
PrivetHTTPClientImpl::PrivetHTTPClientImpl(
const std::string& name,
const net::HostPortPair& host_port,
net::URLRequestContextGetter* request_context)
: name_(name), request_context_(request_context), host_port_(host_port) {}
PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
}
const std::string& PrivetHTTPClientImpl::GetName() {
return name_;
}
scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation(
const PrivetJSONOperation::ResultCallback& callback) {
return scoped_ptr<PrivetJSONOperation>(
new PrivetInfoOperationImpl(this, callback));
}
scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
const GURL& url,
net::URLFetcher::RequestType request_type,
PrivetURLFetcher::Delegate* delegate) {
GURL::Replacements replacements;
replacements.SetHostStr(host_port_.host());
std::string port(base::IntToString(host_port_.port())); // Keep string alive.
replacements.SetPortStr(port);
return scoped_ptr<PrivetURLFetcher>(
new PrivetURLFetcher(url.ReplaceComponents(replacements),
request_type,
request_context_.get(),
delegate));
}
void PrivetHTTPClientImpl::RefreshPrivetToken(
const PrivetURLFetcher::TokenCallback& callback) {
token_callbacks_.push_back(callback);
if (!info_operation_) {
info_operation_ = CreateInfoOperation(
base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone,
base::Unretained(this)));
info_operation_->Start();
}
}
void PrivetHTTPClientImpl::OnPrivetInfoDone(
const base::DictionaryValue* value) {
info_operation_.reset();
std::string token;
// If this does not succeed, token will be empty, and an empty string
// is our sentinel value, since empty X-Privet-Tokens are not allowed.
if (value) {
value->GetString(kPrivetInfoKeyToken, &token);
}
TokenCallbackVector token_callbacks;
token_callbacks_.swap(token_callbacks);
for (TokenCallbackVector::iterator i = token_callbacks.begin();
i != token_callbacks.end(); i++) {
i->Run(token);
}
}
PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl(
scoped_ptr<PrivetHTTPClient> info_client)
: info_client_(info_client.Pass()) {
}
PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() {
}
const std::string& PrivetV1HTTPClientImpl::GetName() {
return info_client()->GetName();
}
scoped_ptr<PrivetJSONOperation> PrivetV1HTTPClientImpl::CreateInfoOperation(
const PrivetJSONOperation::ResultCallback& callback) {
return info_client()->CreateInfoOperation(callback);
}
scoped_ptr<PrivetRegisterOperation>
PrivetV1HTTPClientImpl::CreateRegisterOperation(
const std::string& user,
PrivetRegisterOperation::Delegate* delegate) {
return scoped_ptr<PrivetRegisterOperation>(
new PrivetRegisterOperationImpl(info_client(), user, delegate));
}
scoped_ptr<PrivetJSONOperation>
PrivetV1HTTPClientImpl::CreateCapabilitiesOperation(
const PrivetJSONOperation::ResultCallback& callback) {
return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl(
info_client(), kPrivetCapabilitiesPath, "", callback));
}
scoped_ptr<PrivetLocalPrintOperation>
PrivetV1HTTPClientImpl::CreateLocalPrintOperation(
PrivetLocalPrintOperation::Delegate* delegate) {
return scoped_ptr<PrivetLocalPrintOperation>(
new PrivetLocalPrintOperationImpl(info_client(), delegate));
}
scoped_ptr<PrivetJSONOperation>
PrivetV1HTTPClientImpl::CreateStorageListOperation(
const std::string& path,
const PrivetJSONOperation::ResultCallback& callback) {
std::string url_param =
base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str());
return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl(
info_client(), kPrivetStorageListPath, url_param, callback));
}
scoped_ptr<PrivetDataReadOperation>
PrivetV1HTTPClientImpl::CreateStorageReadOperation(
const std::string& path,
const PrivetDataReadOperation::ResultCallback& callback) {
std::string url_param =
base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str());
return scoped_ptr<PrivetDataReadOperation>(new PrivetDataReadOperationImpl(
info_client(), kPrivetStorageContentPath, url_param, callback));
}
PrivetV3HTTPClientImpl::PrivetV3HTTPClientImpl(
scoped_ptr<PrivetHTTPClient> info_client)
: info_client_(info_client.Pass()) {
}
PrivetV3HTTPClientImpl::~PrivetV3HTTPClientImpl() {
}
const std::string& PrivetV3HTTPClientImpl::GetName() {
return info_client()->GetName();
}
scoped_ptr<PrivetJSONOperation> PrivetV3HTTPClientImpl::CreateInfoOperation(
const PrivetJSONOperation::ResultCallback& callback) {
return info_client()->CreateInfoOperation(callback);
}
} // namespace local_discovery