Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / local_discovery / privet_http_impl.cc
blobdc3b4eff03d7e14d2d256f3af2bbb9d5dc5bd913
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/location.h"
12 #include "base/rand_util.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "chrome/browser/local_discovery/privet_constants.h"
18 #include "chrome/common/cloud_print/cloud_print_constants.h"
19 #include "net/base/url_util.h"
20 #include "url/gurl.h"
22 #if defined(ENABLE_PRINT_PREVIEW)
23 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
24 #include "components/cloud_devices/common/printer_description.h"
25 #include "printing/pdf_render_settings.h"
26 #include "printing/pwg_raster_settings.h"
27 #include "ui/gfx/text_elider.h"
28 #endif // ENABLE_PRINT_PREVIEW
30 namespace local_discovery {
32 namespace {
33 const char kUrlPlaceHolder[] = "http://host/";
34 const char kPrivetRegisterActionArgName[] = "action";
35 const char kPrivetRegisterUserArgName[] = "user";
37 const int kPrivetCancelationTimeoutSeconds = 3;
39 #if defined(ENABLE_PRINT_PREVIEW)
40 const char kPrivetURLKeyUserName[] = "user_name";
41 const char kPrivetURLKeyClientName[] = "client_name";
42 const char kPrivetURLKeyJobname[] = "job_name";
43 const char kPrivetURLKeyOffline[] = "offline";
44 const char kPrivetURLValueOffline[] = "1";
45 const char kPrivetURLValueClientName[] = "Chrome";
47 const char kPrivetContentTypePDF[] = "application/pdf";
48 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
49 const char kPrivetContentTypeAny[] = "*/*";
51 const char kPrivetKeyJobID[] = "job_id";
53 const int kPrivetLocalPrintMaxRetries = 2;
54 const int kPrivetLocalPrintDefaultTimeout = 5;
56 const size_t kPrivetLocalPrintMaxJobNameLength = 64;
57 #endif // ENABLE_PRINT_PREVIEW
59 GURL CreatePrivetURL(const std::string& path) {
60 GURL url(kUrlPlaceHolder);
61 GURL::Replacements replacements;
62 replacements.SetPathStr(path);
63 return url.ReplaceComponents(replacements);
66 GURL CreatePrivetRegisterURL(const std::string& action,
67 const std::string& user) {
68 GURL url = CreatePrivetURL(kPrivetRegisterPath);
69 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action);
70 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user);
73 GURL CreatePrivetParamURL(const std::string& path,
74 const std::string& query_params) {
75 GURL url(kUrlPlaceHolder);
76 GURL::Replacements replacements;
77 replacements.SetPathStr(path);
78 if (!query_params.empty()) {
79 replacements.SetQueryStr(query_params);
81 return url.ReplaceComponents(replacements);
84 } // namespace
86 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
87 PrivetHTTPClient* privet_client,
88 const PrivetJSONOperation::ResultCallback& callback)
89 : privet_client_(privet_client), callback_(callback) {
92 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
95 void PrivetInfoOperationImpl::Start() {
96 url_fetcher_ = privet_client_->CreateURLFetcher(
97 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this);
99 url_fetcher_->DoNotRetryOnTransientError();
100 url_fetcher_->SendEmptyPrivetToken();
102 url_fetcher_->Start();
105 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() {
106 return privet_client_;
109 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
110 PrivetURLFetcher::ErrorType error) {
111 callback_.Run(NULL);
114 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher,
115 const base::DictionaryValue& value,
116 bool has_error) {
117 callback_.Run(&value);
120 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
121 PrivetHTTPClient* privet_client,
122 const std::string& user,
123 PrivetRegisterOperation::Delegate* delegate)
124 : user_(user),
125 delegate_(delegate),
126 privet_client_(privet_client),
127 ongoing_(false) {
130 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
133 void PrivetRegisterOperationImpl::Start() {
134 ongoing_ = true;
135 next_response_handler_ =
136 base::Bind(&PrivetRegisterOperationImpl::StartResponse,
137 base::Unretained(this));
138 SendRequest(kPrivetActionStart);
141 void PrivetRegisterOperationImpl::Cancel() {
142 url_fetcher_.reset();
144 if (ongoing_) {
145 // Owned by the message loop.
146 Cancelation* cancelation = new Cancelation(privet_client_, user_);
148 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
149 FROM_HERE,
150 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup,
151 base::Owned(cancelation)),
152 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds));
154 ongoing_ = false;
158 void PrivetRegisterOperationImpl::CompleteRegistration() {
159 next_response_handler_ =
160 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse,
161 base::Unretained(this));
162 SendRequest(kPrivetActionComplete);
165 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
166 return privet_client_;
169 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
170 PrivetURLFetcher::ErrorType error) {
171 ongoing_ = false;
172 int visible_http_code = -1;
173 FailureReason reason = FAILURE_NETWORK;
175 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
176 visible_http_code = fetcher->response_code();
177 reason = FAILURE_HTTP_ERROR;
178 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
179 reason = FAILURE_MALFORMED_RESPONSE;
180 } else if (error == PrivetURLFetcher::TOKEN_ERROR) {
181 reason = FAILURE_TOKEN;
182 } else if (error == PrivetURLFetcher::RETRY_ERROR) {
183 reason = FAILURE_RETRY;
186 delegate_->OnPrivetRegisterError(this,
187 current_action_,
188 reason,
189 visible_http_code,
190 NULL);
193 void PrivetRegisterOperationImpl::OnParsedJson(
194 PrivetURLFetcher* fetcher,
195 const base::DictionaryValue& value,
196 bool has_error) {
197 if (has_error) {
198 std::string error;
199 value.GetString(kPrivetKeyError, &error);
201 ongoing_ = false;
202 delegate_->OnPrivetRegisterError(this,
203 current_action_,
204 FAILURE_JSON_ERROR,
205 fetcher->response_code(),
206 &value);
207 return;
210 // TODO(noamsml): Match the user&action with the user&action in the object,
211 // and fail if different.
213 next_response_handler_.Run(value);
216 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
217 PrivetURLFetcher* fetcher,
218 const PrivetURLFetcher::TokenCallback& callback) {
219 privet_client_->RefreshPrivetToken(callback);
222 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
223 current_action_ = action;
224 url_fetcher_ = privet_client_->CreateURLFetcher(
225 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
226 url_fetcher_->Start();
229 void PrivetRegisterOperationImpl::StartResponse(
230 const base::DictionaryValue& value) {
231 next_response_handler_ =
232 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse,
233 base::Unretained(this));
235 SendRequest(kPrivetActionGetClaimToken);
238 void PrivetRegisterOperationImpl::GetClaimTokenResponse(
239 const base::DictionaryValue& value) {
240 std::string claimUrl;
241 std::string claimToken;
242 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
243 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
244 if (got_url || got_token) {
245 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
246 } else {
247 delegate_->OnPrivetRegisterError(this,
248 current_action_,
249 FAILURE_MALFORMED_RESPONSE,
251 NULL);
255 void PrivetRegisterOperationImpl::CompleteResponse(
256 const base::DictionaryValue& value) {
257 std::string id;
258 value.GetString(kPrivetKeyDeviceID, &id);
259 ongoing_ = false;
260 expected_id_ = id;
261 StartInfoOperation();
264 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
265 const base::DictionaryValue* value) {
266 // TODO(noamsml): Simplify error case and depracate HTTP error value in
267 // OnPrivetRegisterError.
268 if (!value) {
269 delegate_->OnPrivetRegisterError(this,
270 kPrivetActionNameInfo,
271 FAILURE_NETWORK,
273 NULL);
274 return;
277 if (!value->HasKey(kPrivetInfoKeyID)) {
278 if (value->HasKey(kPrivetKeyError)) {
279 delegate_->OnPrivetRegisterError(this,
280 kPrivetActionNameInfo,
281 FAILURE_JSON_ERROR,
283 value);
284 } else {
285 delegate_->OnPrivetRegisterError(this,
286 kPrivetActionNameInfo,
287 FAILURE_MALFORMED_RESPONSE,
289 NULL);
291 return;
294 std::string id;
296 if (!value->GetString(kPrivetInfoKeyID, &id) ||
297 id != expected_id_) {
298 delegate_->OnPrivetRegisterError(this,
299 kPrivetActionNameInfo,
300 FAILURE_MALFORMED_RESPONSE,
302 NULL);
303 } else {
304 delegate_->OnPrivetRegisterDone(this, id);
308 void PrivetRegisterOperationImpl::StartInfoOperation() {
309 info_operation_ = privet_client_->CreateInfoOperation(
310 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone,
311 base::Unretained(this)));
312 info_operation_->Start();
315 PrivetRegisterOperationImpl::Cancelation::Cancelation(
316 PrivetHTTPClient* privet_client,
317 const std::string& user) {
318 url_fetcher_ =
319 privet_client->CreateURLFetcher(
320 CreatePrivetRegisterURL(kPrivetActionCancel, user),
321 net::URLFetcher::POST, this);
322 url_fetcher_->DoNotRetryOnTransientError();
323 url_fetcher_->Start();
326 PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
329 void PrivetRegisterOperationImpl::Cancelation::OnError(
330 PrivetURLFetcher* fetcher,
331 PrivetURLFetcher::ErrorType error) {
334 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
335 PrivetURLFetcher* fetcher,
336 const base::DictionaryValue& value,
337 bool has_error) {
340 void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
341 // Nothing needs to be done, as base::Owned will delete this object,
342 // this callback is just here to pass ownership of the Cancelation to
343 // the message loop.
346 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
347 PrivetHTTPClient* privet_client,
348 const std::string& path,
349 const std::string& query_params,
350 const PrivetJSONOperation::ResultCallback& callback)
351 : privet_client_(privet_client),
352 path_(path),
353 query_params_(query_params),
354 callback_(callback) {
357 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
360 void PrivetJSONOperationImpl::Start() {
361 url_fetcher_ = privet_client_->CreateURLFetcher(
362 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
363 url_fetcher_->DoNotRetryOnTransientError();
364 url_fetcher_->Start();
367 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() {
368 return privet_client_;
371 void PrivetJSONOperationImpl::OnError(
372 PrivetURLFetcher* fetcher,
373 PrivetURLFetcher::ErrorType error) {
374 callback_.Run(NULL);
377 void PrivetJSONOperationImpl::OnParsedJson(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 #if defined(ENABLE_PRINT_PREVIEW)
390 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
391 PrivetHTTPClient* privet_client,
392 PrivetLocalPrintOperation::Delegate* delegate)
393 : privet_client_(privet_client),
394 delegate_(delegate),
395 use_pdf_(false),
396 has_extended_workflow_(false),
397 started_(false),
398 offline_(false),
399 invalid_job_retries_(0),
400 weak_factory_(this) {
403 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
406 void PrivetLocalPrintOperationImpl::Start() {
407 DCHECK(!started_);
409 // We need to get the /info response so we can know which APIs are available.
410 // TODO(noamsml): Use cached info when available.
411 info_operation_ = privet_client_->CreateInfoOperation(
412 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone,
413 base::Unretained(this)));
414 info_operation_->Start();
416 started_ = true;
419 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
420 const base::DictionaryValue* value) {
421 if (value && !value->HasKey(kPrivetKeyError)) {
422 has_extended_workflow_ = false;
423 bool has_printing = false;
425 const base::ListValue* api_list;
426 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
427 for (size_t i = 0; i < api_list->GetSize(); i++) {
428 std::string api;
429 api_list->GetString(i, &api);
430 if (api == kPrivetSubmitdocPath) {
431 has_printing = true;
432 } else if (api == kPrivetCreatejobPath) {
433 has_extended_workflow_ = true;
438 if (!has_printing) {
439 delegate_->OnPrivetPrintingError(this, -1);
440 return;
443 StartInitialRequest();
444 } else {
445 delegate_->OnPrivetPrintingError(this, -1);
449 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
450 use_pdf_ = false;
451 cloud_devices::printer::ContentTypesCapability content_types;
452 if (content_types.LoadFrom(capabilities_)) {
453 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) ||
454 content_types.Contains(kPrivetContentTypeAny);
457 if (use_pdf_) {
458 StartPrinting();
459 } else {
460 StartConvertToPWG();
464 void PrivetLocalPrintOperationImpl::DoCreatejob() {
465 current_response_ = base::Bind(
466 &PrivetLocalPrintOperationImpl::OnCreatejobResponse,
467 base::Unretained(this));
469 url_fetcher_ = privet_client_->CreateURLFetcher(
470 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this);
471 url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON,
472 ticket_.ToString());
474 url_fetcher_->Start();
477 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
478 current_response_ = base::Bind(
479 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
480 base::Unretained(this));
482 GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
484 url = net::AppendQueryParameter(url,
485 kPrivetURLKeyClientName,
486 kPrivetURLValueClientName);
488 if (!user_.empty()) {
489 url = net::AppendQueryParameter(url,
490 kPrivetURLKeyUserName,
491 user_);
494 base::string16 shortened_jobname;
496 gfx::ElideString(base::UTF8ToUTF16(jobname_),
497 kPrivetLocalPrintMaxJobNameLength,
498 &shortened_jobname);
500 if (!jobname_.empty()) {
501 url = net::AppendQueryParameter(
502 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname));
505 if (!jobid_.empty()) {
506 url = net::AppendQueryParameter(url,
507 kPrivetKeyJobID,
508 jobid_);
511 if (offline_) {
512 url = net::AppendQueryParameter(url,
513 kPrivetURLKeyOffline,
514 kPrivetURLValueOffline);
517 url_fetcher_ =
518 privet_client_->CreateURLFetcher(url, net::URLFetcher::POST, this);
520 if (!use_pdf_) {
521 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster,
522 pwg_file_path_);
523 } else {
524 // TODO(noamsml): Move to file-based upload data?
525 std::string data_str((const char*)data_->front(), data_->size());
526 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str);
529 url_fetcher_->Start();
532 void PrivetLocalPrintOperationImpl::StartPrinting() {
533 if (has_extended_workflow_ && jobid_.empty()) {
534 DoCreatejob();
535 } else {
536 DoSubmitdoc();
540 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
541 if (!pwg_raster_converter_)
542 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
544 pwg_raster_converter_->Start(
545 data_.get(),
546 PWGRasterConverter::GetConversionSettings(capabilities_, page_size_),
547 PWGRasterConverter::GetBitmapSettings(capabilities_, ticket_),
548 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted,
549 base::Unretained(this)));
552 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
553 bool has_error,
554 const base::DictionaryValue* value) {
555 std::string error;
556 // This error is only relevant in the case of extended workflow:
557 // If the print job ID is invalid, retry createjob and submitdoc,
558 // rather than simply retrying the current request.
559 if (has_error && value->GetString(kPrivetKeyError, &error)) {
560 if (has_extended_workflow_ &&
561 error == kPrivetErrorInvalidPrintJob &&
562 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) {
563 invalid_job_retries_++;
565 int timeout = kPrivetLocalPrintDefaultTimeout;
566 value->GetInteger(kPrivetKeyTimeout, &timeout);
568 double random_scaling_factor =
569 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
571 timeout = static_cast<int>(timeout * random_scaling_factor);
573 timeout = std::max(timeout, kPrivetMinimumTimeout);
575 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
576 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob,
577 weak_factory_.GetWeakPtr()),
578 base::TimeDelta::FromSeconds(timeout));
579 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) {
580 use_pdf_ = false;
581 StartConvertToPWG();
582 } else {
583 delegate_->OnPrivetPrintingError(this, 200);
586 return;
589 // If we've gotten this far, there are no errors, so we've effectively
590 // succeeded.
591 delegate_->OnPrivetPrintingDone(this);
594 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
595 bool has_error,
596 const base::DictionaryValue* value) {
597 if (has_error) {
598 delegate_->OnPrivetPrintingError(this, 200);
599 return;
602 // Try to get job ID from value. If not, jobid_ will be empty and we will use
603 // simple printing.
604 value->GetString(kPrivetKeyJobID, &jobid_);
606 DoSubmitdoc();
609 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
610 bool success,
611 const base::FilePath& pwg_file_path) {
612 if (!success) {
613 delegate_->OnPrivetPrintingError(this, -1);
614 return;
617 DCHECK(!pwg_file_path.empty());
619 pwg_file_path_ = pwg_file_path;
620 StartPrinting();
623 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
624 return privet_client_;
627 void PrivetLocalPrintOperationImpl::OnError(
628 PrivetURLFetcher* fetcher,
629 PrivetURLFetcher::ErrorType error) {
630 delegate_->OnPrivetPrintingError(this, -1);
633 void PrivetLocalPrintOperationImpl::OnParsedJson(
634 PrivetURLFetcher* fetcher,
635 const base::DictionaryValue& value,
636 bool has_error) {
637 DCHECK(!current_response_.is_null());
638 current_response_.Run(has_error, &value);
641 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
642 PrivetURLFetcher* fetcher,
643 const PrivetURLFetcher::TokenCallback& callback) {
644 privet_client_->RefreshPrivetToken(callback);
647 void PrivetLocalPrintOperationImpl::SetData(
648 const scoped_refptr<base::RefCountedBytes>& data) {
649 DCHECK(!started_);
650 data_ = data;
653 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
654 DCHECK(!started_);
655 ticket_.InitFromString(ticket);
658 void PrivetLocalPrintOperationImpl::SetCapabilities(
659 const std::string& capabilities) {
660 DCHECK(!started_);
661 capabilities_.InitFromString(capabilities);
664 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
665 DCHECK(!started_);
666 user_ = user;
669 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
670 DCHECK(!started_);
671 jobname_ = jobname;
674 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
675 DCHECK(!started_);
676 offline_ = offline;
679 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) {
680 DCHECK(!started_);
681 page_size_ = page_size;
684 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
685 scoped_ptr<PWGRasterConverter> pwg_raster_converter) {
686 pwg_raster_converter_ = pwg_raster_converter.Pass();
688 #endif // ENABLE_PRINT_PREVIEW
690 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
691 const std::string& name,
692 const net::HostPortPair& host_port,
693 net::URLRequestContextGetter* request_context)
694 : name_(name), request_context_(request_context), host_port_(host_port) {}
696 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
699 const std::string& PrivetHTTPClientImpl::GetName() {
700 return name_;
703 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation(
704 const PrivetJSONOperation::ResultCallback& callback) {
705 return scoped_ptr<PrivetJSONOperation>(
706 new PrivetInfoOperationImpl(this, callback));
709 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
710 const GURL& url,
711 net::URLFetcher::RequestType request_type,
712 PrivetURLFetcher::Delegate* delegate) {
713 GURL::Replacements replacements;
714 replacements.SetHostStr(host_port_.host());
715 std::string port(
716 base::UintToString(host_port_.port())); // Keep string alive.
717 replacements.SetPortStr(port);
718 return scoped_ptr<PrivetURLFetcher>(
719 new PrivetURLFetcher(url.ReplaceComponents(replacements),
720 request_type,
721 request_context_.get(),
722 delegate));
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();
740 std::string token;
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.
744 if (value) {
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++) {
753 i->Run(token);
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));
795 #else
796 return scoped_ptr<PrivetLocalPrintOperation>();
797 #endif // ENABLE_PRINT_PREVIEW
800 } // namespace local_discovery