Update mojo surfaces bindings and mojo/cc/ glue
[chromium-blink-merge.git] / chrome / browser / local_discovery / privet_http_impl.cc
blobd547ac0eb2084f3297affe0220451b9500de6202
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 PrivetHTTPClient* 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 PrivetHTTPClient* privet_client,
125 const std::string& user,
126 PrivetRegisterOperation::Delegate* delegate)
127 : user_(user),
128 delegate_(delegate),
129 privet_client_(privet_client),
130 ongoing_(false) {
133 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
136 void PrivetRegisterOperationImpl::Start() {
137 ongoing_ = true;
138 next_response_handler_ =
139 base::Bind(&PrivetRegisterOperationImpl::StartResponse,
140 base::Unretained(this));
141 SendRequest(kPrivetActionStart);
144 void PrivetRegisterOperationImpl::Cancel() {
145 url_fetcher_.reset();
147 if (ongoing_) {
148 // Owned by the message loop.
149 Cancelation* cancelation = new Cancelation(privet_client_, user_);
151 base::MessageLoop::current()->PostDelayedTask(
152 FROM_HERE,
153 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup,
154 base::Owned(cancelation)),
155 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds));
157 ongoing_ = false;
161 void PrivetRegisterOperationImpl::CompleteRegistration() {
162 next_response_handler_ =
163 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse,
164 base::Unretained(this));
165 SendRequest(kPrivetActionComplete);
168 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
169 return privet_client_;
172 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
173 PrivetURLFetcher::ErrorType error) {
174 ongoing_ = false;
175 int visible_http_code = -1;
176 FailureReason reason = FAILURE_NETWORK;
178 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
179 visible_http_code = fetcher->response_code();
180 reason = FAILURE_HTTP_ERROR;
181 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
182 reason = FAILURE_MALFORMED_RESPONSE;
183 } else if (error == PrivetURLFetcher::TOKEN_ERROR) {
184 reason = FAILURE_TOKEN;
185 } else if (error == PrivetURLFetcher::RETRY_ERROR) {
186 reason = FAILURE_RETRY;
189 delegate_->OnPrivetRegisterError(this,
190 current_action_,
191 reason,
192 visible_http_code,
193 NULL);
196 void PrivetRegisterOperationImpl::OnParsedJson(
197 PrivetURLFetcher* fetcher,
198 const base::DictionaryValue& value,
199 bool has_error) {
200 if (has_error) {
201 std::string error;
202 value.GetString(kPrivetKeyError, &error);
204 ongoing_ = false;
205 delegate_->OnPrivetRegisterError(this,
206 current_action_,
207 FAILURE_JSON_ERROR,
208 fetcher->response_code(),
209 &value);
210 return;
213 // TODO(noamsml): Match the user&action with the user&action in the object,
214 // and fail if different.
216 next_response_handler_.Run(value);
219 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
220 PrivetURLFetcher* fetcher,
221 const PrivetURLFetcher::TokenCallback& callback) {
222 privet_client_->RefreshPrivetToken(callback);
225 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
226 current_action_ = action;
227 url_fetcher_ = privet_client_->CreateURLFetcher(
228 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
229 url_fetcher_->Start();
232 void PrivetRegisterOperationImpl::StartResponse(
233 const base::DictionaryValue& value) {
234 next_response_handler_ =
235 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse,
236 base::Unretained(this));
238 SendRequest(kPrivetActionGetClaimToken);
241 void PrivetRegisterOperationImpl::GetClaimTokenResponse(
242 const base::DictionaryValue& value) {
243 std::string claimUrl;
244 std::string claimToken;
245 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
246 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
247 if (got_url || got_token) {
248 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
249 } else {
250 delegate_->OnPrivetRegisterError(this,
251 current_action_,
252 FAILURE_MALFORMED_RESPONSE,
254 NULL);
258 void PrivetRegisterOperationImpl::CompleteResponse(
259 const base::DictionaryValue& value) {
260 std::string id;
261 value.GetString(kPrivetKeyDeviceID, &id);
262 ongoing_ = false;
263 expected_id_ = id;
264 StartInfoOperation();
267 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
268 const base::DictionaryValue* value) {
269 // TODO(noamsml): Simplify error case and depracate HTTP error value in
270 // OnPrivetRegisterError.
271 if (!value) {
272 delegate_->OnPrivetRegisterError(this,
273 kPrivetActionNameInfo,
274 FAILURE_NETWORK,
276 NULL);
277 return;
280 if (!value->HasKey(kPrivetInfoKeyID)) {
281 if (value->HasKey(kPrivetKeyError)) {
282 delegate_->OnPrivetRegisterError(this,
283 kPrivetActionNameInfo,
284 FAILURE_JSON_ERROR,
286 value);
287 } else {
288 delegate_->OnPrivetRegisterError(this,
289 kPrivetActionNameInfo,
290 FAILURE_MALFORMED_RESPONSE,
292 NULL);
294 return;
297 std::string id;
299 if (!value->GetString(kPrivetInfoKeyID, &id) ||
300 id != expected_id_) {
301 delegate_->OnPrivetRegisterError(this,
302 kPrivetActionNameInfo,
303 FAILURE_MALFORMED_RESPONSE,
305 NULL);
306 } else {
307 delegate_->OnPrivetRegisterDone(this, id);
311 void PrivetRegisterOperationImpl::StartInfoOperation() {
312 info_operation_ = privet_client_->CreateInfoOperation(
313 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone,
314 base::Unretained(this)));
315 info_operation_->Start();
318 PrivetRegisterOperationImpl::Cancelation::Cancelation(
319 PrivetHTTPClient* privet_client,
320 const std::string& user) {
321 url_fetcher_ =
322 privet_client->CreateURLFetcher(
323 CreatePrivetRegisterURL(kPrivetActionCancel, user),
324 net::URLFetcher::POST, this);
325 url_fetcher_->DoNotRetryOnTransientError();
326 url_fetcher_->Start();
329 PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
332 void PrivetRegisterOperationImpl::Cancelation::OnError(
333 PrivetURLFetcher* fetcher,
334 PrivetURLFetcher::ErrorType error) {
337 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
338 PrivetURLFetcher* fetcher,
339 const base::DictionaryValue& value,
340 bool has_error) {
343 void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
344 // Nothing needs to be done, as base::Owned will delete this object,
345 // this callback is just here to pass ownership of the Cancelation to
346 // the message loop.
349 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
350 PrivetHTTPClient* privet_client,
351 const std::string& path,
352 const std::string& query_params,
353 const PrivetJSONOperation::ResultCallback& callback)
354 : privet_client_(privet_client),
355 path_(path),
356 query_params_(query_params),
357 callback_(callback) {
360 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
363 void PrivetJSONOperationImpl::Start() {
364 url_fetcher_ = privet_client_->CreateURLFetcher(
365 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
366 url_fetcher_->DoNotRetryOnTransientError();
367 url_fetcher_->Start();
370 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() {
371 return privet_client_;
374 void PrivetJSONOperationImpl::OnError(
375 PrivetURLFetcher* fetcher,
376 PrivetURLFetcher::ErrorType error) {
377 callback_.Run(NULL);
380 void PrivetJSONOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher,
381 const base::DictionaryValue& value,
382 bool has_error) {
383 callback_.Run(&value);
386 void PrivetJSONOperationImpl::OnNeedPrivetToken(
387 PrivetURLFetcher* fetcher,
388 const PrivetURLFetcher::TokenCallback& callback) {
389 privet_client_->RefreshPrivetToken(callback);
392 PrivetDataReadOperationImpl::PrivetDataReadOperationImpl(
393 PrivetHTTPClient* privet_client,
394 const std::string& path,
395 const std::string& query_params,
396 const PrivetDataReadOperation::ResultCallback& callback)
397 : privet_client_(privet_client),
398 path_(path),
399 query_params_(query_params),
400 callback_(callback),
401 has_range_(false),
402 save_to_file_(false) {
405 PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() {
409 void PrivetDataReadOperationImpl::Start() {
410 url_fetcher_ = privet_client_->CreateURLFetcher(
411 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
412 url_fetcher_->DoNotRetryOnTransientError();
414 if (has_range_) {
415 url_fetcher_->SetByteRange(range_start_, range_end_);
418 if (save_to_file_) {
419 url_fetcher_->SaveResponseToFile();
422 url_fetcher_->Start();
425 void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) {
426 has_range_ = true;
427 range_start_ = range_start;
428 range_end_ = range_end;
431 void PrivetDataReadOperationImpl::SaveDataToFile() {
432 save_to_file_ = false;
435 PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() {
436 return privet_client_;
439 void PrivetDataReadOperationImpl::OnError(
440 PrivetURLFetcher* fetcher,
441 PrivetURLFetcher::ErrorType error) {
442 callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath());
445 void PrivetDataReadOperationImpl::OnParsedJson(
446 PrivetURLFetcher* fetcher,
447 const base::DictionaryValue& value,
448 bool has_error) {
449 NOTREACHED();
452 void PrivetDataReadOperationImpl::OnNeedPrivetToken(
453 PrivetURLFetcher* fetcher,
454 const PrivetURLFetcher::TokenCallback& callback) {
455 privet_client_->RefreshPrivetToken(callback);
458 bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher* fetcher,
459 bool is_file,
460 const std::string& data_str,
461 const base::FilePath& file_path) {
462 ResponseType type = (is_file) ? RESPONSE_TYPE_FILE : RESPONSE_TYPE_STRING;
463 callback_.Run(type, data_str, file_path);
464 return true;
467 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
468 PrivetHTTPClient* privet_client,
469 PrivetLocalPrintOperation::Delegate* delegate)
470 : privet_client_(privet_client),
471 delegate_(delegate),
472 use_pdf_(false),
473 has_extended_workflow_(false),
474 started_(false),
475 offline_(false),
476 dpi_(printing::kDefaultPdfDpi),
477 invalid_job_retries_(0),
478 weak_factory_(this) {
481 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
484 void PrivetLocalPrintOperationImpl::Start() {
485 DCHECK(!started_);
487 // We need to get the /info response so we can know which APIs are available.
488 // TODO(noamsml): Use cached info when available.
489 info_operation_ = privet_client_->CreateInfoOperation(
490 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone,
491 base::Unretained(this)));
492 info_operation_->Start();
494 started_ = true;
497 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
498 const base::DictionaryValue* value) {
499 if (value && !value->HasKey(kPrivetKeyError)) {
500 has_extended_workflow_ = false;
501 bool has_printing = false;
503 const base::ListValue* api_list;
504 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
505 for (size_t i = 0; i < api_list->GetSize(); i++) {
506 std::string api;
507 api_list->GetString(i, &api);
508 if (api == kPrivetSubmitdocPath) {
509 has_printing = true;
510 } else if (api == kPrivetCreatejobPath) {
511 has_extended_workflow_ = true;
516 if (!has_printing) {
517 delegate_->OnPrivetPrintingError(this, -1);
518 return;
521 StartInitialRequest();
522 } else {
523 delegate_->OnPrivetPrintingError(this, -1);
527 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
528 use_pdf_ = false;
529 ContentTypesCapability content_types;
530 if (content_types.LoadFrom(capabilities_)) {
531 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) ||
532 content_types.Contains(kPrivetContentTypeAny);
535 if (use_pdf_) {
536 StartPrinting();
537 } else {
538 DpiCapability dpis;
539 if (dpis.LoadFrom(capabilities_)) {
540 dpi_ = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical);
542 StartConvertToPWG();
546 void PrivetLocalPrintOperationImpl::DoCreatejob() {
547 current_response_ = base::Bind(
548 &PrivetLocalPrintOperationImpl::OnCreatejobResponse,
549 base::Unretained(this));
551 url_fetcher_= privet_client_->CreateURLFetcher(
552 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this);
553 url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON,
554 ticket_.ToString());
556 url_fetcher_->Start();
559 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
560 current_response_ = base::Bind(
561 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
562 base::Unretained(this));
564 GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
566 url = net::AppendQueryParameter(url,
567 kPrivetURLKeyClientName,
568 kPrivetURLValueClientName);
570 if (!user_.empty()) {
571 url = net::AppendQueryParameter(url,
572 kPrivetURLKeyUserName,
573 user_);
576 base::string16 shortened_jobname;
578 gfx::ElideString(base::UTF8ToUTF16(jobname_),
579 kPrivetLocalPrintMaxJobNameLength,
580 &shortened_jobname);
582 if (!jobname_.empty()) {
583 url = net::AppendQueryParameter(
584 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname));
587 if (!jobid_.empty()) {
588 url = net::AppendQueryParameter(url,
589 kPrivetKeyJobID,
590 jobid_);
593 if (offline_) {
594 url = net::AppendQueryParameter(url,
595 kPrivetURLKeyOffline,
596 kPrivetURLValueOffline);
599 url_fetcher_= privet_client_->CreateURLFetcher(
600 url, net::URLFetcher::POST, this);
602 if (!use_pdf_) {
603 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster,
604 pwg_file_path_);
605 } else {
606 // TODO(noamsml): Move to file-based upload data?
607 std::string data_str((const char*)data_->front(), data_->size());
608 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str);
611 url_fetcher_->Start();
614 void PrivetLocalPrintOperationImpl::StartPrinting() {
615 if (has_extended_workflow_ && jobid_.empty()) {
616 DoCreatejob();
617 } else {
618 DoSubmitdoc();
622 void PrivetLocalPrintOperationImpl::FillPwgRasterSettings(
623 printing::PwgRasterSettings* transform_settings) {
624 PwgRasterConfigCapability raster_capability;
625 // If the raster capability fails to load, raster_capability will contain
626 // the default value.
627 raster_capability.LoadFrom(capabilities_);
629 DuplexTicketItem duplex_item;
630 DuplexType duplex_value = NO_DUPLEX;
632 DocumentSheetBack document_sheet_back =
633 raster_capability.value().document_sheet_back;
635 if (duplex_item.LoadFrom(ticket_)) {
636 duplex_value = duplex_item.value();
639 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
640 switch (duplex_value) {
641 case NO_DUPLEX:
642 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL;
643 break;
644 case LONG_EDGE:
645 if (document_sheet_back == ROTATED) {
646 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
647 } else if (document_sheet_back == FLIPPED) {
648 transform_settings->odd_page_transform =
649 printing::TRANSFORM_FLIP_VERTICAL;
651 break;
652 case SHORT_EDGE:
653 if (document_sheet_back == MANUAL_TUMBLE) {
654 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180;
655 } else if (document_sheet_back == FLIPPED) {
656 transform_settings->odd_page_transform =
657 printing::TRANSFORM_FLIP_HORIZONTAL;
661 transform_settings->rotate_all_pages =
662 raster_capability.value().rotate_all_pages;
664 transform_settings->reverse_page_order =
665 raster_capability.value().reverse_order_streaming;
668 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
669 printing::PwgRasterSettings transform_settings;
671 FillPwgRasterSettings(&transform_settings);
673 if (!pwg_raster_converter_)
674 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
676 double scale = dpi_;
677 scale /= printing::kPointsPerInch;
678 // Make vertical rectangle to optimize streaming to printer. Fix orientation
679 // by autorotate.
680 gfx::Rect area(std::min(page_size_.width(), page_size_.height()) * scale,
681 std::max(page_size_.width(), page_size_.height()) * scale);
682 pwg_raster_converter_->Start(
683 data_,
684 printing::PdfRenderSettings(area, dpi_, true),
685 transform_settings,
686 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted,
687 base::Unretained(this)));
690 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
691 bool has_error,
692 const base::DictionaryValue* value) {
693 std::string error;
694 // This error is only relevant in the case of extended workflow:
695 // If the print job ID is invalid, retry createjob and submitdoc,
696 // rather than simply retrying the current request.
697 if (has_error && value->GetString(kPrivetKeyError, &error)) {
698 if (has_extended_workflow_ &&
699 error == kPrivetErrorInvalidPrintJob &&
700 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) {
701 invalid_job_retries_++;
703 int timeout = kPrivetLocalPrintDefaultTimeout;
704 value->GetInteger(kPrivetKeyTimeout, &timeout);
706 double random_scaling_factor =
707 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
709 timeout = static_cast<int>(timeout * random_scaling_factor);
711 timeout = std::max(timeout, kPrivetMinimumTimeout);
713 base::MessageLoop::current()->PostDelayedTask(
714 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob,
715 weak_factory_.GetWeakPtr()),
716 base::TimeDelta::FromSeconds(timeout));
717 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) {
718 use_pdf_ = false;
719 StartConvertToPWG();
720 } else {
721 delegate_->OnPrivetPrintingError(this, 200);
724 return;
727 // If we've gotten this far, there are no errors, so we've effectively
728 // succeeded.
729 delegate_->OnPrivetPrintingDone(this);
732 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
733 bool has_error,
734 const base::DictionaryValue* value) {
735 if (has_error) {
736 delegate_->OnPrivetPrintingError(this, 200);
737 return;
740 // Try to get job ID from value. If not, jobid_ will be empty and we will use
741 // simple printing.
742 value->GetString(kPrivetKeyJobID, &jobid_);
744 DoSubmitdoc();
747 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
748 bool success,
749 const base::FilePath& pwg_file_path) {
750 if (!success) {
751 delegate_->OnPrivetPrintingError(this, -1);
752 return;
755 DCHECK(!pwg_file_path.empty());
757 pwg_file_path_ = pwg_file_path;
758 StartPrinting();
761 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
762 return privet_client_;
765 void PrivetLocalPrintOperationImpl::OnError(
766 PrivetURLFetcher* fetcher,
767 PrivetURLFetcher::ErrorType error) {
768 delegate_->OnPrivetPrintingError(this, -1);
771 void PrivetLocalPrintOperationImpl::OnParsedJson(
772 PrivetURLFetcher* fetcher,
773 const base::DictionaryValue& value,
774 bool has_error) {
775 DCHECK(!current_response_.is_null());
776 current_response_.Run(has_error, &value);
779 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
780 PrivetURLFetcher* fetcher,
781 const PrivetURLFetcher::TokenCallback& callback) {
782 privet_client_->RefreshPrivetToken(callback);
785 void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) {
786 DCHECK(!started_);
787 data_ = data;
790 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
791 DCHECK(!started_);
792 ticket_.InitFromString(ticket);
795 void PrivetLocalPrintOperationImpl::SetCapabilities(
796 const std::string& capabilities) {
797 DCHECK(!started_);
798 capabilities_.InitFromString(capabilities);
801 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
802 DCHECK(!started_);
803 user_= user;
806 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
807 DCHECK(!started_);
808 jobname_ = jobname;
811 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
812 DCHECK(!started_);
813 offline_ = offline;
816 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) {
817 DCHECK(!started_);
818 page_size_ = page_size;
821 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
822 scoped_ptr<PWGRasterConverter> pwg_raster_converter) {
823 pwg_raster_converter_ = pwg_raster_converter.Pass();
826 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
827 const std::string& name,
828 const net::HostPortPair& host_port,
829 net::URLRequestContextGetter* request_context)
830 : name_(name), request_context_(request_context), host_port_(host_port) {}
832 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
835 const std::string& PrivetHTTPClientImpl::GetName() {
836 return name_;
839 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation(
840 const PrivetJSONOperation::ResultCallback& callback) {
841 return scoped_ptr<PrivetJSONOperation>(
842 new PrivetInfoOperationImpl(this, callback));
845 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
846 const GURL& url,
847 net::URLFetcher::RequestType request_type,
848 PrivetURLFetcher::Delegate* delegate) {
849 GURL::Replacements replacements;
850 replacements.SetHostStr(host_port_.host());
851 std::string port(base::IntToString(host_port_.port())); // Keep string alive.
852 replacements.SetPortStr(port);
853 return scoped_ptr<PrivetURLFetcher>(
854 new PrivetURLFetcher(url.ReplaceComponents(replacements),
855 request_type,
856 request_context_.get(),
857 delegate));
860 void PrivetHTTPClientImpl::RefreshPrivetToken(
861 const PrivetURLFetcher::TokenCallback& callback) {
862 token_callbacks_.push_back(callback);
864 if (!info_operation_) {
865 info_operation_ = CreateInfoOperation(
866 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone,
867 base::Unretained(this)));
868 info_operation_->Start();
872 void PrivetHTTPClientImpl::OnPrivetInfoDone(
873 const base::DictionaryValue* value) {
874 info_operation_.reset();
875 std::string token;
877 // If this does not succeed, token will be empty, and an empty string
878 // is our sentinel value, since empty X-Privet-Tokens are not allowed.
879 if (value) {
880 value->GetString(kPrivetInfoKeyToken, &token);
883 TokenCallbackVector token_callbacks;
884 token_callbacks_.swap(token_callbacks);
886 for (TokenCallbackVector::iterator i = token_callbacks.begin();
887 i != token_callbacks.end(); i++) {
888 i->Run(token);
892 PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl(
893 scoped_ptr<PrivetHTTPClient> info_client)
894 : info_client_(info_client.Pass()) {
897 PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() {
900 const std::string& PrivetV1HTTPClientImpl::GetName() {
901 return info_client()->GetName();
904 scoped_ptr<PrivetJSONOperation> PrivetV1HTTPClientImpl::CreateInfoOperation(
905 const PrivetJSONOperation::ResultCallback& callback) {
906 return info_client()->CreateInfoOperation(callback);
909 scoped_ptr<PrivetRegisterOperation>
910 PrivetV1HTTPClientImpl::CreateRegisterOperation(
911 const std::string& user,
912 PrivetRegisterOperation::Delegate* delegate) {
913 return scoped_ptr<PrivetRegisterOperation>(
914 new PrivetRegisterOperationImpl(info_client(), user, delegate));
917 scoped_ptr<PrivetJSONOperation>
918 PrivetV1HTTPClientImpl::CreateCapabilitiesOperation(
919 const PrivetJSONOperation::ResultCallback& callback) {
920 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl(
921 info_client(), kPrivetCapabilitiesPath, "", callback));
924 scoped_ptr<PrivetLocalPrintOperation>
925 PrivetV1HTTPClientImpl::CreateLocalPrintOperation(
926 PrivetLocalPrintOperation::Delegate* delegate) {
927 return scoped_ptr<PrivetLocalPrintOperation>(
928 new PrivetLocalPrintOperationImpl(info_client(), delegate));
931 scoped_ptr<PrivetJSONOperation>
932 PrivetV1HTTPClientImpl::CreateStorageListOperation(
933 const std::string& path,
934 const PrivetJSONOperation::ResultCallback& callback) {
935 std::string url_param =
936 base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str());
937 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl(
938 info_client(), kPrivetStorageListPath, url_param, callback));
941 scoped_ptr<PrivetDataReadOperation>
942 PrivetV1HTTPClientImpl::CreateStorageReadOperation(
943 const std::string& path,
944 const PrivetDataReadOperation::ResultCallback& callback) {
945 std::string url_param =
946 base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str());
947 return scoped_ptr<PrivetDataReadOperation>(new PrivetDataReadOperationImpl(
948 info_client(), kPrivetStorageContentPath, url_param, callback));
951 } // namespace local_discovery