1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/local_discovery/privet_http_impl.h"
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/rand_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/local_discovery/privet_constants.h"
17 #include "components/cloud_devices/printer_description.h"
18 #include "net/base/url_util.h"
19 #include "printing/pwg_raster_settings.h"
20 #include "printing/units.h"
21 #include "ui/gfx/text_elider.h"
24 using namespace cloud_devices::printer;
26 namespace local_discovery {
29 const char kUrlPlaceHolder[] = "http://host/";
30 const char kPrivetRegisterActionArgName[] = "action";
31 const char kPrivetRegisterUserArgName[] = "user";
33 const char kPrivetURLKeyUserName[] = "user_name";
34 const char kPrivetURLKeyClientName[] = "client_name";
35 const char kPrivetURLKeyJobname[] = "job_name";
36 const char kPrivetURLKeyOffline[] = "offline";
37 const char kPrivetURLValueOffline[] = "1";
38 const char kPrivetURLValueClientName[] = "Chrome";
40 const char kPrivetContentTypePDF[] = "application/pdf";
41 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
42 const char kPrivetContentTypeAny[] = "*/*";
43 const char kPrivetContentTypeCJT[] = "application/json";
45 const char kPrivetStorageListPath[] = "/privet/storage/list";
46 const char kPrivetStorageContentPath[] = "/privet/storage/content";
47 const char kPrivetStorageParamPathFormat[] = "path=%s";
49 const char kPrivetKeyJobID[] = "job_id";
51 const int kPrivetCancelationTimeoutSeconds = 3;
53 const int kPrivetLocalPrintMaxRetries = 2;
55 const int kPrivetLocalPrintDefaultTimeout = 5;
57 const size_t kPrivetLocalPrintMaxJobNameLength = 64;
59 GURL CreatePrivetURL(const std::string& path) {
60 GURL url(kUrlPlaceHolder);
61 GURL::Replacements replacements;
62 replacements.SetPathStr(path);
63 return url.ReplaceComponents(replacements);
66 GURL CreatePrivetRegisterURL(const std::string& action,
67 const std::string& user) {
68 GURL url = CreatePrivetURL(kPrivetRegisterPath);
69 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action);
70 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user);
73 GURL CreatePrivetParamURL(const std::string& path,
74 const std::string& query_params) {
75 GURL url(kUrlPlaceHolder);
76 GURL::Replacements replacements;
77 replacements.SetPathStr(path);
78 if (!query_params.empty()) {
79 replacements.SetQueryStr(query_params);
81 return url.ReplaceComponents(replacements);
86 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
87 PrivetHTTPClientImpl* privet_client,
88 const PrivetJSONOperation::ResultCallback& callback)
89 : privet_client_(privet_client), callback_(callback) {
92 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
95 void PrivetInfoOperationImpl::Start() {
96 url_fetcher_ = privet_client_->CreateURLFetcher(
97 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this);
99 url_fetcher_->DoNotRetryOnTransientError();
100 url_fetcher_->AllowEmptyPrivetToken();
102 url_fetcher_->Start();
105 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() {
106 return privet_client_;
109 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
110 PrivetURLFetcher::ErrorType error) {
114 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher,
115 const base::DictionaryValue* value,
117 callback_.Run(value);
120 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
121 PrivetHTTPClientImpl* privet_client,
122 const std::string& user,
123 PrivetRegisterOperation::Delegate* delegate)
124 : user_(user), delegate_(delegate), privet_client_(privet_client),
128 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
131 void PrivetRegisterOperationImpl::Start() {
133 next_response_handler_ =
134 base::Bind(&PrivetRegisterOperationImpl::StartResponse,
135 base::Unretained(this));
136 SendRequest(kPrivetActionStart);
139 void PrivetRegisterOperationImpl::Cancel() {
140 url_fetcher_.reset();
143 // Owned by the message loop.
144 Cancelation* cancelation = new Cancelation(privet_client_, user_);
146 base::MessageLoop::current()->PostDelayedTask(
148 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup,
149 base::Owned(cancelation)),
150 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds));
156 void PrivetRegisterOperationImpl::CompleteRegistration() {
157 next_response_handler_ =
158 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse,
159 base::Unretained(this));
160 SendRequest(kPrivetActionComplete);
163 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
164 return privet_client_;
167 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
168 PrivetURLFetcher::ErrorType error) {
170 int visible_http_code = -1;
171 FailureReason reason = FAILURE_NETWORK;
173 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
174 visible_http_code = fetcher->response_code();
175 reason = FAILURE_HTTP_ERROR;
176 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
177 reason = FAILURE_MALFORMED_RESPONSE;
178 } else if (error == PrivetURLFetcher::TOKEN_ERROR) {
179 reason = FAILURE_TOKEN;
180 } else if (error == PrivetURLFetcher::RETRY_ERROR) {
181 reason = FAILURE_RETRY;
184 delegate_->OnPrivetRegisterError(this,
191 void PrivetRegisterOperationImpl::OnParsedJson(
192 PrivetURLFetcher* fetcher,
193 const base::DictionaryValue* value,
197 value->GetString(kPrivetKeyError, &error);
200 delegate_->OnPrivetRegisterError(this,
203 fetcher->response_code(),
208 // TODO(noamsml): Match the user&action with the user&action in the object,
209 // and fail if different.
211 next_response_handler_.Run(*value);
214 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
215 PrivetURLFetcher* fetcher,
216 const PrivetURLFetcher::TokenCallback& callback) {
217 privet_client_->RefreshPrivetToken(callback);
220 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
221 current_action_ = action;
222 url_fetcher_ = privet_client_->CreateURLFetcher(
223 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
224 url_fetcher_->Start();
227 void PrivetRegisterOperationImpl::StartResponse(
228 const base::DictionaryValue& value) {
229 next_response_handler_ =
230 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse,
231 base::Unretained(this));
233 SendRequest(kPrivetActionGetClaimToken);
236 void PrivetRegisterOperationImpl::GetClaimTokenResponse(
237 const base::DictionaryValue& value) {
238 std::string claimUrl;
239 std::string claimToken;
240 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
241 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
242 if (got_url || got_token) {
243 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
245 delegate_->OnPrivetRegisterError(this,
247 FAILURE_MALFORMED_RESPONSE,
253 void PrivetRegisterOperationImpl::CompleteResponse(
254 const base::DictionaryValue& value) {
256 value.GetString(kPrivetKeyDeviceID, &id);
259 StartInfoOperation();
262 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
263 const base::DictionaryValue* value) {
264 // TODO(noamsml): Simplify error case and depracate HTTP error value in
265 // OnPrivetRegisterError.
267 delegate_->OnPrivetRegisterError(this,
268 kPrivetActionNameInfo,
275 if (!value->HasKey(kPrivetInfoKeyID)) {
276 if (value->HasKey(kPrivetKeyError)) {
277 delegate_->OnPrivetRegisterError(this,
278 kPrivetActionNameInfo,
283 delegate_->OnPrivetRegisterError(this,
284 kPrivetActionNameInfo,
285 FAILURE_MALFORMED_RESPONSE,
294 if (!value->GetString(kPrivetInfoKeyID, &id) ||
295 id != expected_id_) {
296 delegate_->OnPrivetRegisterError(this,
297 kPrivetActionNameInfo,
298 FAILURE_MALFORMED_RESPONSE,
302 delegate_->OnPrivetRegisterDone(this, id);
306 void PrivetRegisterOperationImpl::StartInfoOperation() {
307 info_operation_ = privet_client_->CreateInfoOperation(
308 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone,
309 base::Unretained(this)));
310 info_operation_->Start();
313 PrivetRegisterOperationImpl::Cancelation::Cancelation(
314 PrivetHTTPClientImpl* privet_client,
315 const std::string& user) {
317 privet_client->CreateURLFetcher(
318 CreatePrivetRegisterURL(kPrivetActionCancel, user),
319 net::URLFetcher::POST, this);
320 url_fetcher_->DoNotRetryOnTransientError();
321 url_fetcher_->Start();
324 PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
327 void PrivetRegisterOperationImpl::Cancelation::OnError(
328 PrivetURLFetcher* fetcher,
329 PrivetURLFetcher::ErrorType error) {
332 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
333 PrivetURLFetcher* fetcher,
334 const base::DictionaryValue* value,
338 void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
339 // Nothing needs to be done, as base::Owned will delete this object,
340 // this callback is just here to pass ownership of the Cancelation to
344 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
345 PrivetHTTPClientImpl* privet_client,
346 const std::string& path,
347 const std::string& query_params,
348 const PrivetJSONOperation::ResultCallback& callback)
349 : privet_client_(privet_client), path_(path), query_params_(query_params),
350 callback_(callback) {
353 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
356 void PrivetJSONOperationImpl::Start() {
357 url_fetcher_ = privet_client_->CreateURLFetcher(
358 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
359 url_fetcher_->DoNotRetryOnTransientError();
360 url_fetcher_->Start();
363 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() {
364 return privet_client_;
367 void PrivetJSONOperationImpl::OnError(
368 PrivetURLFetcher* fetcher,
369 PrivetURLFetcher::ErrorType error) {
373 void PrivetJSONOperationImpl::OnParsedJson(
374 PrivetURLFetcher* fetcher,
375 const base::DictionaryValue* value,
377 callback_.Run(value);
380 void PrivetJSONOperationImpl::OnNeedPrivetToken(
381 PrivetURLFetcher* fetcher,
382 const PrivetURLFetcher::TokenCallback& callback) {
383 privet_client_->RefreshPrivetToken(callback);
386 PrivetDataReadOperationImpl::PrivetDataReadOperationImpl(
387 PrivetHTTPClientImpl* privet_client,
388 const std::string& path,
389 const std::string& query_params,
390 const PrivetDataReadOperation::ResultCallback& callback)
391 : privet_client_(privet_client), path_(path), query_params_(query_params),
392 callback_(callback), has_range_(false), save_to_file_(false) {
395 PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() {
399 void PrivetDataReadOperationImpl::Start() {
400 url_fetcher_ = privet_client_->CreateURLFetcher(
401 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
402 url_fetcher_->DoNotRetryOnTransientError();
405 url_fetcher_->SetByteRange(range_start_, range_end_);
409 url_fetcher_->SaveResponseToFile();
412 url_fetcher_->Start();
415 void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) {
417 range_start_ = range_start;
418 range_end_ = range_end;
421 void PrivetDataReadOperationImpl::SaveDataToFile() {
422 save_to_file_ = false;
425 PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() {
426 return privet_client_;
429 void PrivetDataReadOperationImpl::OnError(
430 PrivetURLFetcher* fetcher,
431 PrivetURLFetcher::ErrorType error) {
432 callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath());
435 void PrivetDataReadOperationImpl::OnParsedJson(
436 PrivetURLFetcher* fetcher,
437 const base::DictionaryValue* value,
442 void PrivetDataReadOperationImpl::OnNeedPrivetToken(
443 PrivetURLFetcher* fetcher,
444 const PrivetURLFetcher::TokenCallback& callback) {
445 privet_client_->RefreshPrivetToken(callback);
448 bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher* fetcher,
450 const std::string& data_str,
451 const base::FilePath& file_path) {
452 ResponseType type = (is_file) ? RESPONSE_TYPE_FILE : RESPONSE_TYPE_STRING;
453 callback_.Run(type, data_str, file_path);
457 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
458 PrivetHTTPClientImpl* privet_client,
459 PrivetLocalPrintOperation::Delegate* delegate)
460 : privet_client_(privet_client),
463 has_extended_workflow_(false),
466 dpi_(printing::kDefaultPdfDpi),
467 invalid_job_retries_(0),
468 weak_factory_(this) {
471 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
474 void PrivetLocalPrintOperationImpl::Start() {
477 // We need to get the /info response so we can know which APIs are available.
478 // TODO(noamsml): Use cached info when available.
479 info_operation_ = privet_client_->CreateInfoOperation(
480 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone,
481 base::Unretained(this)));
482 info_operation_->Start();
487 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
488 const base::DictionaryValue* value) {
489 if (value && !value->HasKey(kPrivetKeyError)) {
490 has_extended_workflow_ = false;
491 bool has_printing = false;
493 const base::ListValue* api_list;
494 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
495 for (size_t i = 0; i < api_list->GetSize(); i++) {
497 api_list->GetString(i, &api);
498 if (api == kPrivetSubmitdocPath) {
500 } else if (api == kPrivetCreatejobPath) {
501 has_extended_workflow_ = true;
507 delegate_->OnPrivetPrintingError(this, -1);
511 StartInitialRequest();
513 delegate_->OnPrivetPrintingError(this, -1);
517 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
519 ContentTypesCapability content_types;
520 if (content_types.LoadFrom(capabilities_)) {
521 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) ||
522 content_types.Contains(kPrivetContentTypeAny);
529 if (dpis.LoadFrom(capabilities_)) {
530 dpi_ = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical);
536 void PrivetLocalPrintOperationImpl::DoCreatejob() {
537 current_response_ = base::Bind(
538 &PrivetLocalPrintOperationImpl::OnCreatejobResponse,
539 base::Unretained(this));
541 // Add PWG raster settings to ticket if they are supplied by the printer.
542 PwgRasterConfigCapability raster_capability;
543 PwgRasterConfigTicketItem raster_ticket_item;
544 if (raster_capability.LoadFrom(capabilities_)) {
545 raster_ticket_item.set_value(raster_capability.value());
546 raster_ticket_item.SaveTo(&ticket_);
549 url_fetcher_= privet_client_->CreateURLFetcher(
550 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this);
551 url_fetcher_->SetUploadData(kPrivetContentTypeCJT, ticket_.ToString());
553 url_fetcher_->Start();
556 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
557 current_response_ = base::Bind(
558 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
559 base::Unretained(this));
561 GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
563 url = net::AppendQueryParameter(url,
564 kPrivetURLKeyClientName,
565 kPrivetURLValueClientName);
567 if (!user_.empty()) {
568 url = net::AppendQueryParameter(url,
569 kPrivetURLKeyUserName,
573 base::string16 shortened_jobname;
575 gfx::ElideString(base::UTF8ToUTF16(jobname_),
576 kPrivetLocalPrintMaxJobNameLength,
579 if (!jobname_.empty()) {
580 url = net::AppendQueryParameter(
581 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname));
584 if (!jobid_.empty()) {
585 url = net::AppendQueryParameter(url,
591 url = net::AppendQueryParameter(url,
592 kPrivetURLKeyOffline,
593 kPrivetURLValueOffline);
596 url_fetcher_= privet_client_->CreateURLFetcher(
597 url, net::URLFetcher::POST, this);
600 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster,
603 // TODO(noamsml): Move to file-based upload data?
604 std::string data_str((const char*)data_->front(), data_->size());
605 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str);
608 url_fetcher_->Start();
611 void PrivetLocalPrintOperationImpl::StartPrinting() {
612 if (has_extended_workflow_ && jobid_.empty()) {
619 void PrivetLocalPrintOperationImpl::FillPwgRasterSettings(
620 printing::PwgRasterSettings* transform_settings) {
621 PwgRasterConfigCapability raster_capability;
622 // If the raster capability fails to load, raster_capability will contain
623 // the default value.
624 raster_capability.LoadFrom(capabilities_);
626 DuplexTicketItem duplex_item;
627 DuplexType duplex_value = NO_DUPLEX;
629 DocumentSheetBack document_sheet_back =
630 raster_capability.value().document_sheet_back;
632 if (duplex_item.LoadFrom(ticket_)) {
633 duplex_value = duplex_item.value();
636 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
637 switch (duplex_value) {
639 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
642 if (document_sheet_back == ROTATED) {
643 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
644 } else if (document_sheet_back == FLIPPED) {
645 transform_settings->odd_page_transform =
646 printing::TRANSFORM_FLIP_VERTICAL;
650 if (document_sheet_back == MANUAL_TUMBLE) {
651 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
652 } else if (document_sheet_back == FLIPPED) {
653 transform_settings->odd_page_transform =
654 printing::TRANSFORM_FLIP_HORIZONTAL;
658 transform_settings->rotate_all_pages =
659 raster_capability.value().rotate_all_pages;
661 transform_settings->reverse_page_order =
662 raster_capability.value().reverse_order_streaming;
665 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
666 printing::PwgRasterSettings transform_settings;
668 FillPwgRasterSettings(&transform_settings);
670 if (!pwg_raster_converter_)
671 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
674 scale /= printing::kPointsPerInch;
675 // Make vertical rectangle to optimize streaming to printer. Fix orientation
677 gfx::Rect area(std::min(page_size_.width(), page_size_.height()) * scale,
678 std::max(page_size_.width(), page_size_.height()) * scale);
679 pwg_raster_converter_->Start(
681 printing::PdfRenderSettings(area, dpi_, true),
683 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted,
684 base::Unretained(this)));
687 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
689 const base::DictionaryValue* value) {
691 // This error is only relevant in the case of extended workflow:
692 // If the print job ID is invalid, retry createjob and submitdoc,
693 // rather than simply retrying the current request.
694 if (has_error && value->GetString(kPrivetKeyError, &error)) {
695 if (has_extended_workflow_ &&
696 error == kPrivetErrorInvalidPrintJob &&
697 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) {
698 invalid_job_retries_++;
700 int timeout = kPrivetLocalPrintDefaultTimeout;
701 value->GetInteger(kPrivetKeyTimeout, &timeout);
703 double random_scaling_factor =
704 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
706 timeout = static_cast<int>(timeout * random_scaling_factor);
708 timeout = std::max(timeout, kPrivetMinimumTimeout);
710 base::MessageLoop::current()->PostDelayedTask(
711 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob,
712 weak_factory_.GetWeakPtr()),
713 base::TimeDelta::FromSeconds(timeout));
714 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) {
718 delegate_->OnPrivetPrintingError(this, 200);
724 // If we've gotten this far, there are no errors, so we've effectively
726 delegate_->OnPrivetPrintingDone(this);
729 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
731 const base::DictionaryValue* value) {
733 delegate_->OnPrivetPrintingError(this, 200);
737 // Try to get job ID from value. If not, jobid_ will be empty and we will use
739 value->GetString(kPrivetKeyJobID, &jobid_);
744 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
746 const base::FilePath& pwg_file_path) {
748 delegate_->OnPrivetPrintingError(this, -1);
752 DCHECK(!pwg_file_path.empty());
754 pwg_file_path_ = pwg_file_path;
758 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
759 return privet_client_;
762 void PrivetLocalPrintOperationImpl::OnError(
763 PrivetURLFetcher* fetcher,
764 PrivetURLFetcher::ErrorType error) {
765 delegate_->OnPrivetPrintingError(this, -1);
768 void PrivetLocalPrintOperationImpl::OnParsedJson(
769 PrivetURLFetcher* fetcher,
770 const base::DictionaryValue* value,
772 DCHECK(!current_response_.is_null());
773 current_response_.Run(has_error, value);
776 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
777 PrivetURLFetcher* fetcher,
778 const PrivetURLFetcher::TokenCallback& callback) {
779 privet_client_->RefreshPrivetToken(callback);
782 void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) {
787 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
789 ticket_.InitFromString(ticket);
792 void PrivetLocalPrintOperationImpl::SetCapabilities(
793 const std::string& capabilities) {
795 capabilities_.InitFromString(capabilities);
798 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
803 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
808 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
813 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) {
815 page_size_ = page_size;
818 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
819 scoped_ptr<PWGRasterConverter> pwg_raster_converter) {
820 pwg_raster_converter_ = pwg_raster_converter.Pass();
823 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
824 const std::string& name,
825 const net::HostPortPair& host_port,
826 net::URLRequestContextGetter* request_context)
827 : name_(name), request_context_(request_context), host_port_(host_port) {}
829 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
832 scoped_ptr<PrivetRegisterOperation>
833 PrivetHTTPClientImpl::CreateRegisterOperation(
834 const std::string& user,
835 PrivetRegisterOperation::Delegate* delegate) {
836 return scoped_ptr<PrivetRegisterOperation>(
837 new PrivetRegisterOperationImpl(this, user, delegate));
840 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation(
841 const PrivetJSONOperation::ResultCallback& callback) {
842 return scoped_ptr<PrivetJSONOperation>(
843 new PrivetInfoOperationImpl(this, callback));
846 scoped_ptr<PrivetJSONOperation>
847 PrivetHTTPClientImpl::CreateCapabilitiesOperation(
848 const PrivetJSONOperation::ResultCallback& callback) {
849 return scoped_ptr<PrivetJSONOperation>(
850 new PrivetJSONOperationImpl(this, kPrivetCapabilitiesPath, "", callback));
853 scoped_ptr<PrivetLocalPrintOperation>
854 PrivetHTTPClientImpl::CreateLocalPrintOperation(
855 PrivetLocalPrintOperation::Delegate* delegate) {
856 return scoped_ptr<PrivetLocalPrintOperation>(
857 new PrivetLocalPrintOperationImpl(this, delegate));
860 scoped_ptr<PrivetJSONOperation>
861 PrivetHTTPClientImpl::CreateStorageListOperation(
862 const std::string& path,
863 const PrivetJSONOperation::ResultCallback& callback) {
864 std::string url_param = base::StringPrintf(kPrivetStorageParamPathFormat,
866 return scoped_ptr<PrivetJSONOperation>(
867 new PrivetJSONOperationImpl(this, kPrivetStorageListPath, url_param,
872 scoped_ptr<PrivetDataReadOperation>
873 PrivetHTTPClientImpl::CreateStorageReadOperation(
874 const std::string& path,
875 const PrivetDataReadOperation::ResultCallback& callback) {
876 std::string url_param = base::StringPrintf(kPrivetStorageParamPathFormat,
878 return scoped_ptr<PrivetDataReadOperation>(
879 new PrivetDataReadOperationImpl(this, kPrivetStorageContentPath,
880 url_param, callback));
883 const std::string& PrivetHTTPClientImpl::GetName() {
887 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
888 const GURL& url, net::URLFetcher::RequestType request_type,
889 PrivetURLFetcher::Delegate* delegate) const {
890 GURL::Replacements replacements;
891 replacements.SetHostStr(host_port_.host());
892 std::string port(base::IntToString(host_port_.port())); // Keep string alive.
893 replacements.SetPortStr(port);
894 return scoped_ptr<PrivetURLFetcher>(
895 new PrivetURLFetcher(url.ReplaceComponents(replacements),
897 request_context_.get(),
901 void PrivetHTTPClientImpl::RefreshPrivetToken(
902 const PrivetURLFetcher::TokenCallback& callback) {
903 token_callbacks_.push_back(callback);
905 if (!info_operation_) {
906 info_operation_ = CreateInfoOperation(
907 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone,
908 base::Unretained(this)));
909 info_operation_->Start();
913 void PrivetHTTPClientImpl::OnPrivetInfoDone(
914 const base::DictionaryValue* value) {
915 info_operation_.reset();
918 // If this does not succeed, token will be empty, and an empty string
919 // is our sentinel value, since empty X-Privet-Tokens are not allowed.
921 value->GetString(kPrivetInfoKeyToken, &token);
924 TokenCallbackVector token_callbacks;
925 token_callbacks_.swap(token_callbacks);
927 for (TokenCallbackVector::iterator i = token_callbacks.begin();
928 i != token_callbacks.end(); i++) {
933 } // namespace local_discovery