privet_http_impl.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 "base/strings/stringprintf.h" 15#include "base/strings/utf_string_conversions.h" 16#include "chrome/browser/local_discovery/privet_constants.h" 17#include "components/cloud_devices/common/printer_description.h" 18#include "net/base/url_util.h" 19#include "printing/pwg_raster_settings.h" 20#include "printing/units.h" 21#include "ui/gfx/text_elider.h" 22#include "url/gurl.h" 23 24using namespace cloud_devices::printer; 25 26namespace cloud_print { 27extern const char kContentTypeJSON[]; 28} 29 30namespace local_discovery { 31 32namespace { 33const char kUrlPlaceHolder[] = "http://host/"; 34const char kPrivetRegisterActionArgName[] = "action"; 35const char kPrivetRegisterUserArgName[] = "user"; 36 37const char kPrivetURLKeyUserName[] = "user_name"; 38const char kPrivetURLKeyClientName[] = "client_name"; 39const char kPrivetURLKeyJobname[] = "job_name"; 40const char kPrivetURLKeyOffline[] = "offline"; 41const char kPrivetURLValueOffline[] = "1"; 42const char kPrivetURLValueClientName[] = "Chrome"; 43 44const char kPrivetContentTypePDF[] = "application/pdf"; 45const char kPrivetContentTypePWGRaster[] = "image/pwg-raster"; 46const char kPrivetContentTypeAny[] = "*/*"; 47 48const char kPrivetStorageListPath[] = "/privet/storage/list"; 49const char kPrivetStorageContentPath[] = "/privet/storage/content"; 50const char kPrivetStorageParamPathFormat[] = "path=%s"; 51 52const char kPrivetKeyJobID[] = "job_id"; 53 54const int kPrivetCancelationTimeoutSeconds = 3; 55 56const int kPrivetLocalPrintMaxRetries = 2; 57 58const int kPrivetLocalPrintDefaultTimeout = 5; 59 60const size_t kPrivetLocalPrintMaxJobNameLength = 64; 61 62GURL CreatePrivetURL(const std::string& path) { 63 GURL url(kUrlPlaceHolder); 64 GURL::Replacements replacements; 65 replacements.SetPathStr(path); 66 return url.ReplaceComponents(replacements); 67} 68 69GURL CreatePrivetRegisterURL(const std::string& action, 70 const std::string& user) { 71 GURL url = CreatePrivetURL(kPrivetRegisterPath); 72 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action); 73 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user); 74} 75 76GURL CreatePrivetParamURL(const std::string& path, 77 const std::string& query_params) { 78 GURL url(kUrlPlaceHolder); 79 GURL::Replacements replacements; 80 replacements.SetPathStr(path); 81 if (!query_params.empty()) { 82 replacements.SetQueryStr(query_params); 83 } 84 return url.ReplaceComponents(replacements); 85} 86 87} // namespace 88 89PrivetInfoOperationImpl::PrivetInfoOperationImpl( 90 PrivetHTTPClient* privet_client, 91 const PrivetJSONOperation::ResultCallback& callback) 92 : privet_client_(privet_client), callback_(callback) { 93} 94 95PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { 96} 97 98void PrivetInfoOperationImpl::Start() { 99 url_fetcher_ = privet_client_->CreateURLFetcher( 100 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this); 101 102 url_fetcher_->DoNotRetryOnTransientError(); 103 url_fetcher_->SendEmptyPrivetToken(); 104 105 url_fetcher_->Start(); 106} 107 108PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() { 109 return privet_client_; 110} 111 112void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher, 113 PrivetURLFetcher::ErrorType error) { 114 callback_.Run(NULL); 115} 116 117void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher, 118 const base::DictionaryValue* value, 119 bool has_error) { 120 callback_.Run(value); 121} 122 123PrivetRegisterOperationImpl::PrivetRegisterOperationImpl( 124 PrivetHTTPClient* privet_client, 125 const std::string& user, 126 PrivetRegisterOperation::Delegate* delegate) 127 : user_(user), 128 delegate_(delegate), 129 privet_client_(privet_client), 130 ongoing_(false) { 131} 132 133PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() { 134} 135 136void PrivetRegisterOperationImpl::Start() { 137 ongoing_ = true; 138 next_response_handler_ = 139 base::Bind(&PrivetRegisterOperationImpl::StartResponse, 140 base::Unretained(this)); 141 SendRequest(kPrivetActionStart); 142} 143 144void PrivetRegisterOperationImpl::Cancel() { 145 url_fetcher_.reset(); 146 147 if (ongoing_) { 148 // Owned by the message loop. 149 Cancelation* cancelation = new Cancelation(privet_client_, user_); 150 151 base::MessageLoop::current()->PostDelayedTask( 152 FROM_HERE, 153 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup, 154 base::Owned(cancelation)), 155 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds)); 156 157 ongoing_ = false; 158 } 159} 160 161void PrivetRegisterOperationImpl::CompleteRegistration() { 162 next_response_handler_ = 163 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse, 164 base::Unretained(this)); 165 SendRequest(kPrivetActionComplete); 166} 167 168PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() { 169 return privet_client_; 170} 171 172void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher, 173 PrivetURLFetcher::ErrorType error) { 174 ongoing_ = false; 175 int visible_http_code = -1; 176 FailureReason reason = FAILURE_NETWORK; 177 178 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) { 179 visible_http_code = fetcher->response_code(); 180 reason = FAILURE_HTTP_ERROR; 181 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) { 182 reason = FAILURE_MALFORMED_RESPONSE; 183 } else if (error == PrivetURLFetcher::TOKEN_ERROR) { 184 reason = FAILURE_TOKEN; 185 } else if (error == PrivetURLFetcher::RETRY_ERROR) { 186 reason = FAILURE_RETRY; 187 } 188 189 delegate_->OnPrivetRegisterError(this, 190 current_action_, 191 reason, 192 visible_http_code, 193 NULL); 194} 195 196void PrivetRegisterOperationImpl::OnParsedJson( 197 PrivetURLFetcher* fetcher, 198 const base::DictionaryValue* value, 199 bool has_error) { 200 if (has_error) { 201 std::string error; 202 value->GetString(kPrivetKeyError, &error); 203 204 ongoing_ = false; 205 delegate_->OnPrivetRegisterError(this, 206 current_action_, 207 FAILURE_JSON_ERROR, 208 fetcher->response_code(), 209 value); 210 return; 211 } 212 213 // TODO(noamsml): Match the user&action with the user&action in the object, 214 // and fail if different. 215 216 next_response_handler_.Run(*value); 217} 218 219void PrivetRegisterOperationImpl::OnNeedPrivetToken( 220 PrivetURLFetcher* fetcher, 221 const PrivetURLFetcher::TokenCallback& callback) { 222 privet_client_->RefreshPrivetToken(callback); 223} 224 225void PrivetRegisterOperationImpl::SendRequest(const std::string& action) { 226 current_action_ = action; 227 url_fetcher_ = privet_client_->CreateURLFetcher( 228 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this); 229 url_fetcher_->Start(); 230} 231 232void PrivetRegisterOperationImpl::StartResponse( 233 const base::DictionaryValue& value) { 234 next_response_handler_ = 235 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse, 236 base::Unretained(this)); 237 238 SendRequest(kPrivetActionGetClaimToken); 239} 240 241void PrivetRegisterOperationImpl::GetClaimTokenResponse( 242 const base::DictionaryValue& value) { 243 std::string claimUrl; 244 std::string claimToken; 245 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl); 246 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken); 247 if (got_url || got_token) { 248 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl)); 249 } else { 250 delegate_->OnPrivetRegisterError(this, 251 current_action_, 252 FAILURE_MALFORMED_RESPONSE, 253 -1, 254 NULL); 255 } 256} 257 258void PrivetRegisterOperationImpl::CompleteResponse( 259 const base::DictionaryValue& value) { 260 std::string id; 261 value.GetString(kPrivetKeyDeviceID, &id); 262 ongoing_ = false; 263 expected_id_ = id; 264 StartInfoOperation(); 265} 266 267void PrivetRegisterOperationImpl::OnPrivetInfoDone( 268 const base::DictionaryValue* value) { 269 // TODO(noamsml): Simplify error case and depracate HTTP error value in 270 // OnPrivetRegisterError. 271 if (!value) { 272 delegate_->OnPrivetRegisterError(this, 273 kPrivetActionNameInfo, 274 FAILURE_NETWORK, 275 -1, 276 NULL); 277 return; 278 } 279 280 if (!value->HasKey(kPrivetInfoKeyID)) { 281 if (value->HasKey(kPrivetKeyError)) { 282 delegate_->OnPrivetRegisterError(this, 283 kPrivetActionNameInfo, 284 FAILURE_JSON_ERROR, 285 -1, 286 value); 287 } else { 288 delegate_->OnPrivetRegisterError(this, 289 kPrivetActionNameInfo, 290 FAILURE_MALFORMED_RESPONSE, 291 -1, 292 NULL); 293 } 294 return; 295 } 296 297 std::string id; 298 299 if (!value->GetString(kPrivetInfoKeyID, &id) || 300 id != expected_id_) { 301 delegate_->OnPrivetRegisterError(this, 302 kPrivetActionNameInfo, 303 FAILURE_MALFORMED_RESPONSE, 304 -1, 305 NULL); 306 } else { 307 delegate_->OnPrivetRegisterDone(this, id); 308 } 309} 310 311void PrivetRegisterOperationImpl::StartInfoOperation() { 312 info_operation_ = privet_client_->CreateInfoOperation( 313 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone, 314 base::Unretained(this))); 315 info_operation_->Start(); 316} 317 318PrivetRegisterOperationImpl::Cancelation::Cancelation( 319 PrivetHTTPClient* privet_client, 320 const std::string& user) { 321 url_fetcher_ = 322 privet_client->CreateURLFetcher( 323 CreatePrivetRegisterURL(kPrivetActionCancel, user), 324 net::URLFetcher::POST, this); 325 url_fetcher_->DoNotRetryOnTransientError(); 326 url_fetcher_->Start(); 327} 328 329PrivetRegisterOperationImpl::Cancelation::~Cancelation() { 330} 331 332void PrivetRegisterOperationImpl::Cancelation::OnError( 333 PrivetURLFetcher* fetcher, 334 PrivetURLFetcher::ErrorType error) { 335} 336 337void PrivetRegisterOperationImpl::Cancelation::OnParsedJson( 338 PrivetURLFetcher* fetcher, 339 const base::DictionaryValue* value, 340 bool has_error) { 341} 342 343void PrivetRegisterOperationImpl::Cancelation::Cleanup() { 344 // Nothing needs to be done, as base::Owned will delete this object, 345 // this callback is just here to pass ownership of the Cancelation to 346 // the message loop. 347} 348 349PrivetJSONOperationImpl::PrivetJSONOperationImpl( 350 PrivetHTTPClient* privet_client, 351 const std::string& path, 352 const std::string& query_params, 353 const PrivetJSONOperation::ResultCallback& callback) 354 : privet_client_(privet_client), 355 path_(path), 356 query_params_(query_params), 357 callback_(callback) { 358} 359 360PrivetJSONOperationImpl::~PrivetJSONOperationImpl() { 361} 362 363void PrivetJSONOperationImpl::Start() { 364 url_fetcher_ = privet_client_->CreateURLFetcher( 365 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this); 366 url_fetcher_->DoNotRetryOnTransientError(); 367 url_fetcher_->Start(); 368} 369 370PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() { 371 return privet_client_; 372} 373 374void PrivetJSONOperationImpl::OnError( 375 PrivetURLFetcher* fetcher, 376 PrivetURLFetcher::ErrorType error) { 377 callback_.Run(NULL); 378} 379 380void PrivetJSONOperationImpl::OnParsedJson( 381 PrivetURLFetcher* fetcher, 382 const base::DictionaryValue* value, 383 bool has_error) { 384 callback_.Run(value); 385} 386 387void PrivetJSONOperationImpl::OnNeedPrivetToken( 388 PrivetURLFetcher* fetcher, 389 const PrivetURLFetcher::TokenCallback& callback) { 390 privet_client_->RefreshPrivetToken(callback); 391} 392 393PrivetDataReadOperationImpl::PrivetDataReadOperationImpl( 394 PrivetHTTPClient* privet_client, 395 const std::string& path, 396 const std::string& query_params, 397 const PrivetDataReadOperation::ResultCallback& callback) 398 : privet_client_(privet_client), 399 path_(path), 400 query_params_(query_params), 401 callback_(callback), 402 has_range_(false), 403 save_to_file_(false) { 404} 405 406PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() { 407} 408 409 410void PrivetDataReadOperationImpl::Start() { 411 url_fetcher_ = privet_client_->CreateURLFetcher( 412 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this); 413 url_fetcher_->DoNotRetryOnTransientError(); 414 415 if (has_range_) { 416 url_fetcher_->SetByteRange(range_start_, range_end_); 417 } 418 419 if (save_to_file_) { 420 url_fetcher_->SaveResponseToFile(); 421 } 422 423 url_fetcher_->Start(); 424} 425 426void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) { 427 has_range_ = true; 428 range_start_ = range_start; 429 range_end_ = range_end; 430} 431 432void PrivetDataReadOperationImpl::SaveDataToFile() { 433 save_to_file_ = false; 434} 435 436PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() { 437 return privet_client_; 438} 439 440void PrivetDataReadOperationImpl::OnError( 441 PrivetURLFetcher* fetcher, 442 PrivetURLFetcher::ErrorType error) { 443 callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath()); 444} 445 446void PrivetDataReadOperationImpl::OnParsedJson( 447 PrivetURLFetcher* fetcher, 448 const base::DictionaryValue* value, 449 bool has_error) { 450 NOTREACHED(); 451} 452 453void PrivetDataReadOperationImpl::OnNeedPrivetToken( 454 PrivetURLFetcher* fetcher, 455 const PrivetURLFetcher::TokenCallback& callback) { 456 privet_client_->RefreshPrivetToken(callback); 457} 458 459bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher* fetcher, 460 bool is_file, 461 const std::string& data_str, 462 const base::FilePath& file_path) { 463 ResponseType type = (is_file) ? RESPONSE_TYPE_FILE : RESPONSE_TYPE_STRING; 464 callback_.Run(type, data_str, file_path); 465 return true; 466} 467 468PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl( 469 PrivetHTTPClient* privet_client, 470 PrivetLocalPrintOperation::Delegate* delegate) 471 : privet_client_(privet_client), 472 delegate_(delegate), 473 use_pdf_(false), 474 has_extended_workflow_(false), 475 started_(false), 476 offline_(false), 477 dpi_(printing::kDefaultPdfDpi), 478 invalid_job_retries_(0), 479 weak_factory_(this) { 480} 481 482PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() { 483} 484 485void PrivetLocalPrintOperationImpl::Start() { 486 DCHECK(!started_); 487 488 // We need to get the /info response so we can know which APIs are available. 489 // TODO(noamsml): Use cached info when available. 490 info_operation_ = privet_client_->CreateInfoOperation( 491 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone, 492 base::Unretained(this))); 493 info_operation_->Start(); 494 495 started_ = true; 496} 497 498void PrivetLocalPrintOperationImpl::OnPrivetInfoDone( 499 const base::DictionaryValue* value) { 500 if (value && !value->HasKey(kPrivetKeyError)) { 501 has_extended_workflow_ = false; 502 bool has_printing = false; 503 504 const base::ListValue* api_list; 505 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) { 506 for (size_t i = 0; i < api_list->GetSize(); i++) { 507 std::string api; 508 api_list->GetString(i, &api); 509 if (api == kPrivetSubmitdocPath) { 510 has_printing = true; 511 } else if (api == kPrivetCreatejobPath) { 512 has_extended_workflow_ = true; 513 } 514 } 515 } 516 517 if (!has_printing) { 518 delegate_->OnPrivetPrintingError(this, -1); 519 return; 520 } 521 522 StartInitialRequest(); 523 } else { 524 delegate_->OnPrivetPrintingError(this, -1); 525 } 526} 527 528void PrivetLocalPrintOperationImpl::StartInitialRequest() { 529 use_pdf_ = false; 530 ContentTypesCapability content_types; 531 if (content_types.LoadFrom(capabilities_)) { 532 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) || 533 content_types.Contains(kPrivetContentTypeAny); 534 } 535 536 if (use_pdf_) { 537 StartPrinting(); 538 } else { 539 DpiCapability dpis; 540 if (dpis.LoadFrom(capabilities_)) { 541 dpi_ = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical); 542 } 543 StartConvertToPWG(); 544 } 545} 546 547void PrivetLocalPrintOperationImpl::DoCreatejob() { 548 current_response_ = base::Bind( 549 &PrivetLocalPrintOperationImpl::OnCreatejobResponse, 550 base::Unretained(this)); 551 552 url_fetcher_= privet_client_->CreateURLFetcher( 553 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this); 554 url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON, 555 ticket_.ToString()); 556 557 url_fetcher_->Start(); 558} 559 560void PrivetLocalPrintOperationImpl::DoSubmitdoc() { 561 current_response_ = base::Bind( 562 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse, 563 base::Unretained(this)); 564 565 GURL url = CreatePrivetURL(kPrivetSubmitdocPath); 566 567 url = net::AppendQueryParameter(url, 568 kPrivetURLKeyClientName, 569 kPrivetURLValueClientName); 570 571 if (!user_.empty()) { 572 url = net::AppendQueryParameter(url, 573 kPrivetURLKeyUserName, 574 user_); 575 } 576 577 base::string16 shortened_jobname; 578 579 gfx::ElideString(base::UTF8ToUTF16(jobname_), 580 kPrivetLocalPrintMaxJobNameLength, 581 &shortened_jobname); 582 583 if (!jobname_.empty()) { 584 url = net::AppendQueryParameter( 585 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname)); 586 } 587 588 if (!jobid_.empty()) { 589 url = net::AppendQueryParameter(url, 590 kPrivetKeyJobID, 591 jobid_); 592 } 593 594 if (offline_) { 595 url = net::AppendQueryParameter(url, 596 kPrivetURLKeyOffline, 597 kPrivetURLValueOffline); 598 } 599 600 url_fetcher_= privet_client_->CreateURLFetcher( 601 url, net::URLFetcher::POST, this); 602 603 if (!use_pdf_) { 604 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster, 605 pwg_file_path_); 606 } else { 607 // TODO(noamsml): Move to file-based upload data? 608 std::string data_str((const char*)data_->front(), data_->size()); 609 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str); 610 } 611 612 url_fetcher_->Start(); 613} 614 615void PrivetLocalPrintOperationImpl::StartPrinting() { 616 if (has_extended_workflow_ && jobid_.empty()) { 617 DoCreatejob(); 618 } else { 619 DoSubmitdoc(); 620 } 621} 622 623void PrivetLocalPrintOperationImpl::FillPwgRasterSettings( 624 printing::PwgRasterSettings* transform_settings) { 625 PwgRasterConfigCapability raster_capability; 626 // If the raster capability fails to load, raster_capability will contain 627 // the default value. 628 raster_capability.LoadFrom(capabilities_); 629 630 DuplexTicketItem duplex_item; 631 DuplexType duplex_value = NO_DUPLEX; 632 633 DocumentSheetBack document_sheet_back = 634 raster_capability.value().document_sheet_back; 635 636 if (duplex_item.LoadFrom(ticket_)) { 637 duplex_value = duplex_item.value(); 638 } 639 640 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL; 641 switch (duplex_value) { 642 case NO_DUPLEX: 643 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL; 644 break; 645 case LONG_EDGE: 646 if (document_sheet_back == ROTATED) { 647 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180; 648 } else if (document_sheet_back == FLIPPED) { 649 transform_settings->odd_page_transform = 650 printing::TRANSFORM_FLIP_VERTICAL; 651 } 652 break; 653 case SHORT_EDGE: 654 if (document_sheet_back == MANUAL_TUMBLE) { 655 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180; 656 } else if (document_sheet_back == FLIPPED) { 657 transform_settings->odd_page_transform = 658 printing::TRANSFORM_FLIP_HORIZONTAL; 659 } 660 } 661 662 transform_settings->rotate_all_pages = 663 raster_capability.value().rotate_all_pages; 664 665 transform_settings->reverse_page_order = 666 raster_capability.value().reverse_order_streaming; 667} 668 669void PrivetLocalPrintOperationImpl::StartConvertToPWG() { 670 printing::PwgRasterSettings transform_settings; 671 672 FillPwgRasterSettings(&transform_settings); 673 674 if (!pwg_raster_converter_) 675 pwg_raster_converter_ = PWGRasterConverter::CreateDefault(); 676 677 double scale = dpi_; 678 scale /= printing::kPointsPerInch; 679 // Make vertical rectangle to optimize streaming to printer. Fix orientation 680 // by autorotate. 681 gfx::Rect area(std::min(page_size_.width(), page_size_.height()) * scale, 682 std::max(page_size_.width(), page_size_.height()) * scale); 683 pwg_raster_converter_->Start( 684 data_, 685 printing::PdfRenderSettings(area, dpi_, true), 686 transform_settings, 687 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted, 688 base::Unretained(this))); 689} 690 691void PrivetLocalPrintOperationImpl::OnSubmitdocResponse( 692 bool has_error, 693 const base::DictionaryValue* value) { 694 std::string error; 695 // This error is only relevant in the case of extended workflow: 696 // If the print job ID is invalid, retry createjob and submitdoc, 697 // rather than simply retrying the current request. 698 if (has_error && value->GetString(kPrivetKeyError, &error)) { 699 if (has_extended_workflow_ && 700 error == kPrivetErrorInvalidPrintJob && 701 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) { 702 invalid_job_retries_++; 703 704 int timeout = kPrivetLocalPrintDefaultTimeout; 705 value->GetInteger(kPrivetKeyTimeout, &timeout); 706 707 double random_scaling_factor = 708 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition; 709 710 timeout = static_cast<int>(timeout * random_scaling_factor); 711 712 timeout = std::max(timeout, kPrivetMinimumTimeout); 713 714 base::MessageLoop::current()->PostDelayedTask( 715 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob, 716 weak_factory_.GetWeakPtr()), 717 base::TimeDelta::FromSeconds(timeout)); 718 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) { 719 use_pdf_ = false; 720 StartConvertToPWG(); 721 } else { 722 delegate_->OnPrivetPrintingError(this, 200); 723 } 724 725 return; 726 } 727 728 // If we've gotten this far, there are no errors, so we've effectively 729 // succeeded. 730 delegate_->OnPrivetPrintingDone(this); 731} 732 733void PrivetLocalPrintOperationImpl::OnCreatejobResponse( 734 bool has_error, 735 const base::DictionaryValue* value) { 736 if (has_error) { 737 delegate_->OnPrivetPrintingError(this, 200); 738 return; 739 } 740 741 // Try to get job ID from value. If not, jobid_ will be empty and we will use 742 // simple printing. 743 value->GetString(kPrivetKeyJobID, &jobid_); 744 745 DoSubmitdoc(); 746} 747 748void PrivetLocalPrintOperationImpl::OnPWGRasterConverted( 749 bool success, 750 const base::FilePath& pwg_file_path) { 751 if (!success) { 752 delegate_->OnPrivetPrintingError(this, -1); 753 return; 754 } 755 756 DCHECK(!pwg_file_path.empty()); 757 758 pwg_file_path_ = pwg_file_path; 759 StartPrinting(); 760} 761 762PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() { 763 return privet_client_; 764} 765 766void PrivetLocalPrintOperationImpl::OnError( 767 PrivetURLFetcher* fetcher, 768 PrivetURLFetcher::ErrorType error) { 769 delegate_->OnPrivetPrintingError(this, -1); 770} 771 772void PrivetLocalPrintOperationImpl::OnParsedJson( 773 PrivetURLFetcher* fetcher, 774 const base::DictionaryValue* value, 775 bool has_error) { 776 DCHECK(!current_response_.is_null()); 777 current_response_.Run(has_error, value); 778} 779 780void PrivetLocalPrintOperationImpl::OnNeedPrivetToken( 781 PrivetURLFetcher* fetcher, 782 const PrivetURLFetcher::TokenCallback& callback) { 783 privet_client_->RefreshPrivetToken(callback); 784} 785 786void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) { 787 DCHECK(!started_); 788 data_ = data; 789} 790 791void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) { 792 DCHECK(!started_); 793 ticket_.InitFromString(ticket); 794} 795 796void PrivetLocalPrintOperationImpl::SetCapabilities( 797 const std::string& capabilities) { 798 DCHECK(!started_); 799 capabilities_.InitFromString(capabilities); 800} 801 802void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) { 803 DCHECK(!started_); 804 user_= user; 805} 806 807void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) { 808 DCHECK(!started_); 809 jobname_ = jobname; 810} 811 812void PrivetLocalPrintOperationImpl::SetOffline(bool offline) { 813 DCHECK(!started_); 814 offline_ = offline; 815} 816 817void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) { 818 DCHECK(!started_); 819 page_size_ = page_size; 820} 821 822void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( 823 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { 824 pwg_raster_converter_ = pwg_raster_converter.Pass(); 825} 826 827PrivetHTTPClientImpl::PrivetHTTPClientImpl( 828 const std::string& name, 829 const net::HostPortPair& host_port, 830 net::URLRequestContextGetter* request_context) 831 : name_(name), request_context_(request_context), host_port_(host_port) {} 832 833PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { 834} 835 836const std::string& PrivetHTTPClientImpl::GetName() { 837 return name_; 838} 839 840scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation( 841 const PrivetJSONOperation::ResultCallback& callback) { 842 return scoped_ptr<PrivetJSONOperation>( 843 new PrivetInfoOperationImpl(this, callback)); 844} 845 846scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher( 847 const GURL& url, 848 net::URLFetcher::RequestType request_type, 849 PrivetURLFetcher::Delegate* delegate) { 850 GURL::Replacements replacements; 851 replacements.SetHostStr(host_port_.host()); 852 std::string port(base::IntToString(host_port_.port())); // Keep string alive. 853 replacements.SetPortStr(port); 854 return scoped_ptr<PrivetURLFetcher>( 855 new PrivetURLFetcher(url.ReplaceComponents(replacements), 856 request_type, 857 request_context_.get(), 858 delegate)); 859} 860 861void PrivetHTTPClientImpl::RefreshPrivetToken( 862 const PrivetURLFetcher::TokenCallback& callback) { 863 token_callbacks_.push_back(callback); 864 865 if (!info_operation_) { 866 info_operation_ = CreateInfoOperation( 867 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone, 868 base::Unretained(this))); 869 info_operation_->Start(); 870 } 871} 872 873void PrivetHTTPClientImpl::OnPrivetInfoDone( 874 const base::DictionaryValue* value) { 875 info_operation_.reset(); 876 std::string token; 877 878 // If this does not succeed, token will be empty, and an empty string 879 // is our sentinel value, since empty X-Privet-Tokens are not allowed. 880 if (value) { 881 value->GetString(kPrivetInfoKeyToken, &token); 882 } 883 884 TokenCallbackVector token_callbacks; 885 token_callbacks_.swap(token_callbacks); 886 887 for (TokenCallbackVector::iterator i = token_callbacks.begin(); 888 i != token_callbacks.end(); i++) { 889 i->Run(token); 890 } 891} 892 893PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl( 894 scoped_ptr<PrivetHTTPClient> info_client) 895 : info_client_(info_client.Pass()) { 896} 897 898PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() { 899} 900 901const std::string& PrivetV1HTTPClientImpl::GetName() { 902 return info_client()->GetName(); 903} 904 905scoped_ptr<PrivetJSONOperation> PrivetV1HTTPClientImpl::CreateInfoOperation( 906 const PrivetJSONOperation::ResultCallback& callback) { 907 return info_client()->CreateInfoOperation(callback); 908} 909 910scoped_ptr<PrivetRegisterOperation> 911PrivetV1HTTPClientImpl::CreateRegisterOperation( 912 const std::string& user, 913 PrivetRegisterOperation::Delegate* delegate) { 914 return scoped_ptr<PrivetRegisterOperation>( 915 new PrivetRegisterOperationImpl(info_client(), user, delegate)); 916} 917 918scoped_ptr<PrivetJSONOperation> 919PrivetV1HTTPClientImpl::CreateCapabilitiesOperation( 920 const PrivetJSONOperation::ResultCallback& callback) { 921 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl( 922 info_client(), kPrivetCapabilitiesPath, "", callback)); 923} 924 925scoped_ptr<PrivetLocalPrintOperation> 926PrivetV1HTTPClientImpl::CreateLocalPrintOperation( 927 PrivetLocalPrintOperation::Delegate* delegate) { 928 return scoped_ptr<PrivetLocalPrintOperation>( 929 new PrivetLocalPrintOperationImpl(info_client(), delegate)); 930} 931 932scoped_ptr<PrivetJSONOperation> 933PrivetV1HTTPClientImpl::CreateStorageListOperation( 934 const std::string& path, 935 const PrivetJSONOperation::ResultCallback& callback) { 936 std::string url_param = 937 base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str()); 938 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl( 939 info_client(), kPrivetStorageListPath, url_param, callback)); 940} 941 942scoped_ptr<PrivetDataReadOperation> 943PrivetV1HTTPClientImpl::CreateStorageReadOperation( 944 const std::string& path, 945 const PrivetDataReadOperation::ResultCallback& callback) { 946 std::string url_param = 947 base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str()); 948 return scoped_ptr<PrivetDataReadOperation>(new PrivetDataReadOperationImpl( 949 info_client(), kPrivetStorageContentPath, url_param, callback)); 950} 951 952PrivetV3HTTPClientImpl::PrivetV3HTTPClientImpl( 953 scoped_ptr<PrivetHTTPClient> info_client) 954 : info_client_(info_client.Pass()) { 955} 956 957PrivetV3HTTPClientImpl::~PrivetV3HTTPClientImpl() { 958} 959 960const std::string& PrivetV3HTTPClientImpl::GetName() { 961 return info_client()->GetName(); 962} 963 964scoped_ptr<PrivetJSONOperation> PrivetV3HTTPClientImpl::CreateInfoOperation( 965 const PrivetJSONOperation::ResultCallback& callback) { 966 return info_client()->CreateInfoOperation(callback); 967} 968 969} // namespace local_discovery 970