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 24 using namespace cloud_devices::printer; 25 26 namespace cloud_print { 27 extern const char kContentTypeJSON[]; 28 } 29 30 namespace local_discovery { 31 32 namespace { 33 const char kUrlPlaceHolder[] = "http://host/"; 34 const char kPrivetRegisterActionArgName[] = "action"; 35 const char kPrivetRegisterUserArgName[] = "user"; 36 37 const char kPrivetURLKeyUserName[] = "user_name"; 38 const char kPrivetURLKeyClientName[] = "client_name"; 39 const char kPrivetURLKeyJobname[] = "job_name"; 40 const char kPrivetURLKeyOffline[] = "offline"; 41 const char kPrivetURLValueOffline[] = "1"; 42 const char kPrivetURLValueClientName[] = "Chrome"; 43 44 const char kPrivetContentTypePDF[] = "application/pdf"; 45 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster"; 46 const char kPrivetContentTypeAny[] = "*/*"; 47 48 const char kPrivetStorageListPath[] = "/privet/storage/list"; 49 const char kPrivetStorageContentPath[] = "/privet/storage/content"; 50 const char kPrivetStorageParamPathFormat[] = "path=%s"; 51 52 const char kPrivetKeyJobID[] = "job_id"; 53 54 const int kPrivetCancelationTimeoutSeconds = 3; 55 56 const int kPrivetLocalPrintMaxRetries = 2; 57 58 const int kPrivetLocalPrintDefaultTimeout = 5; 59 60 const size_t kPrivetLocalPrintMaxJobNameLength = 64; 61 62 GURL CreatePrivetURL(const std::string& path) { 63 GURL url(kUrlPlaceHolder); 64 GURL::Replacements replacements; 65 replacements.SetPathStr(path); 66 return url.ReplaceComponents(replacements); 67 } 68 69 GURL 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 76 GURL 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 89 PrivetInfoOperationImpl::PrivetInfoOperationImpl( 90 PrivetHTTPClient* privet_client, 91 const PrivetJSONOperation::ResultCallback& callback) 92 : privet_client_(privet_client), callback_(callback) { 93 } 94 95 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { 96 } 97 98 void 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 108 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() { 109 return privet_client_; 110 } 111 112 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher, 113 PrivetURLFetcher::ErrorType error) { 114 callback_.Run(NULL); 115 } 116 117 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher, 118 const base::DictionaryValue* value, 119 bool has_error) { 120 callback_.Run(value); 121 } 122 123 PrivetRegisterOperationImpl::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 133 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() { 134 } 135 136 void PrivetRegisterOperationImpl::Start() { 137 ongoing_ = true; 138 next_response_handler_ = 139 base::Bind(&PrivetRegisterOperationImpl::StartResponse, 140 base::Unretained(this)); 141 SendRequest(kPrivetActionStart); 142 } 143 144 void 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 161 void PrivetRegisterOperationImpl::CompleteRegistration() { 162 next_response_handler_ = 163 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse, 164 base::Unretained(this)); 165 SendRequest(kPrivetActionComplete); 166 } 167 168 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() { 169 return privet_client_; 170 } 171 172 void 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 196 void 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 219 void PrivetRegisterOperationImpl::OnNeedPrivetToken( 220 PrivetURLFetcher* fetcher, 221 const PrivetURLFetcher::TokenCallback& callback) { 222 privet_client_->RefreshPrivetToken(callback); 223 } 224 225 void 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 232 void 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 241 void 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 258 void 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 267 void 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 311 void PrivetRegisterOperationImpl::StartInfoOperation() { 312 info_operation_ = privet_client_->CreateInfoOperation( 313 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone, 314 base::Unretained(this))); 315 info_operation_->Start(); 316 } 317 318 PrivetRegisterOperationImpl::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 329 PrivetRegisterOperationImpl::Cancelation::~Cancelation() { 330 } 331 332 void PrivetRegisterOperationImpl::Cancelation::OnError( 333 PrivetURLFetcher* fetcher, 334 PrivetURLFetcher::ErrorType error) { 335 } 336 337 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson( 338 PrivetURLFetcher* fetcher, 339 const base::DictionaryValue* value, 340 bool has_error) { 341 } 342 343 void 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 349 PrivetJSONOperationImpl::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 360 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() { 361 } 362 363 void 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 370 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() { 371 return privet_client_; 372 } 373 374 void PrivetJSONOperationImpl::OnError( 375 PrivetURLFetcher* fetcher, 376 PrivetURLFetcher::ErrorType error) { 377 callback_.Run(NULL); 378 } 379 380 void PrivetJSONOperationImpl::OnParsedJson( 381 PrivetURLFetcher* fetcher, 382 const base::DictionaryValue* value, 383 bool has_error) { 384 callback_.Run(value); 385 } 386 387 void PrivetJSONOperationImpl::OnNeedPrivetToken( 388 PrivetURLFetcher* fetcher, 389 const PrivetURLFetcher::TokenCallback& callback) { 390 privet_client_->RefreshPrivetToken(callback); 391 } 392 393 PrivetDataReadOperationImpl::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 406 PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() { 407 } 408 409 410 void 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 426 void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) { 427 has_range_ = true; 428 range_start_ = range_start; 429 range_end_ = range_end; 430 } 431 432 void PrivetDataReadOperationImpl::SaveDataToFile() { 433 save_to_file_ = false; 434 } 435 436 PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() { 437 return privet_client_; 438 } 439 440 void PrivetDataReadOperationImpl::OnError( 441 PrivetURLFetcher* fetcher, 442 PrivetURLFetcher::ErrorType error) { 443 callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath()); 444 } 445 446 void PrivetDataReadOperationImpl::OnParsedJson( 447 PrivetURLFetcher* fetcher, 448 const base::DictionaryValue* value, 449 bool has_error) { 450 NOTREACHED(); 451 } 452 453 void PrivetDataReadOperationImpl::OnNeedPrivetToken( 454 PrivetURLFetcher* fetcher, 455 const PrivetURLFetcher::TokenCallback& callback) { 456 privet_client_->RefreshPrivetToken(callback); 457 } 458 459 bool 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 468 PrivetLocalPrintOperationImpl::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 482 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() { 483 } 484 485 void 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 498 void 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 528 void 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 547 void 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 560 void 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 615 void PrivetLocalPrintOperationImpl::StartPrinting() { 616 if (has_extended_workflow_ && jobid_.empty()) { 617 DoCreatejob(); 618 } else { 619 DoSubmitdoc(); 620 } 621 } 622 623 void 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 669 void 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 691 void 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 733 void 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 748 void 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 762 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() { 763 return privet_client_; 764 } 765 766 void PrivetLocalPrintOperationImpl::OnError( 767 PrivetURLFetcher* fetcher, 768 PrivetURLFetcher::ErrorType error) { 769 delegate_->OnPrivetPrintingError(this, -1); 770 } 771 772 void 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 780 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken( 781 PrivetURLFetcher* fetcher, 782 const PrivetURLFetcher::TokenCallback& callback) { 783 privet_client_->RefreshPrivetToken(callback); 784 } 785 786 void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) { 787 DCHECK(!started_); 788 data_ = data; 789 } 790 791 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) { 792 DCHECK(!started_); 793 ticket_.InitFromString(ticket); 794 } 795 796 void PrivetLocalPrintOperationImpl::SetCapabilities( 797 const std::string& capabilities) { 798 DCHECK(!started_); 799 capabilities_.InitFromString(capabilities); 800 } 801 802 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) { 803 DCHECK(!started_); 804 user_= user; 805 } 806 807 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) { 808 DCHECK(!started_); 809 jobname_ = jobname; 810 } 811 812 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) { 813 DCHECK(!started_); 814 offline_ = offline; 815 } 816 817 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) { 818 DCHECK(!started_); 819 page_size_ = page_size; 820 } 821 822 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( 823 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { 824 pwg_raster_converter_ = pwg_raster_converter.Pass(); 825 } 826 827 PrivetHTTPClientImpl::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 833 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { 834 } 835 836 const std::string& PrivetHTTPClientImpl::GetName() { 837 return name_; 838 } 839 840 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation( 841 const PrivetJSONOperation::ResultCallback& callback) { 842 return scoped_ptr<PrivetJSONOperation>( 843 new PrivetInfoOperationImpl(this, callback)); 844 } 845 846 scoped_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 861 void 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 873 void 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 893 PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl( 894 scoped_ptr<PrivetHTTPClient> info_client) 895 : info_client_(info_client.Pass()) { 896 } 897 898 PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() { 899 } 900 901 const std::string& PrivetV1HTTPClientImpl::GetName() { 902 return info_client()->GetName(); 903 } 904 905 scoped_ptr<PrivetJSONOperation> PrivetV1HTTPClientImpl::CreateInfoOperation( 906 const PrivetJSONOperation::ResultCallback& callback) { 907 return info_client()->CreateInfoOperation(callback); 908 } 909 910 scoped_ptr<PrivetRegisterOperation> 911 PrivetV1HTTPClientImpl::CreateRegisterOperation( 912 const std::string& user, 913 PrivetRegisterOperation::Delegate* delegate) { 914 return scoped_ptr<PrivetRegisterOperation>( 915 new PrivetRegisterOperationImpl(info_client(), user, delegate)); 916 } 917 918 scoped_ptr<PrivetJSONOperation> 919 PrivetV1HTTPClientImpl::CreateCapabilitiesOperation( 920 const PrivetJSONOperation::ResultCallback& callback) { 921 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl( 922 info_client(), kPrivetCapabilitiesPath, "", callback)); 923 } 924 925 scoped_ptr<PrivetLocalPrintOperation> 926 PrivetV1HTTPClientImpl::CreateLocalPrintOperation( 927 PrivetLocalPrintOperation::Delegate* delegate) { 928 return scoped_ptr<PrivetLocalPrintOperation>( 929 new PrivetLocalPrintOperationImpl(info_client(), delegate)); 930 } 931 932 scoped_ptr<PrivetJSONOperation> 933 PrivetV1HTTPClientImpl::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 942 scoped_ptr<PrivetDataReadOperation> 943 PrivetV1HTTPClientImpl::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 952 PrivetV3HTTPClientImpl::PrivetV3HTTPClientImpl( 953 scoped_ptr<PrivetHTTPClient> info_client) 954 : info_client_(info_client.Pass()) { 955 } 956 957 PrivetV3HTTPClientImpl::~PrivetV3HTTPClientImpl() { 958 } 959 960 const std::string& PrivetV3HTTPClientImpl::GetName() { 961 return info_client()->GetName(); 962 } 963 964 scoped_ptr<PrivetJSONOperation> PrivetV3HTTPClientImpl::CreateInfoOperation( 965 const PrivetJSONOperation::ResultCallback& callback) { 966 return info_client()->CreateInfoOperation(callback); 967 } 968 969 } // namespace local_discovery 970