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/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"
24 #if defined(ENABLE_PRINT_PREVIEW)
25 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
26 #endif // ENABLE_PRINT_PREVIEW
28 using namespace cloud_devices::printer
;
30 namespace cloud_print
{
31 extern const char kContentTypeJSON
[];
34 namespace local_discovery
{
37 const char kUrlPlaceHolder
[] = "http://host/";
38 const char kPrivetRegisterActionArgName
[] = "action";
39 const char kPrivetRegisterUserArgName
[] = "user";
41 const int kPrivetCancelationTimeoutSeconds
= 3;
43 #if defined(ENABLE_PRINT_PREVIEW)
44 const char kPrivetURLKeyUserName
[] = "user_name";
45 const char kPrivetURLKeyClientName
[] = "client_name";
46 const char kPrivetURLKeyJobname
[] = "job_name";
47 const char kPrivetURLKeyOffline
[] = "offline";
48 const char kPrivetURLValueOffline
[] = "1";
49 const char kPrivetURLValueClientName
[] = "Chrome";
51 const char kPrivetContentTypePDF
[] = "application/pdf";
52 const char kPrivetContentTypePWGRaster
[] = "image/pwg-raster";
53 const char kPrivetContentTypeAny
[] = "*/*";
55 const char kPrivetKeyJobID
[] = "job_id";
57 const int kPrivetLocalPrintMaxRetries
= 2;
58 const int kPrivetLocalPrintDefaultTimeout
= 5;
60 const size_t kPrivetLocalPrintMaxJobNameLength
= 64;
61 #endif // ENABLE_PRINT_PREVIEW
63 GURL
CreatePrivetURL(const std::string
& path
) {
64 GURL
url(kUrlPlaceHolder
);
65 GURL::Replacements replacements
;
66 replacements
.SetPathStr(path
);
67 return url
.ReplaceComponents(replacements
);
70 GURL
CreatePrivetRegisterURL(const std::string
& action
,
71 const std::string
& user
) {
72 GURL url
= CreatePrivetURL(kPrivetRegisterPath
);
73 url
= net::AppendQueryParameter(url
, kPrivetRegisterActionArgName
, action
);
74 return net::AppendQueryParameter(url
, kPrivetRegisterUserArgName
, user
);
77 GURL
CreatePrivetParamURL(const std::string
& path
,
78 const std::string
& query_params
) {
79 GURL
url(kUrlPlaceHolder
);
80 GURL::Replacements replacements
;
81 replacements
.SetPathStr(path
);
82 if (!query_params
.empty()) {
83 replacements
.SetQueryStr(query_params
);
85 return url
.ReplaceComponents(replacements
);
90 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
91 PrivetHTTPClient
* privet_client
,
92 const PrivetJSONOperation::ResultCallback
& callback
)
93 : privet_client_(privet_client
), callback_(callback
) {
96 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
99 void PrivetInfoOperationImpl::Start() {
100 url_fetcher_
= privet_client_
->CreateURLFetcher(
101 CreatePrivetURL(kPrivetInfoPath
), net::URLFetcher::GET
, this);
103 url_fetcher_
->DoNotRetryOnTransientError();
104 url_fetcher_
->SendEmptyPrivetToken();
106 url_fetcher_
->Start();
109 PrivetHTTPClient
* PrivetInfoOperationImpl::GetHTTPClient() {
110 return privet_client_
;
113 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher
* fetcher
,
114 PrivetURLFetcher::ErrorType error
) {
118 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher
* fetcher
,
119 const base::DictionaryValue
& value
,
121 callback_
.Run(&value
);
124 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
125 PrivetHTTPClient
* privet_client
,
126 const std::string
& user
,
127 PrivetRegisterOperation::Delegate
* delegate
)
130 privet_client_(privet_client
),
134 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
137 void PrivetRegisterOperationImpl::Start() {
139 next_response_handler_
=
140 base::Bind(&PrivetRegisterOperationImpl::StartResponse
,
141 base::Unretained(this));
142 SendRequest(kPrivetActionStart
);
145 void PrivetRegisterOperationImpl::Cancel() {
146 url_fetcher_
.reset();
149 // Owned by the message loop.
150 Cancelation
* cancelation
= new Cancelation(privet_client_
, user_
);
152 base::MessageLoop::current()->PostDelayedTask(
154 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup
,
155 base::Owned(cancelation
)),
156 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds
));
162 void PrivetRegisterOperationImpl::CompleteRegistration() {
163 next_response_handler_
=
164 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse
,
165 base::Unretained(this));
166 SendRequest(kPrivetActionComplete
);
169 PrivetHTTPClient
* PrivetRegisterOperationImpl::GetHTTPClient() {
170 return privet_client_
;
173 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher
* fetcher
,
174 PrivetURLFetcher::ErrorType error
) {
176 int visible_http_code
= -1;
177 FailureReason reason
= FAILURE_NETWORK
;
179 if (error
== PrivetURLFetcher::RESPONSE_CODE_ERROR
) {
180 visible_http_code
= fetcher
->response_code();
181 reason
= FAILURE_HTTP_ERROR
;
182 } else if (error
== PrivetURLFetcher::JSON_PARSE_ERROR
) {
183 reason
= FAILURE_MALFORMED_RESPONSE
;
184 } else if (error
== PrivetURLFetcher::TOKEN_ERROR
) {
185 reason
= FAILURE_TOKEN
;
186 } else if (error
== PrivetURLFetcher::RETRY_ERROR
) {
187 reason
= FAILURE_RETRY
;
190 delegate_
->OnPrivetRegisterError(this,
197 void PrivetRegisterOperationImpl::OnParsedJson(
198 PrivetURLFetcher
* fetcher
,
199 const base::DictionaryValue
& value
,
203 value
.GetString(kPrivetKeyError
, &error
);
206 delegate_
->OnPrivetRegisterError(this,
209 fetcher
->response_code(),
214 // TODO(noamsml): Match the user&action with the user&action in the object,
215 // and fail if different.
217 next_response_handler_
.Run(value
);
220 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
221 PrivetURLFetcher
* fetcher
,
222 const PrivetURLFetcher::TokenCallback
& callback
) {
223 privet_client_
->RefreshPrivetToken(callback
);
226 void PrivetRegisterOperationImpl::SendRequest(const std::string
& action
) {
227 current_action_
= action
;
228 url_fetcher_
= privet_client_
->CreateURLFetcher(
229 CreatePrivetRegisterURL(action
, user_
), net::URLFetcher::POST
, this);
230 url_fetcher_
->Start();
233 void PrivetRegisterOperationImpl::StartResponse(
234 const base::DictionaryValue
& value
) {
235 next_response_handler_
=
236 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse
,
237 base::Unretained(this));
239 SendRequest(kPrivetActionGetClaimToken
);
242 void PrivetRegisterOperationImpl::GetClaimTokenResponse(
243 const base::DictionaryValue
& value
) {
244 std::string claimUrl
;
245 std::string claimToken
;
246 bool got_url
= value
.GetString(kPrivetKeyClaimURL
, &claimUrl
);
247 bool got_token
= value
.GetString(kPrivetKeyClaimToken
, &claimToken
);
248 if (got_url
|| got_token
) {
249 delegate_
->OnPrivetRegisterClaimToken(this, claimToken
, GURL(claimUrl
));
251 delegate_
->OnPrivetRegisterError(this,
253 FAILURE_MALFORMED_RESPONSE
,
259 void PrivetRegisterOperationImpl::CompleteResponse(
260 const base::DictionaryValue
& value
) {
262 value
.GetString(kPrivetKeyDeviceID
, &id
);
265 StartInfoOperation();
268 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
269 const base::DictionaryValue
* value
) {
270 // TODO(noamsml): Simplify error case and depracate HTTP error value in
271 // OnPrivetRegisterError.
273 delegate_
->OnPrivetRegisterError(this,
274 kPrivetActionNameInfo
,
281 if (!value
->HasKey(kPrivetInfoKeyID
)) {
282 if (value
->HasKey(kPrivetKeyError
)) {
283 delegate_
->OnPrivetRegisterError(this,
284 kPrivetActionNameInfo
,
289 delegate_
->OnPrivetRegisterError(this,
290 kPrivetActionNameInfo
,
291 FAILURE_MALFORMED_RESPONSE
,
300 if (!value
->GetString(kPrivetInfoKeyID
, &id
) ||
301 id
!= expected_id_
) {
302 delegate_
->OnPrivetRegisterError(this,
303 kPrivetActionNameInfo
,
304 FAILURE_MALFORMED_RESPONSE
,
308 delegate_
->OnPrivetRegisterDone(this, id
);
312 void PrivetRegisterOperationImpl::StartInfoOperation() {
313 info_operation_
= privet_client_
->CreateInfoOperation(
314 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone
,
315 base::Unretained(this)));
316 info_operation_
->Start();
319 PrivetRegisterOperationImpl::Cancelation::Cancelation(
320 PrivetHTTPClient
* privet_client
,
321 const std::string
& user
) {
323 privet_client
->CreateURLFetcher(
324 CreatePrivetRegisterURL(kPrivetActionCancel
, user
),
325 net::URLFetcher::POST
, this);
326 url_fetcher_
->DoNotRetryOnTransientError();
327 url_fetcher_
->Start();
330 PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
333 void PrivetRegisterOperationImpl::Cancelation::OnError(
334 PrivetURLFetcher
* fetcher
,
335 PrivetURLFetcher::ErrorType error
) {
338 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
339 PrivetURLFetcher
* fetcher
,
340 const base::DictionaryValue
& value
,
344 void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
345 // Nothing needs to be done, as base::Owned will delete this object,
346 // this callback is just here to pass ownership of the Cancelation to
350 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
351 PrivetHTTPClient
* privet_client
,
352 const std::string
& path
,
353 const std::string
& query_params
,
354 const PrivetJSONOperation::ResultCallback
& callback
)
355 : privet_client_(privet_client
),
357 query_params_(query_params
),
358 callback_(callback
) {
361 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
364 void PrivetJSONOperationImpl::Start() {
365 url_fetcher_
= privet_client_
->CreateURLFetcher(
366 CreatePrivetParamURL(path_
, query_params_
), net::URLFetcher::GET
, this);
367 url_fetcher_
->DoNotRetryOnTransientError();
368 url_fetcher_
->Start();
371 PrivetHTTPClient
* PrivetJSONOperationImpl::GetHTTPClient() {
372 return privet_client_
;
375 void PrivetJSONOperationImpl::OnError(
376 PrivetURLFetcher
* fetcher
,
377 PrivetURLFetcher::ErrorType error
) {
381 void PrivetJSONOperationImpl::OnParsedJson(PrivetURLFetcher
* fetcher
,
382 const base::DictionaryValue
& value
,
384 callback_
.Run(&value
);
387 void PrivetJSONOperationImpl::OnNeedPrivetToken(
388 PrivetURLFetcher
* fetcher
,
389 const PrivetURLFetcher::TokenCallback
& callback
) {
390 privet_client_
->RefreshPrivetToken(callback
);
393 PrivetDataReadOperationImpl::PrivetDataReadOperationImpl(
394 PrivetHTTPClient
* privet_client
,
395 const std::string
& path
,
396 const std::string
& query_params
,
397 const PrivetDataReadOperation::ResultCallback
& callback
)
398 : privet_client_(privet_client
),
400 query_params_(query_params
),
403 save_to_file_(false) {
406 PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() {
410 void PrivetDataReadOperationImpl::Start() {
411 url_fetcher_
= privet_client_
->CreateURLFetcher(
412 CreatePrivetParamURL(path_
, query_params_
), net::URLFetcher::GET
, this);
413 url_fetcher_
->DoNotRetryOnTransientError();
416 url_fetcher_
->SetByteRange(range_start_
, range_end_
);
420 url_fetcher_
->SaveResponseToFile();
423 url_fetcher_
->Start();
426 void PrivetDataReadOperationImpl::SetDataRange(int range_start
, int range_end
) {
428 range_start_
= range_start
;
429 range_end_
= range_end
;
432 void PrivetDataReadOperationImpl::SaveDataToFile() {
433 save_to_file_
= false;
436 PrivetHTTPClient
* PrivetDataReadOperationImpl::GetHTTPClient() {
437 return privet_client_
;
440 void PrivetDataReadOperationImpl::OnError(
441 PrivetURLFetcher
* fetcher
,
442 PrivetURLFetcher::ErrorType error
) {
443 callback_
.Run(RESPONSE_TYPE_ERROR
, std::string(), base::FilePath());
446 void PrivetDataReadOperationImpl::OnParsedJson(
447 PrivetURLFetcher
* fetcher
,
448 const base::DictionaryValue
& value
,
453 void PrivetDataReadOperationImpl::OnNeedPrivetToken(
454 PrivetURLFetcher
* fetcher
,
455 const PrivetURLFetcher::TokenCallback
& callback
) {
456 privet_client_
->RefreshPrivetToken(callback
);
459 bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher
* fetcher
,
461 const std::string
& data_str
,
462 const base::FilePath
& file_path
) {
463 ResponseType type
= (is_file
) ? RESPONSE_TYPE_FILE
: RESPONSE_TYPE_STRING
;
464 callback_
.Run(type
, data_str
, file_path
);
468 #if defined(ENABLE_PRINT_PREVIEW)
469 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
470 PrivetHTTPClient
* privet_client
,
471 PrivetLocalPrintOperation::Delegate
* delegate
)
472 : privet_client_(privet_client
),
475 has_extended_workflow_(false),
478 dpi_(printing::kDefaultPdfDpi
),
479 invalid_job_retries_(0),
480 weak_factory_(this) {
483 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
486 void PrivetLocalPrintOperationImpl::Start() {
489 // We need to get the /info response so we can know which APIs are available.
490 // TODO(noamsml): Use cached info when available.
491 info_operation_
= privet_client_
->CreateInfoOperation(
492 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone
,
493 base::Unretained(this)));
494 info_operation_
->Start();
499 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
500 const base::DictionaryValue
* value
) {
501 if (value
&& !value
->HasKey(kPrivetKeyError
)) {
502 has_extended_workflow_
= false;
503 bool has_printing
= false;
505 const base::ListValue
* api_list
;
506 if (value
->GetList(kPrivetInfoKeyAPIList
, &api_list
)) {
507 for (size_t i
= 0; i
< api_list
->GetSize(); i
++) {
509 api_list
->GetString(i
, &api
);
510 if (api
== kPrivetSubmitdocPath
) {
512 } else if (api
== kPrivetCreatejobPath
) {
513 has_extended_workflow_
= true;
519 delegate_
->OnPrivetPrintingError(this, -1);
523 StartInitialRequest();
525 delegate_
->OnPrivetPrintingError(this, -1);
529 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
531 ContentTypesCapability content_types
;
532 if (content_types
.LoadFrom(capabilities_
)) {
533 use_pdf_
= content_types
.Contains(kPrivetContentTypePDF
) ||
534 content_types
.Contains(kPrivetContentTypeAny
);
541 if (dpis
.LoadFrom(capabilities_
)) {
542 dpi_
= std::max(dpis
.GetDefault().horizontal
, dpis
.GetDefault().vertical
);
548 void PrivetLocalPrintOperationImpl::DoCreatejob() {
549 current_response_
= base::Bind(
550 &PrivetLocalPrintOperationImpl::OnCreatejobResponse
,
551 base::Unretained(this));
553 url_fetcher_
= privet_client_
->CreateURLFetcher(
554 CreatePrivetURL(kPrivetCreatejobPath
), net::URLFetcher::POST
, this);
555 url_fetcher_
->SetUploadData(cloud_print::kContentTypeJSON
,
558 url_fetcher_
->Start();
561 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
562 current_response_
= base::Bind(
563 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse
,
564 base::Unretained(this));
566 GURL url
= CreatePrivetURL(kPrivetSubmitdocPath
);
568 url
= net::AppendQueryParameter(url
,
569 kPrivetURLKeyClientName
,
570 kPrivetURLValueClientName
);
572 if (!user_
.empty()) {
573 url
= net::AppendQueryParameter(url
,
574 kPrivetURLKeyUserName
,
578 base::string16 shortened_jobname
;
580 gfx::ElideString(base::UTF8ToUTF16(jobname_
),
581 kPrivetLocalPrintMaxJobNameLength
,
584 if (!jobname_
.empty()) {
585 url
= net::AppendQueryParameter(
586 url
, kPrivetURLKeyJobname
, base::UTF16ToUTF8(shortened_jobname
));
589 if (!jobid_
.empty()) {
590 url
= net::AppendQueryParameter(url
,
596 url
= net::AppendQueryParameter(url
,
597 kPrivetURLKeyOffline
,
598 kPrivetURLValueOffline
);
601 url_fetcher_
= privet_client_
->CreateURLFetcher(
602 url
, net::URLFetcher::POST
, this);
605 url_fetcher_
->SetUploadFilePath(kPrivetContentTypePWGRaster
,
608 // TODO(noamsml): Move to file-based upload data?
609 std::string
data_str((const char*)data_
->front(), data_
->size());
610 url_fetcher_
->SetUploadData(kPrivetContentTypePDF
, data_str
);
613 url_fetcher_
->Start();
616 void PrivetLocalPrintOperationImpl::StartPrinting() {
617 if (has_extended_workflow_
&& jobid_
.empty()) {
624 void PrivetLocalPrintOperationImpl::FillPwgRasterSettings(
625 printing::PwgRasterSettings
* transform_settings
) {
626 PwgRasterConfigCapability raster_capability
;
627 // If the raster capability fails to load, raster_capability will contain
628 // the default value.
629 raster_capability
.LoadFrom(capabilities_
);
631 DuplexTicketItem duplex_item
;
632 DuplexType duplex_value
= NO_DUPLEX
;
634 DocumentSheetBack document_sheet_back
=
635 raster_capability
.value().document_sheet_back
;
637 if (duplex_item
.LoadFrom(ticket_
)) {
638 duplex_value
= duplex_item
.value();
641 transform_settings
->odd_page_transform
= printing::TRANSFORM_NORMAL
;
642 switch (duplex_value
) {
644 transform_settings
->odd_page_transform
= printing::TRANSFORM_NORMAL
;
647 if (document_sheet_back
== ROTATED
) {
648 transform_settings
->odd_page_transform
= printing::TRANSFORM_ROTATE_180
;
649 } else if (document_sheet_back
== FLIPPED
) {
650 transform_settings
->odd_page_transform
=
651 printing::TRANSFORM_FLIP_VERTICAL
;
655 if (document_sheet_back
== MANUAL_TUMBLE
) {
656 transform_settings
->odd_page_transform
= printing::TRANSFORM_ROTATE_180
;
657 } else if (document_sheet_back
== FLIPPED
) {
658 transform_settings
->odd_page_transform
=
659 printing::TRANSFORM_FLIP_HORIZONTAL
;
663 transform_settings
->rotate_all_pages
=
664 raster_capability
.value().rotate_all_pages
;
666 transform_settings
->reverse_page_order
=
667 raster_capability
.value().reverse_order_streaming
;
670 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
671 printing::PwgRasterSettings transform_settings
;
673 FillPwgRasterSettings(&transform_settings
);
675 if (!pwg_raster_converter_
)
676 pwg_raster_converter_
= PWGRasterConverter::CreateDefault();
679 scale
/= printing::kPointsPerInch
;
680 // Make vertical rectangle to optimize streaming to printer. Fix orientation
682 gfx::Rect
area(std::min(page_size_
.width(), page_size_
.height()) * scale
,
683 std::max(page_size_
.width(), page_size_
.height()) * scale
);
684 pwg_raster_converter_
->Start(
686 printing::PdfRenderSettings(area
, dpi_
, true),
688 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted
,
689 base::Unretained(this)));
692 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
694 const base::DictionaryValue
* value
) {
696 // This error is only relevant in the case of extended workflow:
697 // If the print job ID is invalid, retry createjob and submitdoc,
698 // rather than simply retrying the current request.
699 if (has_error
&& value
->GetString(kPrivetKeyError
, &error
)) {
700 if (has_extended_workflow_
&&
701 error
== kPrivetErrorInvalidPrintJob
&&
702 invalid_job_retries_
< kPrivetLocalPrintMaxRetries
) {
703 invalid_job_retries_
++;
705 int timeout
= kPrivetLocalPrintDefaultTimeout
;
706 value
->GetInteger(kPrivetKeyTimeout
, &timeout
);
708 double random_scaling_factor
=
709 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition
;
711 timeout
= static_cast<int>(timeout
* random_scaling_factor
);
713 timeout
= std::max(timeout
, kPrivetMinimumTimeout
);
715 base::MessageLoop::current()->PostDelayedTask(
716 FROM_HERE
, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob
,
717 weak_factory_
.GetWeakPtr()),
718 base::TimeDelta::FromSeconds(timeout
));
719 } else if (use_pdf_
&& error
== kPrivetErrorInvalidDocumentType
) {
723 delegate_
->OnPrivetPrintingError(this, 200);
729 // If we've gotten this far, there are no errors, so we've effectively
731 delegate_
->OnPrivetPrintingDone(this);
734 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
736 const base::DictionaryValue
* value
) {
738 delegate_
->OnPrivetPrintingError(this, 200);
742 // Try to get job ID from value. If not, jobid_ will be empty and we will use
744 value
->GetString(kPrivetKeyJobID
, &jobid_
);
749 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
751 const base::FilePath
& pwg_file_path
) {
753 delegate_
->OnPrivetPrintingError(this, -1);
757 DCHECK(!pwg_file_path
.empty());
759 pwg_file_path_
= pwg_file_path
;
763 PrivetHTTPClient
* PrivetLocalPrintOperationImpl::GetHTTPClient() {
764 return privet_client_
;
767 void PrivetLocalPrintOperationImpl::OnError(
768 PrivetURLFetcher
* fetcher
,
769 PrivetURLFetcher::ErrorType error
) {
770 delegate_
->OnPrivetPrintingError(this, -1);
773 void PrivetLocalPrintOperationImpl::OnParsedJson(
774 PrivetURLFetcher
* fetcher
,
775 const base::DictionaryValue
& value
,
777 DCHECK(!current_response_
.is_null());
778 current_response_
.Run(has_error
, &value
);
781 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
782 PrivetURLFetcher
* fetcher
,
783 const PrivetURLFetcher::TokenCallback
& callback
) {
784 privet_client_
->RefreshPrivetToken(callback
);
787 void PrivetLocalPrintOperationImpl::SetData(
788 const scoped_refptr
<base::RefCountedBytes
>& data
) {
793 void PrivetLocalPrintOperationImpl::SetTicket(const std::string
& ticket
) {
795 ticket_
.InitFromString(ticket
);
798 void PrivetLocalPrintOperationImpl::SetCapabilities(
799 const std::string
& capabilities
) {
801 capabilities_
.InitFromString(capabilities
);
804 void PrivetLocalPrintOperationImpl::SetUsername(const std::string
& user
) {
809 void PrivetLocalPrintOperationImpl::SetJobname(const std::string
& jobname
) {
814 void PrivetLocalPrintOperationImpl::SetOffline(bool offline
) {
819 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size
& page_size
) {
821 page_size_
= page_size
;
824 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
825 scoped_ptr
<PWGRasterConverter
> pwg_raster_converter
) {
826 pwg_raster_converter_
= pwg_raster_converter
.Pass();
828 #endif // ENABLE_PRINT_PREVIEW
830 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
831 const std::string
& name
,
832 const net::HostPortPair
& host_port
,
833 net::URLRequestContextGetter
* request_context
)
834 : name_(name
), request_context_(request_context
), host_port_(host_port
) {}
836 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
839 const std::string
& PrivetHTTPClientImpl::GetName() {
843 scoped_ptr
<PrivetJSONOperation
> PrivetHTTPClientImpl::CreateInfoOperation(
844 const PrivetJSONOperation::ResultCallback
& callback
) {
845 return scoped_ptr
<PrivetJSONOperation
>(
846 new PrivetInfoOperationImpl(this, callback
));
849 scoped_ptr
<PrivetURLFetcher
> PrivetHTTPClientImpl::CreateURLFetcher(
851 net::URLFetcher::RequestType request_type
,
852 PrivetURLFetcher::Delegate
* delegate
) {
853 GURL::Replacements replacements
;
854 replacements
.SetHostStr(host_port_
.host());
855 std::string
port(base::IntToString(host_port_
.port())); // Keep string alive.
856 replacements
.SetPortStr(port
);
857 return scoped_ptr
<PrivetURLFetcher
>(
858 new PrivetURLFetcher(url
.ReplaceComponents(replacements
),
860 request_context_
.get(),
864 void PrivetHTTPClientImpl::RefreshPrivetToken(
865 const PrivetURLFetcher::TokenCallback
& callback
) {
866 token_callbacks_
.push_back(callback
);
868 if (!info_operation_
) {
869 info_operation_
= CreateInfoOperation(
870 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone
,
871 base::Unretained(this)));
872 info_operation_
->Start();
876 void PrivetHTTPClientImpl::OnPrivetInfoDone(
877 const base::DictionaryValue
* value
) {
878 info_operation_
.reset();
881 // If this does not succeed, token will be empty, and an empty string
882 // is our sentinel value, since empty X-Privet-Tokens are not allowed.
884 value
->GetString(kPrivetInfoKeyToken
, &token
);
887 TokenCallbackVector token_callbacks
;
888 token_callbacks_
.swap(token_callbacks
);
890 for (TokenCallbackVector::iterator i
= token_callbacks
.begin();
891 i
!= token_callbacks
.end(); i
++) {
896 PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl(
897 scoped_ptr
<PrivetHTTPClient
> info_client
)
898 : info_client_(info_client
.Pass()) {
901 PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() {
904 const std::string
& PrivetV1HTTPClientImpl::GetName() {
905 return info_client()->GetName();
908 scoped_ptr
<PrivetJSONOperation
> PrivetV1HTTPClientImpl::CreateInfoOperation(
909 const PrivetJSONOperation::ResultCallback
& callback
) {
910 return info_client()->CreateInfoOperation(callback
);
913 scoped_ptr
<PrivetRegisterOperation
>
914 PrivetV1HTTPClientImpl::CreateRegisterOperation(
915 const std::string
& user
,
916 PrivetRegisterOperation::Delegate
* delegate
) {
917 return scoped_ptr
<PrivetRegisterOperation
>(
918 new PrivetRegisterOperationImpl(info_client(), user
, delegate
));
921 scoped_ptr
<PrivetJSONOperation
>
922 PrivetV1HTTPClientImpl::CreateCapabilitiesOperation(
923 const PrivetJSONOperation::ResultCallback
& callback
) {
924 return scoped_ptr
<PrivetJSONOperation
>(new PrivetJSONOperationImpl(
925 info_client(), kPrivetCapabilitiesPath
, "", callback
));
928 scoped_ptr
<PrivetLocalPrintOperation
>
929 PrivetV1HTTPClientImpl::CreateLocalPrintOperation(
930 PrivetLocalPrintOperation::Delegate
* delegate
) {
931 #if defined(ENABLE_PRINT_PREVIEW)
932 return scoped_ptr
<PrivetLocalPrintOperation
>(
933 new PrivetLocalPrintOperationImpl(info_client(), delegate
));
935 return scoped_ptr
<PrivetLocalPrintOperation
>();
936 #endif // ENABLE_PRINT_PREVIEW
939 } // namespace local_discovery