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 18 namespace local_discovery { 19 20 namespace { 21 const char kUrlPlaceHolder[] = "http://host/"; 22 const char kPrivetRegisterActionArgName[] = "action"; 23 const char kPrivetRegisterUserArgName[] = "user"; 24 25 const char kPrivetURLKeyUserName[] = "user_name"; 26 const char kPrivetURLKeyClientName[] = "client_name"; 27 const char kPrivetURLKeyJobname[] = "job_name"; 28 const char kPrivetURLKeyOffline[] = "offline"; 29 const char kPrivetURLValueOffline[] = "1"; 30 const char kPrivetURLValueClientName[] = "Chrome"; 31 32 const char kPrivetContentTypePDF[] = "application/pdf"; 33 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster"; 34 const char kPrivetContentTypeAny[] = "*/*"; 35 const char kPrivetContentTypeCJT[] = "application/json"; 36 37 const char kPrivetCDDKeySupportedContentTypes[] = 38 "printer.supported_content_type"; 39 40 const char kPrivetCDDKeyContentType[] = "content_type"; 41 42 const char kPrivetKeyJobID[] = "job_id"; 43 44 const int kPrivetCancelationTimeoutSeconds = 3; 45 46 const int kPrivetLocalPrintMaxRetries = 2; 47 48 const int kPrivetLocalPrintDefaultTimeout = 5; 49 50 GURL CreatePrivetURL(const std::string& path) { 51 GURL url(kUrlPlaceHolder); 52 GURL::Replacements replacements; 53 replacements.SetPathStr(path); 54 return url.ReplaceComponents(replacements); 55 } 56 57 GURL 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 66 PrivetInfoOperationImpl::PrivetInfoOperationImpl( 67 PrivetHTTPClientImpl* privet_client, 68 PrivetInfoOperation::Delegate* delegate) 69 : privet_client_(privet_client), delegate_(delegate) { 70 } 71 72 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { 73 } 74 75 void 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 85 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() { 86 return privet_client_; 87 } 88 89 void 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 98 void 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 106 PrivetRegisterOperationImpl::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 114 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() { 115 } 116 117 void PrivetRegisterOperationImpl::Start() { 118 ongoing_ = true; 119 next_response_handler_ = 120 base::Bind(&PrivetRegisterOperationImpl::StartResponse, 121 base::Unretained(this)); 122 SendRequest(kPrivetActionStart); 123 } 124 125 void 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 142 void PrivetRegisterOperationImpl::CompleteRegistration() { 143 next_response_handler_ = 144 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse, 145 base::Unretained(this)); 146 SendRequest(kPrivetActionComplete); 147 } 148 149 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() { 150 return privet_client_; 151 } 152 153 void 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 177 void 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 200 void PrivetRegisterOperationImpl::OnNeedPrivetToken( 201 PrivetURLFetcher* fetcher, 202 const PrivetURLFetcher::TokenCallback& callback) { 203 privet_client_->RefreshPrivetToken(callback); 204 } 205 206 void 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 213 void 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 222 void 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 239 void 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 248 void 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 293 void PrivetRegisterOperationImpl::StartInfoOperation() { 294 info_operation_ = privet_client_->CreateInfoOperation(this); 295 info_operation_->Start(); 296 } 297 298 PrivetRegisterOperationImpl::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 309 PrivetRegisterOperationImpl::Cancelation::~Cancelation() { 310 } 311 312 void PrivetRegisterOperationImpl::Cancelation::OnError( 313 PrivetURLFetcher* fetcher, 314 PrivetURLFetcher::ErrorType error) { 315 } 316 317 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson( 318 PrivetURLFetcher* fetcher, 319 const base::DictionaryValue* value, 320 bool has_error) { 321 } 322 323 void 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 329 PrivetCapabilitiesOperationImpl::PrivetCapabilitiesOperationImpl( 330 PrivetHTTPClientImpl* privet_client, 331 PrivetCapabilitiesOperation::Delegate* delegate) 332 : privet_client_(privet_client), delegate_(delegate) { 333 } 334 335 PrivetCapabilitiesOperationImpl::~PrivetCapabilitiesOperationImpl() { 336 } 337 338 void 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 345 PrivetHTTPClient* PrivetCapabilitiesOperationImpl::GetHTTPClient() { 346 return privet_client_; 347 } 348 349 void PrivetCapabilitiesOperationImpl::OnError( 350 PrivetURLFetcher* fetcher, 351 PrivetURLFetcher::ErrorType error) { 352 delegate_->OnPrivetCapabilities(this, -1, NULL); 353 } 354 355 void PrivetCapabilitiesOperationImpl::OnParsedJson( 356 PrivetURLFetcher* fetcher, 357 const base::DictionaryValue* value, 358 bool has_error) { 359 delegate_->OnPrivetCapabilities(this, fetcher->response_code(), value); 360 } 361 362 void PrivetCapabilitiesOperationImpl::OnNeedPrivetToken( 363 PrivetURLFetcher* fetcher, 364 const PrivetURLFetcher::TokenCallback& callback) { 365 privet_client_->RefreshPrivetToken(callback); 366 } 367 368 PrivetLocalPrintOperationImpl::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 377 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() { 378 } 379 380 void 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 391 void 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 426 void 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 437 void 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 449 void 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 461 void 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 511 void PrivetLocalPrintOperationImpl::StartPrinting() { 512 if (has_extended_workflow_ && !ticket_.empty() && jobid_.empty()) { 513 DoCreatejob(); 514 } else { 515 DoSubmitdoc(); 516 } 517 } 518 519 void 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 529 void 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 563 void 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 605 void 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 620 void 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 634 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() { 635 return privet_client_; 636 } 637 638 void PrivetLocalPrintOperationImpl::OnError( 639 PrivetURLFetcher* fetcher, 640 PrivetURLFetcher::ErrorType error) { 641 delegate_->OnPrivetPrintingError(this, -1); 642 } 643 644 void 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 652 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken( 653 PrivetURLFetcher* fetcher, 654 const PrivetURLFetcher::TokenCallback& callback) { 655 privet_client_->RefreshPrivetToken(callback); 656 } 657 658 void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) { 659 DCHECK(!started_); 660 data_ = data; 661 } 662 663 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) { 664 DCHECK(!started_); 665 ticket_ = ticket; 666 } 667 668 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) { 669 DCHECK(!started_); 670 user_= user; 671 } 672 673 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) { 674 DCHECK(!started_); 675 jobname_ = jobname; 676 } 677 678 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) { 679 DCHECK(!started_); 680 offline_ = offline; 681 } 682 683 void PrivetLocalPrintOperationImpl::SetConversionSettings( 684 const printing::PdfRenderSettings& conversion_settings) { 685 DCHECK(!started_); 686 conversion_settings_ = conversion_settings; 687 } 688 689 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( 690 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { 691 pwg_raster_converter_ = pwg_raster_converter.Pass(); 692 } 693 694 PrivetHTTPClientImpl::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 703 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { 704 } 705 706 const base::DictionaryValue* PrivetHTTPClientImpl::GetCachedInfo() const { 707 return cached_info_.get(); 708 } 709 710 scoped_ptr<PrivetRegisterOperation> 711 PrivetHTTPClientImpl::CreateRegisterOperation( 712 const std::string& user, 713 PrivetRegisterOperation::Delegate* delegate) { 714 return scoped_ptr<PrivetRegisterOperation>( 715 new PrivetRegisterOperationImpl(this, user, delegate)); 716 } 717 718 scoped_ptr<PrivetInfoOperation> PrivetHTTPClientImpl::CreateInfoOperation( 719 PrivetInfoOperation::Delegate* delegate) { 720 return scoped_ptr<PrivetInfoOperation>( 721 new PrivetInfoOperationImpl(this, delegate)); 722 } 723 724 scoped_ptr<PrivetCapabilitiesOperation> 725 PrivetHTTPClientImpl::CreateCapabilitiesOperation( 726 PrivetCapabilitiesOperation::Delegate* delegate) { 727 return scoped_ptr<PrivetCapabilitiesOperation>( 728 new PrivetCapabilitiesOperationImpl(this, delegate)); 729 } 730 731 scoped_ptr<PrivetLocalPrintOperation> 732 PrivetHTTPClientImpl::CreateLocalPrintOperation( 733 PrivetLocalPrintOperation::Delegate* delegate) { 734 return scoped_ptr<PrivetLocalPrintOperation>( 735 new PrivetLocalPrintOperationImpl(this, delegate)); 736 } 737 738 const std::string& PrivetHTTPClientImpl::GetName() { 739 return name_; 740 } 741 742 scoped_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 754 void 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 762 bool PrivetHTTPClientImpl::HasToken() const { 763 return fetcher_factory_.get_token() != ""; 764 }; 765 766 void 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 776 void 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