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