Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / local_discovery / privet_http_impl.cc
blob8cef172d13b1a0728814a98cda95557f5d8b1301
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 "chrome/browser/local_discovery/privet_constants.h"
16 #include "net/base/url_util.h"
17 #include "url/gurl.h"
19 namespace local_discovery {
21 namespace {
22 const char kUrlPlaceHolder[] = "http://host/";
23 const char kPrivetRegisterActionArgName[] = "action";
24 const char kPrivetRegisterUserArgName[] = "user";
26 const char kPrivetURLKeyUser[] = "user";
27 const char kPrivetURLKeyJobname[] = "jobname";
28 const char kPrivetURLKeyOffline[] = "offline";
29 const char kPrivetURLValueOffline[] = "1";
31 const char kPrivetContentTypePDF[] = "application/pdf";
32 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster";
33 const char kPrivetContentTypeAny[] = "*/*";
34 const char kPrivetContentTypeCJT[] = "application/json";
36 const char kPrivetStorageListPath[] = "/privet/storage/list";
37 const char kPrivetStorageParamPathFormat[] = "path=%s";
39 const char kPrivetCDDKeySupportedContentTypes[] =
40 "printer.supported_content_type";
42 const char kPrivetCDDKeyContentType[] = "content_type";
44 const char kPrivetKeyJobID[] = "job_id";
46 const int kPrivetCancelationTimeoutSeconds = 3;
48 const int kPrivetLocalPrintMaxRetries = 2;
50 const int kPrivetLocalPrintDefaultTimeout = 5;
52 GURL CreatePrivetURL(const std::string& path) {
53 GURL url(kUrlPlaceHolder);
54 GURL::Replacements replacements;
55 replacements.SetPathStr(path);
56 return url.ReplaceComponents(replacements);
59 GURL CreatePrivetRegisterURL(const std::string& action,
60 const std::string& user) {
61 GURL url = CreatePrivetURL(kPrivetRegisterPath);
62 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action);
63 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user);
66 GURL CreatePrivetParamURL(const std::string& path,
67 const std::string& query_params) {
68 GURL url(kUrlPlaceHolder);
69 GURL::Replacements replacements;
70 replacements.SetPathStr(path);
71 if (!query_params.empty()) {
72 replacements.SetQueryStr(query_params);
74 return url.ReplaceComponents(replacements);
77 } // namespace
79 PrivetInfoOperationImpl::PrivetInfoOperationImpl(
80 PrivetHTTPClientImpl* privet_client,
81 const PrivetJSONOperation::ResultCallback& callback)
82 : privet_client_(privet_client), callback_(callback) {
85 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() {
88 void PrivetInfoOperationImpl::Start() {
89 url_fetcher_ = privet_client_->CreateURLFetcher(
90 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this);
92 url_fetcher_->DoNotRetryOnTransientError();
93 url_fetcher_->AllowEmptyPrivetToken();
95 url_fetcher_->Start();
98 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() {
99 return privet_client_;
102 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
103 PrivetURLFetcher::ErrorType error) {
104 callback_.Run(NULL);
107 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher,
108 const base::DictionaryValue* value,
109 bool has_error) {
110 if (!has_error)
111 privet_client_->CacheInfo(value);
112 callback_.Run(value);
115 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
116 PrivetHTTPClientImpl* privet_client,
117 const std::string& user,
118 PrivetRegisterOperation::Delegate* delegate)
119 : user_(user), delegate_(delegate), privet_client_(privet_client),
120 ongoing_(false) {
123 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() {
126 void PrivetRegisterOperationImpl::Start() {
127 ongoing_ = true;
128 next_response_handler_ =
129 base::Bind(&PrivetRegisterOperationImpl::StartResponse,
130 base::Unretained(this));
131 SendRequest(kPrivetActionStart);
134 void PrivetRegisterOperationImpl::Cancel() {
135 url_fetcher_.reset();
137 if (ongoing_) {
138 // Owned by the message loop.
139 Cancelation* cancelation = new Cancelation(privet_client_, user_);
141 base::MessageLoop::current()->PostDelayedTask(
142 FROM_HERE,
143 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup,
144 base::Owned(cancelation)),
145 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds));
147 ongoing_ = false;
151 void PrivetRegisterOperationImpl::CompleteRegistration() {
152 next_response_handler_ =
153 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse,
154 base::Unretained(this));
155 SendRequest(kPrivetActionComplete);
158 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
159 return privet_client_;
162 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
163 PrivetURLFetcher::ErrorType error) {
164 ongoing_ = false;
165 int visible_http_code = -1;
166 FailureReason reason = FAILURE_NETWORK;
168 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
169 visible_http_code = fetcher->response_code();
170 reason = FAILURE_HTTP_ERROR;
171 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) {
172 reason = FAILURE_MALFORMED_RESPONSE;
173 } else if (error == PrivetURLFetcher::TOKEN_ERROR) {
174 reason = FAILURE_TOKEN;
175 } else if (error == PrivetURLFetcher::RETRY_ERROR) {
176 reason = FAILURE_RETRY;
179 delegate_->OnPrivetRegisterError(this,
180 current_action_,
181 reason,
182 visible_http_code,
183 NULL);
186 void PrivetRegisterOperationImpl::OnParsedJson(
187 PrivetURLFetcher* fetcher,
188 const base::DictionaryValue* value,
189 bool has_error) {
190 if (has_error) {
191 std::string error;
192 value->GetString(kPrivetKeyError, &error);
194 ongoing_ = false;
195 delegate_->OnPrivetRegisterError(this,
196 current_action_,
197 FAILURE_JSON_ERROR,
198 fetcher->response_code(),
199 value);
200 return;
203 // TODO(noamsml): Match the user&action with the user&action in the object,
204 // and fail if different.
206 next_response_handler_.Run(*value);
209 void PrivetRegisterOperationImpl::OnNeedPrivetToken(
210 PrivetURLFetcher* fetcher,
211 const PrivetURLFetcher::TokenCallback& callback) {
212 privet_client_->RefreshPrivetToken(callback);
215 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) {
216 current_action_ = action;
217 url_fetcher_ = privet_client_->CreateURLFetcher(
218 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this);
219 url_fetcher_->Start();
222 void PrivetRegisterOperationImpl::StartResponse(
223 const base::DictionaryValue& value) {
224 next_response_handler_ =
225 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse,
226 base::Unretained(this));
228 SendRequest(kPrivetActionGetClaimToken);
231 void PrivetRegisterOperationImpl::GetClaimTokenResponse(
232 const base::DictionaryValue& value) {
233 std::string claimUrl;
234 std::string claimToken;
235 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
236 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
237 if (got_url || got_token) {
238 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
239 } else {
240 delegate_->OnPrivetRegisterError(this,
241 current_action_,
242 FAILURE_MALFORMED_RESPONSE,
244 NULL);
248 void PrivetRegisterOperationImpl::CompleteResponse(
249 const base::DictionaryValue& value) {
250 std::string id;
251 value.GetString(kPrivetKeyDeviceID, &id);
252 ongoing_ = false;
253 expected_id_ = id;
254 StartInfoOperation();
257 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
258 const base::DictionaryValue* value) {
259 // TODO(noamsml): Simplify error case and depracate HTTP error value in
260 // OnPrivetRegisterError.
261 if (!value) {
262 delegate_->OnPrivetRegisterError(this,
263 kPrivetActionNameInfo,
264 FAILURE_NETWORK,
266 NULL);
267 return;
270 if (!value->HasKey(kPrivetInfoKeyID)) {
271 if (value->HasKey(kPrivetKeyError)) {
272 delegate_->OnPrivetRegisterError(this,
273 kPrivetActionNameInfo,
274 FAILURE_JSON_ERROR,
276 value);
277 } else {
278 delegate_->OnPrivetRegisterError(this,
279 kPrivetActionNameInfo,
280 FAILURE_MALFORMED_RESPONSE,
282 NULL);
284 return;
287 std::string id;
289 if (!value->GetString(kPrivetInfoKeyID, &id) ||
290 id != expected_id_) {
291 delegate_->OnPrivetRegisterError(this,
292 kPrivetActionNameInfo,
293 FAILURE_MALFORMED_RESPONSE,
295 NULL);
296 } else {
297 delegate_->OnPrivetRegisterDone(this, id);
301 void PrivetRegisterOperationImpl::StartInfoOperation() {
302 info_operation_ = privet_client_->CreateInfoOperation(
303 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone,
304 base::Unretained(this)));
305 info_operation_->Start();
308 PrivetRegisterOperationImpl::Cancelation::Cancelation(
309 PrivetHTTPClientImpl* privet_client,
310 const std::string& user) {
311 url_fetcher_ =
312 privet_client->CreateURLFetcher(
313 CreatePrivetRegisterURL(kPrivetActionCancel, user),
314 net::URLFetcher::POST, this);
315 url_fetcher_->DoNotRetryOnTransientError();
316 url_fetcher_->Start();
319 PrivetRegisterOperationImpl::Cancelation::~Cancelation() {
322 void PrivetRegisterOperationImpl::Cancelation::OnError(
323 PrivetURLFetcher* fetcher,
324 PrivetURLFetcher::ErrorType error) {
327 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson(
328 PrivetURLFetcher* fetcher,
329 const base::DictionaryValue* value,
330 bool has_error) {
333 void PrivetRegisterOperationImpl::Cancelation::Cleanup() {
334 // Nothing needs to be done, as base::Owned will delete this object,
335 // this callback is just here to pass ownership of the Cancelation to
336 // the message loop.
339 PrivetJSONOperationImpl::PrivetJSONOperationImpl(
340 PrivetHTTPClientImpl* privet_client,
341 const std::string& path,
342 const std::string& query_params,
343 const PrivetJSONOperation::ResultCallback& callback)
344 : privet_client_(privet_client), path_(path), query_params_(query_params),
345 callback_(callback) {
348 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() {
351 void PrivetJSONOperationImpl::Start() {
352 url_fetcher_ = privet_client_->CreateURLFetcher(
353 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this);
354 url_fetcher_->DoNotRetryOnTransientError();
355 url_fetcher_->Start();
358 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() {
359 return privet_client_;
362 void PrivetJSONOperationImpl::OnError(
363 PrivetURLFetcher* fetcher,
364 PrivetURLFetcher::ErrorType error) {
365 callback_.Run(NULL);
368 void PrivetJSONOperationImpl::OnParsedJson(
369 PrivetURLFetcher* fetcher,
370 const base::DictionaryValue* value,
371 bool has_error) {
372 callback_.Run(value);
375 void PrivetJSONOperationImpl::OnNeedPrivetToken(
376 PrivetURLFetcher* fetcher,
377 const PrivetURLFetcher::TokenCallback& callback) {
378 privet_client_->RefreshPrivetToken(callback);
381 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl(
382 PrivetHTTPClientImpl* privet_client,
383 PrivetLocalPrintOperation::Delegate* delegate)
384 : privet_client_(privet_client), delegate_(delegate),
385 use_pdf_(false), has_capabilities_(false), has_extended_workflow_(false),
386 started_(false), offline_(false), invalid_job_retries_(0),
387 weak_factory_(this) {
390 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() {
393 void PrivetLocalPrintOperationImpl::Start() {
394 DCHECK(!started_);
396 // We need to get the /info response so we can know which APIs are available.
397 // TODO(noamsml): Use cached info when available.
398 info_operation_ = privet_client_->CreateInfoOperation(
399 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone,
400 base::Unretained(this)));
401 info_operation_->Start();
403 started_ = true;
406 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone(
407 const base::DictionaryValue* value) {
408 if (value && !value->HasKey(kPrivetKeyError)) {
409 has_capabilities_ = false;
410 has_extended_workflow_ = false;
411 bool has_printing = false;
413 const base::ListValue* api_list;
414 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
415 for (size_t i = 0; i < api_list->GetSize(); i++) {
416 std::string api;
417 api_list->GetString(i, &api);
418 if (api == kPrivetCapabilitiesPath) {
419 has_capabilities_ = true;
420 } else if (api == kPrivetSubmitdocPath) {
421 has_printing = true;
422 } else if (api == kPrivetCreatejobPath) {
423 has_extended_workflow_ = true;
428 if (!has_printing) {
429 delegate_->OnPrivetPrintingError(this, -1);
430 return;
433 StartInitialRequest();
434 } else {
435 delegate_->OnPrivetPrintingError(this, -1);
439 void PrivetLocalPrintOperationImpl::StartInitialRequest() {
440 if (has_capabilities_) {
441 GetCapabilities();
442 } else {
443 // Since we have no capabiltties, the only reasonable format we can
444 // request is PWG Raster.
445 use_pdf_ = false;
446 StartConvertToPWG();
450 void PrivetLocalPrintOperationImpl::GetCapabilities() {
451 current_response_ = base::Bind(
452 &PrivetLocalPrintOperationImpl::OnCapabilitiesResponse,
453 base::Unretained(this));
455 url_fetcher_= privet_client_->CreateURLFetcher(
456 CreatePrivetURL(kPrivetCapabilitiesPath), net::URLFetcher::GET, this);
457 url_fetcher_->DoNotRetryOnTransientError();
459 url_fetcher_->Start();
462 void PrivetLocalPrintOperationImpl::DoCreatejob() {
463 current_response_ = base::Bind(
464 &PrivetLocalPrintOperationImpl::OnCreatejobResponse,
465 base::Unretained(this));
467 url_fetcher_= privet_client_->CreateURLFetcher(
468 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this);
469 url_fetcher_->SetUploadData(kPrivetContentTypeCJT, ticket_);
471 url_fetcher_->Start();
474 void PrivetLocalPrintOperationImpl::DoSubmitdoc() {
475 current_response_ = base::Bind(
476 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse,
477 base::Unretained(this));
479 GURL url = CreatePrivetURL(kPrivetSubmitdocPath);
481 if (!user_.empty()) {
482 url = net::AppendQueryParameter(url,
483 kPrivetURLKeyUser,
484 user_);
487 if (!jobname_.empty()) {
488 url = net::AppendQueryParameter(url,
489 kPrivetURLKeyJobname,
490 jobname_);
493 if (!jobid_.empty()) {
494 url = net::AppendQueryParameter(url,
495 kPrivetKeyJobID,
496 jobid_);
499 if (offline_) {
500 url = net::AppendQueryParameter(url,
501 kPrivetURLKeyOffline,
502 kPrivetURLValueOffline);
505 url_fetcher_= privet_client_->CreateURLFetcher(
506 url, net::URLFetcher::POST, this);
508 if (!use_pdf_) {
509 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster,
510 pwg_file_path_);
511 } else {
512 // TODO(noamsml): Move to file-based upload data?
513 std::string data_str((const char*)data_->front(), data_->size());
514 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str);
517 url_fetcher_->Start();
520 void PrivetLocalPrintOperationImpl::StartPrinting() {
521 if (has_extended_workflow_ && !ticket_.empty() && jobid_.empty()) {
522 DoCreatejob();
523 } else {
524 DoSubmitdoc();
528 void PrivetLocalPrintOperationImpl::StartConvertToPWG() {
529 if (!pwg_raster_converter_)
530 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
531 pwg_raster_converter_->Start(
532 data_,
533 conversion_settings_,
534 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted,
535 base::Unretained(this)));
538 void PrivetLocalPrintOperationImpl::OnCapabilitiesResponse(
539 bool has_error,
540 const base::DictionaryValue* value) {
541 if (has_error) {
542 delegate_->OnPrivetPrintingError(this, 200);
543 return;
546 const base::ListValue* supported_content_types;
547 use_pdf_ = false;
549 if (value->GetList(kPrivetCDDKeySupportedContentTypes,
550 &supported_content_types)) {
551 for (size_t i = 0; i < supported_content_types->GetSize(); i++) {
552 const base::DictionaryValue* content_type_value;
553 std::string content_type;
555 if (supported_content_types->GetDictionary(i, &content_type_value) &&
556 content_type_value->GetString(kPrivetCDDKeyContentType,
557 &content_type) &&
558 (content_type == kPrivetContentTypePDF ||
559 content_type == kPrivetContentTypeAny) ) {
560 use_pdf_ = true;
565 if (use_pdf_) {
566 StartPrinting();
567 } else {
568 StartConvertToPWG();
572 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse(
573 bool has_error,
574 const base::DictionaryValue* value) {
575 std::string error;
576 // This error is only relevant in the case of extended workflow:
577 // If the print job ID is invalid, retry createjob and submitdoc,
578 // rather than simply retrying the current request.
579 if (has_error && value->GetString(kPrivetKeyError, &error)) {
580 if (has_extended_workflow_ &&
581 error == kPrivetErrorInvalidPrintJob &&
582 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) {
583 invalid_job_retries_++;
585 int timeout = kPrivetLocalPrintDefaultTimeout;
586 value->GetInteger(kPrivetKeyTimeout, &timeout);
588 double random_scaling_factor =
589 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition;
591 timeout = static_cast<int>(timeout * random_scaling_factor);
593 timeout = std::max(timeout, kPrivetMinimumTimeout);
595 base::MessageLoop::current()->PostDelayedTask(
596 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob,
597 weak_factory_.GetWeakPtr()),
598 base::TimeDelta::FromSeconds(timeout));
599 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) {
600 use_pdf_ = false;
601 StartConvertToPWG();
602 } else {
603 delegate_->OnPrivetPrintingError(this, 200);
606 return;
609 // If we've gotten this far, there are no errors, so we've effectively
610 // succeeded.
611 delegate_->OnPrivetPrintingDone(this);
614 void PrivetLocalPrintOperationImpl::OnCreatejobResponse(
615 bool has_error,
616 const base::DictionaryValue* value) {
617 if (has_error) {
618 delegate_->OnPrivetPrintingError(this, 200);
619 return;
622 // Try to get job ID from value. If not, jobid_ will be empty and we will use
623 // simple printing.
624 value->GetString(kPrivetKeyJobID, &jobid_);
626 DoSubmitdoc();
629 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted(
630 bool success,
631 const base::FilePath& pwg_file_path) {
632 if (!success) {
633 delegate_->OnPrivetPrintingError(this, -1);
634 return;
637 DCHECK(!pwg_file_path.empty());
639 pwg_file_path_ = pwg_file_path;
640 StartPrinting();
643 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() {
644 return privet_client_;
647 void PrivetLocalPrintOperationImpl::OnError(
648 PrivetURLFetcher* fetcher,
649 PrivetURLFetcher::ErrorType error) {
650 delegate_->OnPrivetPrintingError(this, -1);
653 void PrivetLocalPrintOperationImpl::OnParsedJson(
654 PrivetURLFetcher* fetcher,
655 const base::DictionaryValue* value,
656 bool has_error) {
657 DCHECK(!current_response_.is_null());
658 current_response_.Run(has_error, value);
661 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken(
662 PrivetURLFetcher* fetcher,
663 const PrivetURLFetcher::TokenCallback& callback) {
664 privet_client_->RefreshPrivetToken(callback);
667 void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) {
668 DCHECK(!started_);
669 data_ = data;
672 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) {
673 DCHECK(!started_);
674 ticket_ = ticket;
677 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) {
678 DCHECK(!started_);
679 user_= user;
682 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) {
683 DCHECK(!started_);
684 jobname_ = jobname;
687 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) {
688 DCHECK(!started_);
689 offline_ = offline;
692 void PrivetLocalPrintOperationImpl::SetConversionSettings(
693 const printing::PdfRenderSettings& conversion_settings) {
694 DCHECK(!started_);
695 conversion_settings_ = conversion_settings;
698 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting(
699 scoped_ptr<PWGRasterConverter> pwg_raster_converter) {
700 pwg_raster_converter_ = pwg_raster_converter.Pass();
703 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
704 const std::string& name,
705 const net::HostPortPair& host_port,
706 net::URLRequestContextGetter* request_context)
707 : name_(name),
708 fetcher_factory_(request_context),
709 host_port_(host_port) {
712 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() {
715 const base::DictionaryValue* PrivetHTTPClientImpl::GetCachedInfo() const {
716 return cached_info_.get();
719 scoped_ptr<PrivetRegisterOperation>
720 PrivetHTTPClientImpl::CreateRegisterOperation(
721 const std::string& user,
722 PrivetRegisterOperation::Delegate* delegate) {
723 return scoped_ptr<PrivetRegisterOperation>(
724 new PrivetRegisterOperationImpl(this, user, delegate));
727 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation(
728 const PrivetJSONOperation::ResultCallback& callback) {
729 return scoped_ptr<PrivetJSONOperation>(
730 new PrivetInfoOperationImpl(this, callback));
733 scoped_ptr<PrivetJSONOperation>
734 PrivetHTTPClientImpl::CreateCapabilitiesOperation(
735 const PrivetJSONOperation::ResultCallback& callback) {
736 return scoped_ptr<PrivetJSONOperation>(
737 new PrivetJSONOperationImpl(this, kPrivetCapabilitiesPath, "", callback));
740 scoped_ptr<PrivetLocalPrintOperation>
741 PrivetHTTPClientImpl::CreateLocalPrintOperation(
742 PrivetLocalPrintOperation::Delegate* delegate) {
743 return scoped_ptr<PrivetLocalPrintOperation>(
744 new PrivetLocalPrintOperationImpl(this, delegate));
747 scoped_ptr<PrivetJSONOperation>
748 PrivetHTTPClientImpl::CreateStorageListOperation(
749 const std::string& path,
750 const PrivetJSONOperation::ResultCallback& callback) {
751 std::string url_param = base::StringPrintf(kPrivetStorageParamPathFormat,
752 path.c_str());
753 return scoped_ptr<PrivetJSONOperation>(
754 new PrivetJSONOperationImpl(this, kPrivetStorageListPath, url_param,
755 callback));
758 const std::string& PrivetHTTPClientImpl::GetName() {
759 return name_;
762 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher(
763 const GURL& url, net::URLFetcher::RequestType request_type,
764 PrivetURLFetcher::Delegate* delegate) const {
765 GURL::Replacements replacements;
766 replacements.SetHostStr(host_port_.host());
767 std::string port(base::IntToString(host_port_.port())); // Keep string alive.
768 replacements.SetPortStr(port);
769 return fetcher_factory_.CreateURLFetcher(url.ReplaceComponents(replacements),
770 request_type, delegate);
773 void PrivetHTTPClientImpl::CacheInfo(const base::DictionaryValue* cached_info) {
774 cached_info_.reset(cached_info->DeepCopy());
775 std::string token;
776 if (cached_info_->GetString(kPrivetInfoKeyToken, &token)) {
777 fetcher_factory_.set_token(token);
781 bool PrivetHTTPClientImpl::HasToken() const {
782 return fetcher_factory_.get_token() != "";
785 void PrivetHTTPClientImpl::RefreshPrivetToken(
786 const PrivetURLFetcher::TokenCallback& callback) {
787 token_callbacks_.push_back(callback);
789 if (!info_operation_) {
790 info_operation_ = CreateInfoOperation(
791 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone,
792 base::Unretained(this)));
793 info_operation_->Start();
797 void PrivetHTTPClientImpl::OnPrivetInfoDone(
798 const base::DictionaryValue* value) {
799 info_operation_.reset();
800 std::string token;
802 // If this does not succeed, token will be empty, and an empty string
803 // is our sentinel value, since empty X-Privet-Tokens are not allowed.
804 if (value) {
805 value->GetString(kPrivetInfoKeyToken, &token);
808 TokenCallbackVector token_callbacks;
809 token_callbacks_.swap(token_callbacks);
811 for (TokenCallbackVector::iterator i = token_callbacks.begin();
812 i != token_callbacks.end(); i++) {
813 i->Run(token);
817 } // namespace local_discovery