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. 4 5#include "chrome/browser/local_discovery/privet_http_impl.h" 6 7#include <algorithm> 8#include <vector> 9 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 "chrome/browser/local_discovery/privet_constants.h" 15#include "net/base/url_util.h" 16#include "url/gurl.h" 17 18namespace local_discovery { 19 20namespace { 21const char kUrlPlaceHolder[] = "http://host/"; 22const char kPrivetRegisterActionArgName[] = "action"; 23const char kPrivetRegisterUserArgName[] = "user"; 24 25const char kPrivetURLKeyUserName[] = "user_name"; 26const char kPrivetURLKeyClientName[] = "client_name"; 27const char kPrivetURLKeyJobname[] = "job_name"; 28const char kPrivetURLKeyOffline[] = "offline"; 29const char kPrivetURLValueOffline[] = "1"; 30const char kPrivetURLValueClientName[] = "Chrome"; 31 32const char kPrivetContentTypePDF[] = "application/pdf"; 33const char kPrivetContentTypePWGRaster[] = "image/pwg-raster"; 34const char kPrivetContentTypeAny[] = "*/*"; 35const char kPrivetContentTypeCJT[] = "application/json"; 36 37const char kPrivetCDDKeySupportedContentTypes[] = 38 "printer.supported_content_type"; 39 40const char kPrivetCDDKeyContentType[] = "content_type"; 41 42const char kPrivetKeyJobID[] = "job_id"; 43 44const int kPrivetCancelationTimeoutSeconds = 3; 45 46const int kPrivetLocalPrintMaxRetries = 2; 47 48const int kPrivetLocalPrintDefaultTimeout = 5; 49 50GURL CreatePrivetURL(const std::string& path) { 51 GURL url(kUrlPlaceHolder); 52 GURL::Replacements replacements; 53 replacements.SetPathStr(path); 54 return url.ReplaceComponents(replacements); 55} 56 57GURL CreatePrivetRegisterURL(const std::string& action, 58 const std::string& user) { 59 GURL url = CreatePrivetURL(kPrivetRegisterPath); 60 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action); 61 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user); 62} 63 64} // namespace 65 66PrivetInfoOperationImpl::PrivetInfoOperationImpl( 67 PrivetHTTPClientImpl* privet_client, 68 PrivetInfoOperation::Delegate* delegate) 69 : privet_client_(privet_client), delegate_(delegate) { 70} 71 72PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { 73} 74 75void PrivetInfoOperationImpl::Start() { 76 url_fetcher_ = privet_client_->CreateURLFetcher( 77 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this); 78 79 url_fetcher_->DoNotRetryOnTransientError(); 80 url_fetcher_->AllowEmptyPrivetToken(); 81 82 url_fetcher_->Start(); 83} 84 85PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() { 86 return privet_client_; 87} 88 89void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher, 90 PrivetURLFetcher::ErrorType error) { 91 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) { 92 delegate_->OnPrivetInfoDone(this, fetcher->response_code(), NULL); 93 } else { 94 delegate_->OnPrivetInfoDone(this, kPrivetHTTPCodeInternalFailure, NULL); 95 } 96} 97 98void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher, 99 const base::DictionaryValue* value, 100 bool has_error) { 101 if (!has_error) 102 privet_client_->CacheInfo(value); 103 delegate_->OnPrivetInfoDone(this, fetcher->response_code(), value); 104} 105 106PrivetRegisterOperationImpl::PrivetRegisterOperationImpl( 107 PrivetHTTPClientImpl* privet_client, 108 const std::string& user, 109 PrivetRegisterOperation::Delegate* delegate) 110 : user_(user), delegate_(delegate), privet_client_(privet_client), 111 ongoing_(false) { 112} 113 114PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() { 115} 116 117void PrivetRegisterOperationImpl::Start() { 118 ongoing_ = true; 119 next_response_handler_ = 120 base::Bind(&PrivetRegisterOperationImpl::StartResponse, 121 base::Unretained(this)); 122 SendRequest(kPrivetActionStart); 123} 124 125void PrivetRegisterOperationImpl::Cancel() { 126 url_fetcher_.reset(); 127 128 if (ongoing_) { 129 // Owned by the message loop. 130 Cancelation* cancelation = new Cancelation(privet_client_, user_); 131 132 base::MessageLoop::current()->PostDelayedTask( 133 FROM_HERE, 134 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup, 135 base::Owned(cancelation)), 136 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds)); 137 138 ongoing_ = false; 139 } 140} 141 142void PrivetRegisterOperationImpl::CompleteRegistration() { 143 next_response_handler_ = 144 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse, 145 base::Unretained(this)); 146 SendRequest(kPrivetActionComplete); 147} 148 149PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() { 150 return privet_client_; 151} 152 153void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher, 154 PrivetURLFetcher::ErrorType error) { 155 ongoing_ = false; 156 int visible_http_code = -1; 157 FailureReason reason = FAILURE_NETWORK; 158 159 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) { 160 visible_http_code = fetcher->response_code(); 161 reason = FAILURE_HTTP_ERROR; 162 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) { 163 reason = FAILURE_MALFORMED_RESPONSE; 164 } else if (error == PrivetURLFetcher::TOKEN_ERROR) { 165 reason = FAILURE_TOKEN; 166 } else if (error == PrivetURLFetcher::RETRY_ERROR) { 167 reason = FAILURE_RETRY; 168 } 169 170 delegate_->OnPrivetRegisterError(this, 171 current_action_, 172 reason, 173 visible_http_code, 174 NULL); 175} 176 177void PrivetRegisterOperationImpl::OnParsedJson( 178 PrivetURLFetcher* fetcher, 179 const base::DictionaryValue* value, 180 bool has_error) { 181 if (has_error) { 182 std::string error; 183 value->GetString(kPrivetKeyError, &error); 184 185 ongoing_ = false; 186 delegate_->OnPrivetRegisterError(this, 187 current_action_, 188 FAILURE_JSON_ERROR, 189 fetcher->response_code(), 190 value); 191 return; 192 } 193 194 // TODO(noamsml): Match the user&action with the user&action in the object, 195 // and fail if different. 196 197 next_response_handler_.Run(*value); 198} 199 200void PrivetRegisterOperationImpl::OnNeedPrivetToken( 201 PrivetURLFetcher* fetcher, 202 const PrivetURLFetcher::TokenCallback& callback) { 203 privet_client_->RefreshPrivetToken(callback); 204} 205 206void PrivetRegisterOperationImpl::SendRequest(const std::string& action) { 207 current_action_ = action; 208 url_fetcher_ = privet_client_->CreateURLFetcher( 209 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this); 210 url_fetcher_->Start(); 211} 212 213void PrivetRegisterOperationImpl::StartResponse( 214 const base::DictionaryValue& value) { 215 next_response_handler_ = 216 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse, 217 base::Unretained(this)); 218 219 SendRequest(kPrivetActionGetClaimToken); 220} 221 222void PrivetRegisterOperationImpl::GetClaimTokenResponse( 223 const base::DictionaryValue& value) { 224 std::string claimUrl; 225 std::string claimToken; 226 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl); 227 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken); 228 if (got_url || got_token) { 229 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl)); 230 } else { 231 delegate_->OnPrivetRegisterError(this, 232 current_action_, 233 FAILURE_MALFORMED_RESPONSE, 234 -1, 235 NULL); 236 } 237} 238 239void PrivetRegisterOperationImpl::CompleteResponse( 240 const base::DictionaryValue& value) { 241 std::string id; 242 value.GetString(kPrivetKeyDeviceID, &id); 243 ongoing_ = false; 244 expected_id_ = id; 245 StartInfoOperation(); 246} 247 248void PrivetRegisterOperationImpl::OnPrivetInfoDone( 249 PrivetInfoOperation* operation, 250 int http_code, 251 const base::DictionaryValue* value) { 252 // TODO(noamsml): Simplify error case. 253 if (!value) { 254 delegate_->OnPrivetRegisterError(this, 255 kPrivetActionNameInfo, 256 FAILURE_NETWORK, 257 -1, 258 NULL); 259 return; 260 } 261 262 if (!value->HasKey(kPrivetInfoKeyID)) { 263 if (value->HasKey(kPrivetKeyError)) { 264 delegate_->OnPrivetRegisterError(this, 265 kPrivetActionNameInfo, 266 FAILURE_JSON_ERROR, 267 http_code, 268 value); 269 } else { 270 delegate_->OnPrivetRegisterError(this, 271 kPrivetActionNameInfo, 272 FAILURE_MALFORMED_RESPONSE, 273 -1, 274 NULL); 275 } 276 return; 277 } 278 279 std::string id; 280 281 if (!value->GetString(kPrivetInfoKeyID, &id) || 282 id != expected_id_) { 283 delegate_->OnPrivetRegisterError(this, 284 kPrivetActionNameInfo, 285 FAILURE_MALFORMED_RESPONSE, 286 -1, 287 NULL); 288 } else { 289 delegate_->OnPrivetRegisterDone(this, id); 290 } 291} 292 293void PrivetRegisterOperationImpl::StartInfoOperation() { 294 info_operation_ = privet_client_->CreateInfoOperation(this); 295 info_operation_->Start(); 296} 297 298PrivetRegisterOperationImpl::Cancelation::Cancelation( 299 PrivetHTTPClientImpl* privet_client, 300 const std::string& user) { 301 url_fetcher_ = 302 privet_client->CreateURLFetcher( 303 CreatePrivetRegisterURL(kPrivetActionCancel, user), 304 net::URLFetcher::POST, this); 305 url_fetcher_->DoNotRetryOnTransientError(); 306 url_fetcher_->Start(); 307} 308 309PrivetRegisterOperationImpl::Cancelation::~Cancelation() { 310} 311 312void PrivetRegisterOperationImpl::Cancelation::OnError( 313 PrivetURLFetcher* fetcher, 314 PrivetURLFetcher::ErrorType error) { 315} 316 317void PrivetRegisterOperationImpl::Cancelation::OnParsedJson( 318 PrivetURLFetcher* fetcher, 319 const base::DictionaryValue* value, 320 bool has_error) { 321} 322 323void PrivetRegisterOperationImpl::Cancelation::Cleanup() { 324 // Nothing needs to be done, as base::Owned will delete this object, 325 // this callback is just here to pass ownership of the Cancelation to 326 // the message loop. 327} 328 329PrivetCapabilitiesOperationImpl::PrivetCapabilitiesOperationImpl( 330 PrivetHTTPClientImpl* privet_client, 331 PrivetCapabilitiesOperation::Delegate* delegate) 332 : privet_client_(privet_client), delegate_(delegate) { 333} 334 335PrivetCapabilitiesOperationImpl::~PrivetCapabilitiesOperationImpl() { 336} 337 338void PrivetCapabilitiesOperationImpl::Start() { 339 url_fetcher_ = privet_client_->CreateURLFetcher( 340 CreatePrivetURL(kPrivetCapabilitiesPath), net::URLFetcher::GET, this); 341 url_fetcher_->DoNotRetryOnTransientError(); 342 url_fetcher_->Start(); 343} 344 345PrivetHTTPClient* PrivetCapabilitiesOperationImpl::GetHTTPClient() { 346 return privet_client_; 347} 348 349void PrivetCapabilitiesOperationImpl::OnError( 350 PrivetURLFetcher* fetcher, 351 PrivetURLFetcher::ErrorType error) { 352 delegate_->OnPrivetCapabilities(this, -1, NULL); 353} 354 355void PrivetCapabilitiesOperationImpl::OnParsedJson( 356 PrivetURLFetcher* fetcher, 357 const base::DictionaryValue* value, 358 bool has_error) { 359 delegate_->OnPrivetCapabilities(this, fetcher->response_code(), value); 360} 361 362void PrivetCapabilitiesOperationImpl::OnNeedPrivetToken( 363 PrivetURLFetcher* fetcher, 364 const PrivetURLFetcher::TokenCallback& callback) { 365 privet_client_->RefreshPrivetToken(callback); 366} 367 368PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl( 369 PrivetHTTPClientImpl* privet_client, 370 PrivetLocalPrintOperation::Delegate* delegate) 371 : privet_client_(privet_client), delegate_(delegate), 372 use_pdf_(false), has_capabilities_(false), has_extended_workflow_(false), 373 started_(false), offline_(false), invalid_job_retries_(0), 374 weak_factory_(this) { 375} 376 377PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() { 378} 379 380void PrivetLocalPrintOperationImpl::Start() { 381 DCHECK(!started_); 382 383 // We need to get the /info response so we can know which APIs are available. 384 // TODO(noamsml): Use cached info when available. 385 info_operation_ = privet_client_->CreateInfoOperation(this); 386 info_operation_->Start(); 387 388 started_ = true; 389} 390 391void PrivetLocalPrintOperationImpl::OnPrivetInfoDone( 392 PrivetInfoOperation* operation, 393 int http_code, 394 const base::DictionaryValue* value) { 395 if (value && !value->HasKey(kPrivetKeyError)) { 396 has_capabilities_ = false; 397 has_extended_workflow_ = false; 398 bool has_printing = false; 399 400 const base::ListValue* api_list; 401 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) { 402 for (size_t i = 0; i < api_list->GetSize(); i++) { 403 std::string api; 404 api_list->GetString(i, &api); 405 if (api == kPrivetCapabilitiesPath) { 406 has_capabilities_ = true; 407 } else if (api == kPrivetSubmitdocPath) { 408 has_printing = true; 409 } else if (api == kPrivetCreatejobPath) { 410 has_extended_workflow_ = true; 411 } 412 } 413 } 414 415 if (!has_printing) { 416 delegate_->OnPrivetPrintingError(this, -1); 417 return; 418 } 419 420 StartInitialRequest(); 421 } else { 422 delegate_->OnPrivetPrintingError(this, http_code); 423 } 424} 425 426void PrivetLocalPrintOperationImpl::StartInitialRequest() { 427 if (has_capabilities_) { 428 GetCapabilities(); 429 } else { 430 // Since we have no capabiltties, the only reasonable format we can 431 // request is PWG Raster. 432 use_pdf_ = false; 433 StartConvertToPWG(); 434 } 435} 436 437void PrivetLocalPrintOperationImpl::GetCapabilities() { 438 current_response_ = base::Bind( 439 &PrivetLocalPrintOperationImpl::OnCapabilitiesResponse, 440 base::Unretained(this)); 441 442 url_fetcher_= privet_client_->CreateURLFetcher( 443 CreatePrivetURL(kPrivetCapabilitiesPath), net::URLFetcher::GET, this); 444 url_fetcher_->DoNotRetryOnTransientError(); 445 446 url_fetcher_->Start(); 447} 448 449void PrivetLocalPrintOperationImpl::DoCreatejob() { 450 current_response_ = base::Bind( 451 &PrivetLocalPrintOperationImpl::OnCreatejobResponse, 452 base::Unretained(this)); 453 454 url_fetcher_= privet_client_->CreateURLFetcher( 455 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this); 456 url_fetcher_->SetUploadData(kPrivetContentTypeCJT, ticket_); 457 458 url_fetcher_->Start(); 459} 460 461void PrivetLocalPrintOperationImpl::DoSubmitdoc() { 462 current_response_ = base::Bind( 463 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse, 464 base::Unretained(this)); 465 466 GURL url = CreatePrivetURL(kPrivetSubmitdocPath); 467 468 url = net::AppendQueryParameter(url, 469 kPrivetURLKeyClientName, 470 kPrivetURLValueClientName); 471 472 if (!user_.empty()) { 473 url = net::AppendQueryParameter(url, 474 kPrivetURLKeyUserName, 475 user_); 476 } 477 478 if (!jobname_.empty()) { 479 url = net::AppendQueryParameter(url, 480 kPrivetURLKeyJobname, 481 jobname_); 482 } 483 484 if (!jobid_.empty()) { 485 url = net::AppendQueryParameter(url, 486 kPrivetKeyJobID, 487 jobid_); 488 } 489 490 if (offline_) { 491 url = net::AppendQueryParameter(url, 492 kPrivetURLKeyOffline, 493 kPrivetURLValueOffline); 494 } 495 496 url_fetcher_= privet_client_->CreateURLFetcher( 497 url, net::URLFetcher::POST, this); 498 499 if (!use_pdf_) { 500 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster, 501 pwg_file_path_); 502 } else { 503 // TODO(noamsml): Move to file-based upload data? 504 std::string data_str((const char*)data_->front(), data_->size()); 505 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str); 506 } 507 508 url_fetcher_->Start(); 509} 510 511void PrivetLocalPrintOperationImpl::StartPrinting() { 512 if (has_extended_workflow_ && !ticket_.empty() && jobid_.empty()) { 513 DoCreatejob(); 514 } else { 515 DoSubmitdoc(); 516 } 517} 518 519void PrivetLocalPrintOperationImpl::StartConvertToPWG() { 520 if (!pwg_raster_converter_) 521 pwg_raster_converter_ = PWGRasterConverter::CreateDefault(); 522 pwg_raster_converter_->Start( 523 data_, 524 conversion_settings_, 525 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted, 526 base::Unretained(this))); 527} 528 529void PrivetLocalPrintOperationImpl::OnCapabilitiesResponse( 530 bool has_error, 531 const base::DictionaryValue* value) { 532 if (has_error) { 533 delegate_->OnPrivetPrintingError(this, 200); 534 return; 535 } 536 537 const base::ListValue* supported_content_types; 538 use_pdf_ = false; 539 540 if (value->GetList(kPrivetCDDKeySupportedContentTypes, 541 &supported_content_types)) { 542 for (size_t i = 0; i < supported_content_types->GetSize(); i++) { 543 const base::DictionaryValue* content_type_value; 544 std::string content_type; 545 546 if (supported_content_types->GetDictionary(i, &content_type_value) && 547 content_type_value->GetString(kPrivetCDDKeyContentType, 548 &content_type) && 549 (content_type == kPrivetContentTypePDF || 550 content_type == kPrivetContentTypeAny) ) { 551 use_pdf_ = true; 552 } 553 } 554 } 555 556 if (use_pdf_) { 557 StartPrinting(); 558 } else { 559 StartConvertToPWG(); 560 } 561} 562 563void PrivetLocalPrintOperationImpl::OnSubmitdocResponse( 564 bool has_error, 565 const base::DictionaryValue* value) { 566 std::string error; 567 // This error is only relevant in the case of extended workflow: 568 // If the print job ID is invalid, retry createjob and submitdoc, 569 // rather than simply retrying the current request. 570 if (has_error && value->GetString(kPrivetKeyError, &error)) { 571 if (has_extended_workflow_ && 572 error == kPrivetErrorInvalidPrintJob && 573 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) { 574 invalid_job_retries_++; 575 576 int timeout = kPrivetLocalPrintDefaultTimeout; 577 value->GetInteger(kPrivetKeyTimeout, &timeout); 578 579 double random_scaling_factor = 580 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition; 581 582 timeout = static_cast<int>(timeout * random_scaling_factor); 583 584 timeout = std::max(timeout, kPrivetMinimumTimeout); 585 586 base::MessageLoop::current()->PostDelayedTask( 587 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob, 588 weak_factory_.GetWeakPtr()), 589 base::TimeDelta::FromSeconds(timeout)); 590 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) { 591 use_pdf_ = false; 592 StartConvertToPWG(); 593 } else { 594 delegate_->OnPrivetPrintingError(this, 200); 595 } 596 597 return; 598 } 599 600 // If we've gotten this far, there are no errors, so we've effectively 601 // succeeded. 602 delegate_->OnPrivetPrintingDone(this); 603} 604 605void PrivetLocalPrintOperationImpl::OnCreatejobResponse( 606 bool has_error, 607 const base::DictionaryValue* value) { 608 if (has_error) { 609 delegate_->OnPrivetPrintingError(this, 200); 610 return; 611 } 612 613 // Try to get job ID from value. If not, jobid_ will be empty and we will use 614 // simple printing. 615 value->GetString(kPrivetKeyJobID, &jobid_); 616 617 DoSubmitdoc(); 618} 619 620void PrivetLocalPrintOperationImpl::OnPWGRasterConverted( 621 bool success, 622 const base::FilePath& pwg_file_path) { 623 if (!success) { 624 delegate_->OnPrivetPrintingError(this, -1); 625 return; 626 } 627 628 DCHECK(!pwg_file_path.empty()); 629 630 pwg_file_path_ = pwg_file_path; 631 StartPrinting(); 632} 633 634PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() { 635 return privet_client_; 636} 637 638void PrivetLocalPrintOperationImpl::OnError( 639 PrivetURLFetcher* fetcher, 640 PrivetURLFetcher::ErrorType error) { 641 delegate_->OnPrivetPrintingError(this, -1); 642} 643 644void PrivetLocalPrintOperationImpl::OnParsedJson( 645 PrivetURLFetcher* fetcher, 646 const base::DictionaryValue* value, 647 bool has_error) { 648 DCHECK(!current_response_.is_null()); 649 current_response_.Run(has_error, value); 650} 651 652void PrivetLocalPrintOperationImpl::OnNeedPrivetToken( 653 PrivetURLFetcher* fetcher, 654 const PrivetURLFetcher::TokenCallback& callback) { 655 privet_client_->RefreshPrivetToken(callback); 656} 657 658void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) { 659 DCHECK(!started_); 660 data_ = data; 661} 662 663void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) { 664 DCHECK(!started_); 665 ticket_ = ticket; 666} 667 668void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) { 669 DCHECK(!started_); 670 user_= user; 671} 672 673void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) { 674 DCHECK(!started_); 675 jobname_ = jobname; 676} 677 678void PrivetLocalPrintOperationImpl::SetOffline(bool offline) { 679 DCHECK(!started_); 680 offline_ = offline; 681} 682 683void PrivetLocalPrintOperationImpl::SetConversionSettings( 684 const printing::PdfRenderSettings& conversion_settings) { 685 DCHECK(!started_); 686 conversion_settings_ = conversion_settings; 687} 688 689void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( 690 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { 691 pwg_raster_converter_ = pwg_raster_converter.Pass(); 692} 693 694PrivetHTTPClientImpl::PrivetHTTPClientImpl( 695 const std::string& name, 696 const net::HostPortPair& host_port, 697 net::URLRequestContextGetter* request_context) 698 : name_(name), 699 fetcher_factory_(request_context), 700 host_port_(host_port) { 701} 702 703PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { 704} 705 706const base::DictionaryValue* PrivetHTTPClientImpl::GetCachedInfo() const { 707 return cached_info_.get(); 708} 709 710scoped_ptr<PrivetRegisterOperation> 711PrivetHTTPClientImpl::CreateRegisterOperation( 712 const std::string& user, 713 PrivetRegisterOperation::Delegate* delegate) { 714 return scoped_ptr<PrivetRegisterOperation>( 715 new PrivetRegisterOperationImpl(this, user, delegate)); 716} 717 718scoped_ptr<PrivetInfoOperation> PrivetHTTPClientImpl::CreateInfoOperation( 719 PrivetInfoOperation::Delegate* delegate) { 720 return scoped_ptr<PrivetInfoOperation>( 721 new PrivetInfoOperationImpl(this, delegate)); 722} 723 724scoped_ptr<PrivetCapabilitiesOperation> 725PrivetHTTPClientImpl::CreateCapabilitiesOperation( 726 PrivetCapabilitiesOperation::Delegate* delegate) { 727 return scoped_ptr<PrivetCapabilitiesOperation>( 728 new PrivetCapabilitiesOperationImpl(this, delegate)); 729} 730 731scoped_ptr<PrivetLocalPrintOperation> 732PrivetHTTPClientImpl::CreateLocalPrintOperation( 733 PrivetLocalPrintOperation::Delegate* delegate) { 734 return scoped_ptr<PrivetLocalPrintOperation>( 735 new PrivetLocalPrintOperationImpl(this, delegate)); 736} 737 738const std::string& PrivetHTTPClientImpl::GetName() { 739 return name_; 740} 741 742scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher( 743 const GURL& url, net::URLFetcher::RequestType request_type, 744 PrivetURLFetcher::Delegate* delegate) const { 745 GURL::Replacements replacements; 746 replacements.SetHostStr(host_port_.host()); 747 std::string port(base::IntToString(host_port_.port())); // Keep string alive. 748 replacements.SetPortStr(port); 749 GURL url2 = url.ReplaceComponents(replacements); 750 return fetcher_factory_.CreateURLFetcher(url.ReplaceComponents(replacements), 751 request_type, delegate); 752} 753 754void PrivetHTTPClientImpl::CacheInfo(const base::DictionaryValue* cached_info) { 755 cached_info_.reset(cached_info->DeepCopy()); 756 std::string token; 757 if (cached_info_->GetString(kPrivetInfoKeyToken, &token)) { 758 fetcher_factory_.set_token(token); 759 } 760} 761 762bool PrivetHTTPClientImpl::HasToken() const { 763 return fetcher_factory_.get_token() != ""; 764}; 765 766void PrivetHTTPClientImpl::RefreshPrivetToken( 767 const PrivetURLFetcher::TokenCallback& callback) { 768 token_callbacks_.push_back(callback); 769 770 if (!info_operation_) { 771 info_operation_ = CreateInfoOperation(this); 772 info_operation_->Start(); 773 } 774} 775 776void PrivetHTTPClientImpl::OnPrivetInfoDone( 777 PrivetInfoOperation* operation, 778 int http_code, 779 const base::DictionaryValue* value) { 780 info_operation_.reset(); 781 std::string token; 782 783 // If this does not succeed, token will be empty, and an empty string 784 // is our sentinel value, since empty X-Privet-Tokens are not allowed. 785 if (value) { 786 value->GetString(kPrivetInfoKeyToken, &token); 787 } 788 789 TokenCallbackVector token_callbacks; 790 token_callbacks_.swap(token_callbacks); 791 792 for (TokenCallbackVector::iterator i = token_callbacks.begin(); 793 i != token_callbacks.end(); i++) { 794 i->Run(token); 795 } 796} 797 798} // namespace local_discovery 799