[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / local_discovery / privet_http_impl.cc
blob19896c43e09b79f7101925e1f259ecfa57d8b487
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"
7 #include <algorithm>
8 #include <vector>
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/common/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"
22 #include "url/gurl.h"
24 using namespace cloud_devices::printer;
26 namespace cloud_print {
27 extern const char kContentTypeJSON[];
30 namespace local_discovery {
32 namespace {
33 const char kUrlPlaceHolder[] = "http://host/";
34 const char kPrivetRegisterActionArgName[] = "action";
35 const char kPrivetRegisterUserArgName[] = "user";
37 const char kPrivetURLKeyUserName[] = "user_name";
38 const char kPrivetURLKeyClientName[] = "client_name";
39 const char kPrivetURLKeyJobname[] = "job_name";
40 const char kPrivetURLKeyOffline[] = "offline";
41 const char kPrivetURLValueOffline[] = "1";
42 const char kPrivetURLValueClientName[] = "Chrome";
44 const char kPrivetContentTypePDF[] = "application/pdf";
45 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
46 const char kPrivetContentTypeAny[] = "*/*";
48 const char kPrivetStorageListPath[] = "/privet/storage/list";
49 const char kPrivetStorageContentPath[] = "/privet/storage/content";
50 const char kPrivetStorageParamPathFormat[] = "path=%s";
52 const char kPrivetKeyJobID[] = "job_id";
54 const int kPrivetCancelationTimeoutSeconds = 3;
56 const int kPrivetLocalPrintMaxRetries = 2;
58 const int kPrivetLocalPrintDefaultTimeout = 5;
60 const size_t kPrivetLocalPrintMaxJobNameLength = 64;
62 GURL CreatePrivetURL(const std::string& path) {
63 GURL url(kUrlPlaceHolder);
64 GURL::Replacements replacements;
65 replacements.SetPathStr(path);
66 return url.ReplaceComponents(replacements);
69 GURL CreatePrivetRegisterURL(const std::string& action,
70 const std::string& user) {
71 GURL url = CreatePrivetURL(kPrivetRegisterPath);
72 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action);
73 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user);
76 GURL CreatePrivetParamURL(const std::string& path,
77 const std::string& query_params) {
78 GURL url(kUrlPlaceHolder);
79 GURL::Replacements replacements;
80 replacements.SetPathStr(path);
81 if (!query_params.empty()) {
82 replacements.SetQueryStr(query_params);
84 return url.ReplaceComponents(replacements);
87 } // namespace
89 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
90 PrivetHTTPClientImpl* privet_client,
91 const PrivetJSONOperation::ResultCallback& callback)
92 : privet_client_(privet_client), callback_(callback) {
95 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
98 void PrivetInfoOperationImpl::Start() {
99 url_fetcher_ = privet_client_->CreateURLFetcher(
100 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this);
102 url_fetcher_->DoNotRetryOnTransientError();
103 url_fetcher_->SendEmptyPrivetToken();
105 url_fetcher_->Start();
108 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() {
109 return privet_client_;
112 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
113 PrivetURLFetcher::ErrorType error) {
114 callback_.Run(NULL);
117 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher,
118 const base::DictionaryValue* value,
119 bool has_error) {
120 callback_.Run(value);
123 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
124 PrivetHTTPClientImpl* privet_client,
125 const std::string& user,
126 PrivetRegisterOperation::Delegate* delegate)
127 : user_(user), delegate_(delegate), privet_client_(privet_client),
128 ongoing_(false) {
131 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
134 void PrivetRegisterOperationImpl::Start() {
135 ongoing_ = true;
136 next_response_handler_ =
137 base::Bind(&PrivetRegisterOperationImpl::StartResponse,
138 base::Unretained(this));
139 SendRequest(kPrivetActionStart);
142 void PrivetRegisterOperationImpl::Cancel() {
143 url_fetcher_.reset();
145 if (ongoing_) {
146 // Owned by the message loop.
147 Cancelation* cancelation = new Cancelation(privet_client_, user_);
149 base::MessageLoop::current()->PostDelayedTask(
150 FROM_HERE,
151 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup,
152 base::Owned(cancelation)),
153 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds));
155 ongoing_ = false;
159 void PrivetRegisterOperationImpl::CompleteRegistration() {
160 next_response_handler_ =
161 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse,
162 base::Unretained(this));
163 SendRequest(kPrivetActionComplete);
166 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
167 return privet_client_;
170 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
171 PrivetURLFetcher::ErrorType error) {
172 ongoing_ = false;
173 int visible_http_code = -1;
174 FailureReason reason = FAILURE_NETWORK;
176 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
177 visible_http_code = fetcher->response_code();
178 reason = FAILURE_HTTP_ERROR;
179 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
180 reason = FAILURE_MALFORMED_RESPONSE;
181 } else if (error == PrivetURLFetcher::TOKEN_ERROR) {
182 reason = FAILURE_TOKEN;
183 } else if (error == PrivetURLFetcher::RETRY_ERROR) {
184 reason = FAILURE_RETRY;
187 delegate_->OnPrivetRegisterError(this,
188 current_action_,
189 reason,
190 visible_http_code,
191 NULL);
194 void PrivetRegisterOperationImpl::OnParsedJson(
195 PrivetURLFetcher* fetcher,
196 const base::DictionaryValue* value,
197 bool has_error) {
198 if (has_error) {
199 std::string error;
200 value->GetString(kPrivetKeyError, &error);
202 ongoing_ = false;
203 delegate_->OnPrivetRegisterError(this,
204 current_action_,
205 FAILURE_JSON_ERROR,
206 fetcher->response_code(),
207 value);
208 return;
211 // TODO(noamsml): Match the user&action with the user&action in the object,
212 // and fail if different.
214 next_response_handler_.Run(*value);
217 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
218 PrivetURLFetcher* fetcher,
219 const PrivetURLFetcher::TokenCallback& callback) {
220 privet_client_->RefreshPrivetToken(callback);
223 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
224 current_action_ = action;
225 url_fetcher_ = privet_client_->CreateURLFetcher(
226 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
227 url_fetcher_->Start();
230 void PrivetRegisterOperationImpl::StartResponse(
231 const base::DictionaryValue& value) {
232 next_response_handler_ =
233 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse,
234 base::Unretained(this));
236 SendRequest(kPrivetActionGetClaimToken);
239 void PrivetRegisterOperationImpl::GetClaimTokenResponse(
240 const base::DictionaryValue& value) {
241 std::string claimUrl;
242 std::string claimToken;
243 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
244 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
245 if (got_url || got_token) {
246 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
247 } else {
248 delegate_->OnPrivetRegisterError(this,
249 current_action_,
250 FAILURE_MALFORMED_RESPONSE,
252 NULL);
256 void PrivetRegisterOperationImpl::CompleteResponse(
257 const base::DictionaryValue& value) {
258 std::string id;
259 value.GetString(kPrivetKeyDeviceID, &id);
260 ongoing_ = false;
261 expected_id_ = id;
262 StartInfoOperation();
265 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
266 const base::DictionaryValue* value) {
267 // TODO(noamsml): Simplify error case and depracate HTTP error value in
268 // OnPrivetRegisterError.
269 if (!value) {
270 delegate_->OnPrivetRegisterError(this,
271 kPrivetActionNameInfo,
272 FAILURE_NETWORK,
274 NULL);
275 return;
278 if (!value->HasKey(kPrivetInfoKeyID)) {
279 if (value->HasKey(kPrivetKeyError)) {
280 delegate_->OnPrivetRegisterError(this,
281 kPrivetActionNameInfo,
282 FAILURE_JSON_ERROR,
284 value);
285 } else {
286 delegate_->OnPrivetRegisterError(this,
287 kPrivetActionNameInfo,
288 FAILURE_MALFORMED_RESPONSE,
290 NULL);
292 return;
295 std::string id;
297 if (!value->GetString(kPrivetInfoKeyID, &id) ||
298 id != expected_id_) {
299 delegate_->OnPrivetRegisterError(this,
300 kPrivetActionNameInfo,
301 FAILURE_MALFORMED_RESPONSE,
303 NULL);
304 } else {
305 delegate_->OnPrivetRegisterDone(this, id);
309 void PrivetRegisterOperationImpl::StartInfoOperation() {
310 info_operation_ = privet_client_->CreateInfoOperation(
311 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone,
312 base::Unretained(this)));
313 info_operation_->Start();
316 PrivetRegisterOperationImpl::Cancelation::Cancelation(
317 PrivetHTTPClientImpl* privet_client,
318 const std::string& user) {
319 url_fetcher_ =
320 privet_client->CreateURLFetcher(
321 CreatePrivetRegisterURL(kPrivetActionCancel, user),
322 net::URLFetcher::POST, this);
323 url_fetcher_->DoNotRetryOnTransientError();
324 url_fetcher_->Start();
327 PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
330 void PrivetRegisterOperationImpl::Cancelation::OnError(
331 PrivetURLFetcher* fetcher,
332 PrivetURLFetcher::ErrorType error) {
335 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
336 PrivetURLFetcher* fetcher,
337 const base::DictionaryValue* value,
338 bool has_error) {
341 void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
342 // Nothing needs to be done, as base::Owned will delete this object,
343 // this callback is just here to pass ownership of the Cancelation to
344 // the message loop.
347 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
348 PrivetHTTPClientImpl* privet_client,
349 const std::string& path,
350 const std::string& query_params,
351 const PrivetJSONOperation::ResultCallback& callback)
352 : privet_client_(privet_client), path_(path), query_params_(query_params),
353 callback_(callback) {
356 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
359 void PrivetJSONOperationImpl::Start() {
360 url_fetcher_ = privet_client_->CreateURLFetcher(
361 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
362 url_fetcher_->DoNotRetryOnTransientError();
363 url_fetcher_->Start();
366 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() {
367 return privet_client_;
370 void PrivetJSONOperationImpl::OnError(
371 PrivetURLFetcher* fetcher,
372 PrivetURLFetcher::ErrorType error) {
373 callback_.Run(NULL);
376 void PrivetJSONOperationImpl::OnParsedJson(
377 PrivetURLFetcher* fetcher,
378 const base::DictionaryValue* value,
379 bool has_error) {
380 callback_.Run(value);
383 void PrivetJSONOperationImpl::OnNeedPrivetToken(
384 PrivetURLFetcher* fetcher,
385 const PrivetURLFetcher::TokenCallback& callback) {
386 privet_client_->RefreshPrivetToken(callback);
389 PrivetDataReadOperationImpl::PrivetDataReadOperationImpl(
390 PrivetHTTPClientImpl* privet_client,
391 const std::string& path,
392 const std::string& query_params,
393 const PrivetDataReadOperation::ResultCallback& callback)
394 : privet_client_(privet_client), path_(path), query_params_(query_params),
395 callback_(callback), has_range_(false), save_to_file_(false) {
398 PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() {
402 void PrivetDataReadOperationImpl::Start() {
403 url_fetcher_ = privet_client_->CreateURLFetcher(
404 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
405 url_fetcher_->DoNotRetryOnTransientError();
407 if (has_range_) {
408 url_fetcher_->SetByteRange(range_start_, range_end_);
411 if (save_to_file_) {
412 url_fetcher_->SaveResponseToFile();
415 url_fetcher_->Start();
418 void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) {
419 has_range_ = true;
420 range_start_ = range_start;
421 range_end_ = range_end;
424 void PrivetDataReadOperationImpl::SaveDataToFile() {
425 save_to_file_ = false;
428 PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() {
429 return privet_client_;
432 void PrivetDataReadOperationImpl::OnError(
433 PrivetURLFetcher* fetcher,
434 PrivetURLFetcher::ErrorType error) {
435 callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath());
438 void PrivetDataReadOperationImpl::OnParsedJson(
439 PrivetURLFetcher* fetcher,
440 const base::DictionaryValue* value,
441 bool has_error) {
442 NOTREACHED();
445 void PrivetDataReadOperationImpl::OnNeedPrivetToken(
446 PrivetURLFetcher* fetcher,
447 const PrivetURLFetcher::TokenCallback& callback) {
448 privet_client_->RefreshPrivetToken(callback);
451 bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher* fetcher,
452 bool is_file,
453 const std::string& data_str,
454 const base::FilePath& file_path) {
455 ResponseType type = (is_file) ? RESPONSE_TYPE_FILE : RESPONSE_TYPE_STRING;
456 callback_.Run(type, data_str, file_path);
457 return true;
460 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
461 PrivetHTTPClientImpl* privet_client,
462 PrivetLocalPrintOperation::Delegate* delegate)
463 : privet_client_(privet_client),
464 delegate_(delegate),
465 use_pdf_(false),
466 has_extended_workflow_(false),
467 started_(false),
468 offline_(false),
469 dpi_(printing::kDefaultPdfDpi),
470 invalid_job_retries_(0),
471 weak_factory_(this) {
474 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
477 void PrivetLocalPrintOperationImpl::Start() {
478 DCHECK(!started_);
480 // We need to get the /info response so we can know which APIs are available.
481 // TODO(noamsml): Use cached info when available.
482 info_operation_ = privet_client_->CreateInfoOperation(
483 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone,
484 base::Unretained(this)));
485 info_operation_->Start();
487 started_ = true;
490 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
491 const base::DictionaryValue* value) {
492 if (value && !value->HasKey(kPrivetKeyError)) {
493 has_extended_workflow_ = false;
494 bool has_printing = false;
496 const base::ListValue* api_list;
497 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
498 for (size_t i = 0; i < api_list->GetSize(); i++) {
499 std::string api;
500 api_list->GetString(i, &api);
501 if (api == kPrivetSubmitdocPath) {
502 has_printing = true;
503 } else if (api == kPrivetCreatejobPath) {
504 has_extended_workflow_ = true;
509 if (!has_printing) {
510 delegate_->OnPrivetPrintingError(this, -1);
511 return;
514 StartInitialRequest();
515 } else {
516 delegate_->OnPrivetPrintingError(this, -1);
520 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
521 use_pdf_ = false;
522 ContentTypesCapability content_types;
523 if (content_types.LoadFrom(capabilities_)) {
524 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) ||
525 content_types.Contains(kPrivetContentTypeAny);
528 if (use_pdf_) {
529 StartPrinting();
530 } else {
531 DpiCapability dpis;
532 if (dpis.LoadFrom(capabilities_)) {
533 dpi_ = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical);
535 StartConvertToPWG();
539 void PrivetLocalPrintOperationImpl::DoCreatejob() {
540 current_response_ = base::Bind(
541 &PrivetLocalPrintOperationImpl::OnCreatejobResponse,
542 base::Unretained(this));
544 url_fetcher_= privet_client_->CreateURLFetcher(
545 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this);
546 url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON,
547 ticket_.ToString());
549 url_fetcher_->Start();
552 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
553 current_response_ = base::Bind(
554 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
555 base::Unretained(this));
557 GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
559 url = net::AppendQueryParameter(url,
560 kPrivetURLKeyClientName,
561 kPrivetURLValueClientName);
563 if (!user_.empty()) {
564 url = net::AppendQueryParameter(url,
565 kPrivetURLKeyUserName,
566 user_);
569 base::string16 shortened_jobname;
571 gfx::ElideString(base::UTF8ToUTF16(jobname_),
572 kPrivetLocalPrintMaxJobNameLength,
573 &shortened_jobname);
575 if (!jobname_.empty()) {
576 url = net::AppendQueryParameter(
577 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname));
580 if (!jobid_.empty()) {
581 url = net::AppendQueryParameter(url,
582 kPrivetKeyJobID,
583 jobid_);
586 if (offline_) {
587 url = net::AppendQueryParameter(url,
588 kPrivetURLKeyOffline,
589 kPrivetURLValueOffline);
592 url_fetcher_= privet_client_->CreateURLFetcher(
593 url, net::URLFetcher::POST, this);
595 if (!use_pdf_) {
596 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster,
597 pwg_file_path_);
598 } else {
599 // TODO(noamsml): Move to file-based upload data?
600 std::string data_str((const char*)data_->front(), data_->size());
601 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str);
604 url_fetcher_->Start();
607 void PrivetLocalPrintOperationImpl::StartPrinting() {
608 if (has_extended_workflow_ && jobid_.empty()) {
609 DoCreatejob();
610 } else {
611 DoSubmitdoc();
615 void PrivetLocalPrintOperationImpl::FillPwgRasterSettings(
616 printing::PwgRasterSettings* transform_settings) {
617 PwgRasterConfigCapability raster_capability;
618 // If the raster capability fails to load, raster_capability will contain
619 // the default value.
620 raster_capability.LoadFrom(capabilities_);
622 DuplexTicketItem duplex_item;
623 DuplexType duplex_value = NO_DUPLEX;
625 DocumentSheetBack document_sheet_back =
626 raster_capability.value().document_sheet_back;
628 if (duplex_item.LoadFrom(ticket_)) {
629 duplex_value = duplex_item.value();
632 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
633 switch (duplex_value) {
634 case NO_DUPLEX:
635 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
636 break;
637 case LONG_EDGE:
638 if (document_sheet_back == ROTATED) {
639 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
640 } else if (document_sheet_back == FLIPPED) {
641 transform_settings->odd_page_transform =
642 printing::TRANSFORM_FLIP_VERTICAL;
644 break;
645 case SHORT_EDGE:
646 if (document_sheet_back == MANUAL_TUMBLE) {
647 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
648 } else if (document_sheet_back == FLIPPED) {
649 transform_settings->odd_page_transform =
650 printing::TRANSFORM_FLIP_HORIZONTAL;
654 transform_settings->rotate_all_pages =
655 raster_capability.value().rotate_all_pages;
657 transform_settings->reverse_page_order =
658 raster_capability.value().reverse_order_streaming;
661 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
662 printing::PwgRasterSettings transform_settings;
664 FillPwgRasterSettings(&transform_settings);
666 if (!pwg_raster_converter_)
667 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
669 double scale = dpi_;
670 scale /= printing::kPointsPerInch;
671 // Make vertical rectangle to optimize streaming to printer. Fix orientation
672 // by autorotate.
673 gfx::Rect area(std::min(page_size_.width(), page_size_.height()) * scale,
674 std::max(page_size_.width(), page_size_.height()) * scale);
675 pwg_raster_converter_->Start(
676 data_,
677 printing::PdfRenderSettings(area, dpi_, true),
678 transform_settings,
679 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted,
680 base::Unretained(this)));
683 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
684 bool has_error,
685 const base::DictionaryValue* value) {
686 std::string error;
687 // This error is only relevant in the case of extended workflow:
688 // If the print job ID is invalid, retry createjob and submitdoc,
689 // rather than simply retrying the current request.
690 if (has_error && value->GetString(kPrivetKeyError, &error)) {
691 if (has_extended_workflow_ &&
692 error == kPrivetErrorInvalidPrintJob &&
693 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) {
694 invalid_job_retries_++;
696 int timeout = kPrivetLocalPrintDefaultTimeout;
697 value->GetInteger(kPrivetKeyTimeout, &timeout);
699 double random_scaling_factor =
700 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
702 timeout = static_cast<int>(timeout * random_scaling_factor);
704 timeout = std::max(timeout, kPrivetMinimumTimeout);
706 base::MessageLoop::current()->PostDelayedTask(
707 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob,
708 weak_factory_.GetWeakPtr()),
709 base::TimeDelta::FromSeconds(timeout));
710 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) {
711 use_pdf_ = false;
712 StartConvertToPWG();
713 } else {
714 delegate_->OnPrivetPrintingError(this, 200);
717 return;
720 // If we've gotten this far, there are no errors, so we've effectively
721 // succeeded.
722 delegate_->OnPrivetPrintingDone(this);
725 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
726 bool has_error,
727 const base::DictionaryValue* value) {
728 if (has_error) {
729 delegate_->OnPrivetPrintingError(this, 200);
730 return;
733 // Try to get job ID from value. If not, jobid_ will be empty and we will use
734 // simple printing.
735 value->GetString(kPrivetKeyJobID, &jobid_);
737 DoSubmitdoc();
740 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
741 bool success,
742 const base::FilePath& pwg_file_path) {
743 if (!success) {
744 delegate_->OnPrivetPrintingError(this, -1);
745 return;
748 DCHECK(!pwg_file_path.empty());
750 pwg_file_path_ = pwg_file_path;
751 StartPrinting();
754 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
755 return privet_client_;
758 void PrivetLocalPrintOperationImpl::OnError(
759 PrivetURLFetcher* fetcher,
760 PrivetURLFetcher::ErrorType error) {
761 delegate_->OnPrivetPrintingError(this, -1);
764 void PrivetLocalPrintOperationImpl::OnParsedJson(
765 PrivetURLFetcher* fetcher,
766 const base::DictionaryValue* value,
767 bool has_error) {
768 DCHECK(!current_response_.is_null());
769 current_response_.Run(has_error, value);
772 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
773 PrivetURLFetcher* fetcher,
774 const PrivetURLFetcher::TokenCallback& callback) {
775 privet_client_->RefreshPrivetToken(callback);
778 void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) {
779 DCHECK(!started_);
780 data_ = data;
783 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
784 DCHECK(!started_);
785 ticket_.InitFromString(ticket);
788 void PrivetLocalPrintOperationImpl::SetCapabilities(
789 const std::string& capabilities) {
790 DCHECK(!started_);
791 capabilities_.InitFromString(capabilities);
794 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
795 DCHECK(!started_);
796 user_= user;
799 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
800 DCHECK(!started_);
801 jobname_ = jobname;
804 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
805 DCHECK(!started_);
806 offline_ = offline;
809 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) {
810 DCHECK(!started_);
811 page_size_ = page_size;
814 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
815 scoped_ptr<PWGRasterConverter> pwg_raster_converter) {
816 pwg_raster_converter_ = pwg_raster_converter.Pass();
819 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
820 const std::string& name,
821 const net::HostPortPair& host_port,
822 net::URLRequestContextGetter* request_context)
823 : name_(name), request_context_(request_context), host_port_(host_port) {}
825 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
828 scoped_ptr<PrivetRegisterOperation>
829 PrivetHTTPClientImpl::CreateRegisterOperation(
830 const std::string& user,
831 PrivetRegisterOperation::Delegate* delegate) {
832 return scoped_ptr<PrivetRegisterOperation>(
833 new PrivetRegisterOperationImpl(this, user, delegate));
836 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation(
837 const PrivetJSONOperation::ResultCallback& callback) {
838 return scoped_ptr<PrivetJSONOperation>(
839 new PrivetInfoOperationImpl(this, callback));
842 scoped_ptr<PrivetJSONOperation>
843 PrivetHTTPClientImpl::CreateCapabilitiesOperation(
844 const PrivetJSONOperation::ResultCallback& callback) {
845 return scoped_ptr<PrivetJSONOperation>(
846 new PrivetJSONOperationImpl(this, kPrivetCapabilitiesPath, "", callback));
849 scoped_ptr<PrivetLocalPrintOperation>
850 PrivetHTTPClientImpl::CreateLocalPrintOperation(
851 PrivetLocalPrintOperation::Delegate* delegate) {
852 return scoped_ptr<PrivetLocalPrintOperation>(
853 new PrivetLocalPrintOperationImpl(this, delegate));
856 scoped_ptr<PrivetJSONOperation>
857 PrivetHTTPClientImpl::CreateStorageListOperation(
858 const std::string& path,
859 const PrivetJSONOperation::ResultCallback& callback) {
860 std::string url_param = base::StringPrintf(kPrivetStorageParamPathFormat,
861 path.c_str());
862 return scoped_ptr<PrivetJSONOperation>(
863 new PrivetJSONOperationImpl(this, kPrivetStorageListPath, url_param,
864 callback));
868 scoped_ptr<PrivetDataReadOperation>
869 PrivetHTTPClientImpl::CreateStorageReadOperation(
870 const std::string& path,
871 const PrivetDataReadOperation::ResultCallback& callback) {
872 std::string url_param = base::StringPrintf(kPrivetStorageParamPathFormat,
873 path.c_str());
874 return scoped_ptr<PrivetDataReadOperation>(
875 new PrivetDataReadOperationImpl(this, kPrivetStorageContentPath,
876 url_param, callback));
879 const std::string& PrivetHTTPClientImpl::GetName() {
880 return name_;
883 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
884 const GURL& url, net::URLFetcher::RequestType request_type,
885 PrivetURLFetcher::Delegate* delegate) const {
886 GURL::Replacements replacements;
887 replacements.SetHostStr(host_port_.host());
888 std::string port(base::IntToString(host_port_.port())); // Keep string alive.
889 replacements.SetPortStr(port);
890 return scoped_ptr<PrivetURLFetcher>(
891 new PrivetURLFetcher(url.ReplaceComponents(replacements),
892 request_type,
893 request_context_.get(),
894 delegate));
897 void PrivetHTTPClientImpl::RefreshPrivetToken(
898 const PrivetURLFetcher::TokenCallback& callback) {
899 token_callbacks_.push_back(callback);
901 if (!info_operation_) {
902 info_operation_ = CreateInfoOperation(
903 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone,
904 base::Unretained(this)));
905 info_operation_->Start();
909 void PrivetHTTPClientImpl::OnPrivetInfoDone(
910 const base::DictionaryValue* value) {
911 info_operation_.reset();
912 std::string token;
914 // If this does not succeed, token will be empty, and an empty string
915 // is our sentinel value, since empty X-Privet-Tokens are not allowed.
916 if (value) {
917 value->GetString(kPrivetInfoKeyToken, &token);
920 TokenCallbackVector token_callbacks;
921 token_callbacks_.swap(token_callbacks);
923 for (TokenCallbackVector::iterator i = token_callbacks.begin();
924 i != token_callbacks.end(); i++) {
925 i->Run(token);
929 } // namespace local_discovery