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/utf_string_conversions.h"
15 #include "chrome/browser/local_discovery/privet_constants.h"
16 #include "net/base/url_util.h"
19 #if defined(ENABLE_PRINT_PREVIEW)
20 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
21 #include "components/cloud_devices/common/printer_description.h"
22 #include "printing/pdf_render_settings.h"
23 #include "printing/pwg_raster_settings.h"
24 #include "ui/gfx/text_elider.h"
25 #endif // ENABLE_PRINT_PREVIEW
27 namespace cloud_print
{
28 extern const char kContentTypeJSON
[];
31 namespace local_discovery
{
34 const char kUrlPlaceHolder
[] = "http://host/";
35 const char kPrivetRegisterActionArgName
[] = "action";
36 const char kPrivetRegisterUserArgName
[] = "user";
38 const int kPrivetCancelationTimeoutSeconds
= 3;
40 #if defined(ENABLE_PRINT_PREVIEW)
41 const char kPrivetURLKeyUserName
[] = "user_name";
42 const char kPrivetURLKeyClientName
[] = "client_name";
43 const char kPrivetURLKeyJobname
[] = "job_name";
44 const char kPrivetURLKeyOffline
[] = "offline";
45 const char kPrivetURLValueOffline
[] = "1";
46 const char kPrivetURLValueClientName
[] = "Chrome";
48 const char kPrivetContentTypePDF
[] = "application/pdf";
49 const char kPrivetContentTypePWGRaster
[] = "image/pwg-raster";
50 const char kPrivetContentTypeAny
[] = "*/*";
52 const char kPrivetKeyJobID
[] = "job_id";
54 const int kPrivetLocalPrintMaxRetries
= 2;
55 const int kPrivetLocalPrintDefaultTimeout
= 5;
57 const size_t kPrivetLocalPrintMaxJobNameLength
= 64;
58 #endif // ENABLE_PRINT_PREVIEW
60 GURL
CreatePrivetURL(const std::string
& path
) {
61 GURL
url(kUrlPlaceHolder
);
62 GURL::Replacements replacements
;
63 replacements
.SetPathStr(path
);
64 return url
.ReplaceComponents(replacements
);
67 GURL
CreatePrivetRegisterURL(const std::string
& action
,
68 const std::string
& user
) {
69 GURL url
= CreatePrivetURL(kPrivetRegisterPath
);
70 url
= net::AppendQueryParameter(url
, kPrivetRegisterActionArgName
, action
);
71 return net::AppendQueryParameter(url
, kPrivetRegisterUserArgName
, user
);
74 GURL
CreatePrivetParamURL(const std::string
& path
,
75 const std::string
& query_params
) {
76 GURL
url(kUrlPlaceHolder
);
77 GURL::Replacements replacements
;
78 replacements
.SetPathStr(path
);
79 if (!query_params
.empty()) {
80 replacements
.SetQueryStr(query_params
);
82 return url
.ReplaceComponents(replacements
);
87 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
88 PrivetHTTPClient
* privet_client
,
89 const PrivetJSONOperation::ResultCallback
& callback
)
90 : privet_client_(privet_client
), callback_(callback
) {
93 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
96 void PrivetInfoOperationImpl::Start() {
97 url_fetcher_
= privet_client_
->CreateURLFetcher(
98 CreatePrivetURL(kPrivetInfoPath
), net::URLFetcher::GET
, this);
100 url_fetcher_
->DoNotRetryOnTransientError();
101 url_fetcher_
->SendEmptyPrivetToken();
103 url_fetcher_
->Start();
106 PrivetHTTPClient
* PrivetInfoOperationImpl::GetHTTPClient() {
107 return privet_client_
;
110 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher
* fetcher
,
111 PrivetURLFetcher::ErrorType error
) {
115 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher
* fetcher
,
116 const base::DictionaryValue
& value
,
118 callback_
.Run(&value
);
121 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
122 PrivetHTTPClient
* privet_client
,
123 const std::string
& user
,
124 PrivetRegisterOperation::Delegate
* delegate
)
127 privet_client_(privet_client
),
131 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
134 void PrivetRegisterOperationImpl::Start() {
136 next_response_handler_
=
137 base::Bind(&PrivetRegisterOperationImpl::StartResponse
,
138 base::Unretained(this));
139 SendRequest(kPrivetActionStart
);
142 void PrivetRegisterOperationImpl::Cancel() {
143 url_fetcher_
.reset();
146 // Owned by the message loop.
147 Cancelation
* cancelation
= new Cancelation(privet_client_
, user_
);
149 base::MessageLoop::current()->PostDelayedTask(
151 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup
,
152 base::Owned(cancelation
)),
153 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds
));
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
) {
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,
194 void PrivetRegisterOperationImpl::OnParsedJson(
195 PrivetURLFetcher
* fetcher
,
196 const base::DictionaryValue
& value
,
200 value
.GetString(kPrivetKeyError
, &error
);
203 delegate_
->OnPrivetRegisterError(this,
206 fetcher
->response_code(),
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
));
248 delegate_
->OnPrivetRegisterError(this,
250 FAILURE_MALFORMED_RESPONSE
,
256 void PrivetRegisterOperationImpl::CompleteResponse(
257 const base::DictionaryValue
& value
) {
259 value
.GetString(kPrivetKeyDeviceID
, &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.
270 delegate_
->OnPrivetRegisterError(this,
271 kPrivetActionNameInfo
,
278 if (!value
->HasKey(kPrivetInfoKeyID
)) {
279 if (value
->HasKey(kPrivetKeyError
)) {
280 delegate_
->OnPrivetRegisterError(this,
281 kPrivetActionNameInfo
,
286 delegate_
->OnPrivetRegisterError(this,
287 kPrivetActionNameInfo
,
288 FAILURE_MALFORMED_RESPONSE
,
297 if (!value
->GetString(kPrivetInfoKeyID
, &id
) ||
298 id
!= expected_id_
) {
299 delegate_
->OnPrivetRegisterError(this,
300 kPrivetActionNameInfo
,
301 FAILURE_MALFORMED_RESPONSE
,
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 PrivetHTTPClient
* privet_client
,
318 const std::string
& user
) {
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
,
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
347 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
348 PrivetHTTPClient
* privet_client
,
349 const std::string
& path
,
350 const std::string
& query_params
,
351 const PrivetJSONOperation::ResultCallback
& callback
)
352 : privet_client_(privet_client
),
354 query_params_(query_params
),
355 callback_(callback
) {
358 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
361 void PrivetJSONOperationImpl::Start() {
362 url_fetcher_
= privet_client_
->CreateURLFetcher(
363 CreatePrivetParamURL(path_
, query_params_
), net::URLFetcher::GET
, this);
364 url_fetcher_
->DoNotRetryOnTransientError();
365 url_fetcher_
->Start();
368 PrivetHTTPClient
* PrivetJSONOperationImpl::GetHTTPClient() {
369 return privet_client_
;
372 void PrivetJSONOperationImpl::OnError(
373 PrivetURLFetcher
* fetcher
,
374 PrivetURLFetcher::ErrorType error
) {
378 void PrivetJSONOperationImpl::OnParsedJson(PrivetURLFetcher
* fetcher
,
379 const base::DictionaryValue
& value
,
381 callback_
.Run(&value
);
384 void PrivetJSONOperationImpl::OnNeedPrivetToken(
385 PrivetURLFetcher
* fetcher
,
386 const PrivetURLFetcher::TokenCallback
& callback
) {
387 privet_client_
->RefreshPrivetToken(callback
);
390 #if defined(ENABLE_PRINT_PREVIEW)
391 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
392 PrivetHTTPClient
* privet_client
,
393 PrivetLocalPrintOperation::Delegate
* delegate
)
394 : privet_client_(privet_client
),
397 has_extended_workflow_(false),
400 invalid_job_retries_(0),
401 weak_factory_(this) {
404 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
407 void PrivetLocalPrintOperationImpl::Start() {
410 // We need to get the /info response so we can know which APIs are available.
411 // TODO(noamsml): Use cached info when available.
412 info_operation_
= privet_client_
->CreateInfoOperation(
413 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone
,
414 base::Unretained(this)));
415 info_operation_
->Start();
420 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
421 const base::DictionaryValue
* value
) {
422 if (value
&& !value
->HasKey(kPrivetKeyError
)) {
423 has_extended_workflow_
= false;
424 bool has_printing
= false;
426 const base::ListValue
* api_list
;
427 if (value
->GetList(kPrivetInfoKeyAPIList
, &api_list
)) {
428 for (size_t i
= 0; i
< api_list
->GetSize(); i
++) {
430 api_list
->GetString(i
, &api
);
431 if (api
== kPrivetSubmitdocPath
) {
433 } else if (api
== kPrivetCreatejobPath
) {
434 has_extended_workflow_
= true;
440 delegate_
->OnPrivetPrintingError(this, -1);
444 StartInitialRequest();
446 delegate_
->OnPrivetPrintingError(this, -1);
450 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
452 cloud_devices::printer::ContentTypesCapability content_types
;
453 if (content_types
.LoadFrom(capabilities_
)) {
454 use_pdf_
= content_types
.Contains(kPrivetContentTypePDF
) ||
455 content_types
.Contains(kPrivetContentTypeAny
);
465 void PrivetLocalPrintOperationImpl::DoCreatejob() {
466 current_response_
= base::Bind(
467 &PrivetLocalPrintOperationImpl::OnCreatejobResponse
,
468 base::Unretained(this));
470 url_fetcher_
= privet_client_
->CreateURLFetcher(
471 CreatePrivetURL(kPrivetCreatejobPath
), net::URLFetcher::POST
, this);
472 url_fetcher_
->SetUploadData(cloud_print::kContentTypeJSON
,
475 url_fetcher_
->Start();
478 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
479 current_response_
= base::Bind(
480 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse
,
481 base::Unretained(this));
483 GURL url
= CreatePrivetURL(kPrivetSubmitdocPath
);
485 url
= net::AppendQueryParameter(url
,
486 kPrivetURLKeyClientName
,
487 kPrivetURLValueClientName
);
489 if (!user_
.empty()) {
490 url
= net::AppendQueryParameter(url
,
491 kPrivetURLKeyUserName
,
495 base::string16 shortened_jobname
;
497 gfx::ElideString(base::UTF8ToUTF16(jobname_
),
498 kPrivetLocalPrintMaxJobNameLength
,
501 if (!jobname_
.empty()) {
502 url
= net::AppendQueryParameter(
503 url
, kPrivetURLKeyJobname
, base::UTF16ToUTF8(shortened_jobname
));
506 if (!jobid_
.empty()) {
507 url
= net::AppendQueryParameter(url
,
513 url
= net::AppendQueryParameter(url
,
514 kPrivetURLKeyOffline
,
515 kPrivetURLValueOffline
);
519 privet_client_
->CreateURLFetcher(url
, net::URLFetcher::POST
, this);
522 url_fetcher_
->SetUploadFilePath(kPrivetContentTypePWGRaster
,
525 // TODO(noamsml): Move to file-based upload data?
526 std::string
data_str((const char*)data_
->front(), data_
->size());
527 url_fetcher_
->SetUploadData(kPrivetContentTypePDF
, data_str
);
530 url_fetcher_
->Start();
533 void PrivetLocalPrintOperationImpl::StartPrinting() {
534 if (has_extended_workflow_
&& jobid_
.empty()) {
541 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
542 if (!pwg_raster_converter_
)
543 pwg_raster_converter_
= PWGRasterConverter::CreateDefault();
545 pwg_raster_converter_
->Start(
547 PWGRasterConverter::GetConversionSettings(capabilities_
, page_size_
),
548 PWGRasterConverter::GetBitmapSettings(capabilities_
, ticket_
),
549 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted
,
550 base::Unretained(this)));
553 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
555 const base::DictionaryValue
* value
) {
557 // This error is only relevant in the case of extended workflow:
558 // If the print job ID is invalid, retry createjob and submitdoc,
559 // rather than simply retrying the current request.
560 if (has_error
&& value
->GetString(kPrivetKeyError
, &error
)) {
561 if (has_extended_workflow_
&&
562 error
== kPrivetErrorInvalidPrintJob
&&
563 invalid_job_retries_
< kPrivetLocalPrintMaxRetries
) {
564 invalid_job_retries_
++;
566 int timeout
= kPrivetLocalPrintDefaultTimeout
;
567 value
->GetInteger(kPrivetKeyTimeout
, &timeout
);
569 double random_scaling_factor
=
570 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition
;
572 timeout
= static_cast<int>(timeout
* random_scaling_factor
);
574 timeout
= std::max(timeout
, kPrivetMinimumTimeout
);
576 base::MessageLoop::current()->PostDelayedTask(
577 FROM_HERE
, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob
,
578 weak_factory_
.GetWeakPtr()),
579 base::TimeDelta::FromSeconds(timeout
));
580 } else if (use_pdf_
&& error
== kPrivetErrorInvalidDocumentType
) {
584 delegate_
->OnPrivetPrintingError(this, 200);
590 // If we've gotten this far, there are no errors, so we've effectively
592 delegate_
->OnPrivetPrintingDone(this);
595 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
597 const base::DictionaryValue
* value
) {
599 delegate_
->OnPrivetPrintingError(this, 200);
603 // Try to get job ID from value. If not, jobid_ will be empty and we will use
605 value
->GetString(kPrivetKeyJobID
, &jobid_
);
610 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
612 const base::FilePath
& pwg_file_path
) {
614 delegate_
->OnPrivetPrintingError(this, -1);
618 DCHECK(!pwg_file_path
.empty());
620 pwg_file_path_
= pwg_file_path
;
624 PrivetHTTPClient
* PrivetLocalPrintOperationImpl::GetHTTPClient() {
625 return privet_client_
;
628 void PrivetLocalPrintOperationImpl::OnError(
629 PrivetURLFetcher
* fetcher
,
630 PrivetURLFetcher::ErrorType error
) {
631 delegate_
->OnPrivetPrintingError(this, -1);
634 void PrivetLocalPrintOperationImpl::OnParsedJson(
635 PrivetURLFetcher
* fetcher
,
636 const base::DictionaryValue
& value
,
638 DCHECK(!current_response_
.is_null());
639 current_response_
.Run(has_error
, &value
);
642 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
643 PrivetURLFetcher
* fetcher
,
644 const PrivetURLFetcher::TokenCallback
& callback
) {
645 privet_client_
->RefreshPrivetToken(callback
);
648 void PrivetLocalPrintOperationImpl::SetData(
649 const scoped_refptr
<base::RefCountedBytes
>& data
) {
654 void PrivetLocalPrintOperationImpl::SetTicket(const std::string
& ticket
) {
656 ticket_
.InitFromString(ticket
);
659 void PrivetLocalPrintOperationImpl::SetCapabilities(
660 const std::string
& capabilities
) {
662 capabilities_
.InitFromString(capabilities
);
665 void PrivetLocalPrintOperationImpl::SetUsername(const std::string
& user
) {
670 void PrivetLocalPrintOperationImpl::SetJobname(const std::string
& jobname
) {
675 void PrivetLocalPrintOperationImpl::SetOffline(bool offline
) {
680 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size
& page_size
) {
682 page_size_
= page_size
;
685 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
686 scoped_ptr
<PWGRasterConverter
> pwg_raster_converter
) {
687 pwg_raster_converter_
= pwg_raster_converter
.Pass();
689 #endif // ENABLE_PRINT_PREVIEW
691 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
692 const std::string
& name
,
693 const net::HostPortPair
& host_port
,
694 net::URLRequestContextGetter
* request_context
)
695 : name_(name
), request_context_(request_context
), host_port_(host_port
) {}
697 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
700 const std::string
& PrivetHTTPClientImpl::GetName() {
704 scoped_ptr
<PrivetJSONOperation
> PrivetHTTPClientImpl::CreateInfoOperation(
705 const PrivetJSONOperation::ResultCallback
& callback
) {
706 return scoped_ptr
<PrivetJSONOperation
>(
707 new PrivetInfoOperationImpl(this, callback
));
710 scoped_ptr
<PrivetURLFetcher
> PrivetHTTPClientImpl::CreateURLFetcher(
712 net::URLFetcher::RequestType request_type
,
713 PrivetURLFetcher::Delegate
* delegate
) {
714 GURL::Replacements replacements
;
715 replacements
.SetHostStr(host_port_
.host());
716 std::string
port(base::IntToString(host_port_
.port())); // Keep string alive.
717 replacements
.SetPortStr(port
);
718 return scoped_ptr
<PrivetURLFetcher
>(
719 new PrivetURLFetcher(url
.ReplaceComponents(replacements
),
721 request_context_
.get(),
725 void PrivetHTTPClientImpl::RefreshPrivetToken(
726 const PrivetURLFetcher::TokenCallback
& callback
) {
727 token_callbacks_
.push_back(callback
);
729 if (!info_operation_
) {
730 info_operation_
= CreateInfoOperation(
731 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone
,
732 base::Unretained(this)));
733 info_operation_
->Start();
737 void PrivetHTTPClientImpl::OnPrivetInfoDone(
738 const base::DictionaryValue
* value
) {
739 info_operation_
.reset();
742 // If this does not succeed, token will be empty, and an empty string
743 // is our sentinel value, since empty X-Privet-Tokens are not allowed.
745 value
->GetString(kPrivetInfoKeyToken
, &token
);
748 TokenCallbackVector token_callbacks
;
749 token_callbacks_
.swap(token_callbacks
);
751 for (TokenCallbackVector::iterator i
= token_callbacks
.begin();
752 i
!= token_callbacks
.end(); i
++) {
757 PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl(
758 scoped_ptr
<PrivetHTTPClient
> info_client
)
759 : info_client_(info_client
.Pass()) {
762 PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() {
765 const std::string
& PrivetV1HTTPClientImpl::GetName() {
766 return info_client()->GetName();
769 scoped_ptr
<PrivetJSONOperation
> PrivetV1HTTPClientImpl::CreateInfoOperation(
770 const PrivetJSONOperation::ResultCallback
& callback
) {
771 return info_client()->CreateInfoOperation(callback
);
774 scoped_ptr
<PrivetRegisterOperation
>
775 PrivetV1HTTPClientImpl::CreateRegisterOperation(
776 const std::string
& user
,
777 PrivetRegisterOperation::Delegate
* delegate
) {
778 return scoped_ptr
<PrivetRegisterOperation
>(
779 new PrivetRegisterOperationImpl(info_client(), user
, delegate
));
782 scoped_ptr
<PrivetJSONOperation
>
783 PrivetV1HTTPClientImpl::CreateCapabilitiesOperation(
784 const PrivetJSONOperation::ResultCallback
& callback
) {
785 return scoped_ptr
<PrivetJSONOperation
>(new PrivetJSONOperationImpl(
786 info_client(), kPrivetCapabilitiesPath
, "", callback
));
789 scoped_ptr
<PrivetLocalPrintOperation
>
790 PrivetV1HTTPClientImpl::CreateLocalPrintOperation(
791 PrivetLocalPrintOperation::Delegate
* delegate
) {
792 #if defined(ENABLE_PRINT_PREVIEW)
793 return scoped_ptr
<PrivetLocalPrintOperation
>(
794 new PrivetLocalPrintOperationImpl(info_client(), delegate
));
796 return scoped_ptr
<PrivetLocalPrintOperation
>();
797 #endif // ENABLE_PRINT_PREVIEW
800 } // namespace local_discovery