privet_http_impl.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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(PrivetURLFetcher* fetcher, 381 const base::DictionaryValue& value, 382 bool has_error) { 383 callback_.Run(&value); 384} 385 386void PrivetJSONOperationImpl::OnNeedPrivetToken( 387 PrivetURLFetcher* fetcher, 388 const PrivetURLFetcher::TokenCallback& callback) { 389 privet_client_->RefreshPrivetToken(callback); 390} 391 392PrivetDataReadOperationImpl::PrivetDataReadOperationImpl( 393 PrivetHTTPClient* privet_client, 394 const std::string& path, 395 const std::string& query_params, 396 const PrivetDataReadOperation::ResultCallback& callback) 397 : privet_client_(privet_client), 398 path_(path), 399 query_params_(query_params), 400 callback_(callback), 401 has_range_(false), 402 save_to_file_(false) { 403} 404 405PrivetDataReadOperationImpl::~PrivetDataReadOperationImpl() { 406} 407 408 409void PrivetDataReadOperationImpl::Start() { 410 url_fetcher_ = privet_client_->CreateURLFetcher( 411 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this); 412 url_fetcher_->DoNotRetryOnTransientError(); 413 414 if (has_range_) { 415 url_fetcher_->SetByteRange(range_start_, range_end_); 416 } 417 418 if (save_to_file_) { 419 url_fetcher_->SaveResponseToFile(); 420 } 421 422 url_fetcher_->Start(); 423} 424 425void PrivetDataReadOperationImpl::SetDataRange(int range_start, int range_end) { 426 has_range_ = true; 427 range_start_ = range_start; 428 range_end_ = range_end; 429} 430 431void PrivetDataReadOperationImpl::SaveDataToFile() { 432 save_to_file_ = false; 433} 434 435PrivetHTTPClient* PrivetDataReadOperationImpl::GetHTTPClient() { 436 return privet_client_; 437} 438 439void PrivetDataReadOperationImpl::OnError( 440 PrivetURLFetcher* fetcher, 441 PrivetURLFetcher::ErrorType error) { 442 callback_.Run(RESPONSE_TYPE_ERROR, std::string(), base::FilePath()); 443} 444 445void PrivetDataReadOperationImpl::OnParsedJson( 446 PrivetURLFetcher* fetcher, 447 const base::DictionaryValue& value, 448 bool has_error) { 449 NOTREACHED(); 450} 451 452void PrivetDataReadOperationImpl::OnNeedPrivetToken( 453 PrivetURLFetcher* fetcher, 454 const PrivetURLFetcher::TokenCallback& callback) { 455 privet_client_->RefreshPrivetToken(callback); 456} 457 458bool PrivetDataReadOperationImpl::OnRawData(PrivetURLFetcher* fetcher, 459 bool is_file, 460 const std::string& data_str, 461 const base::FilePath& file_path) { 462 ResponseType type = (is_file) ? RESPONSE_TYPE_FILE : RESPONSE_TYPE_STRING; 463 callback_.Run(type, data_str, file_path); 464 return true; 465} 466 467PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl( 468 PrivetHTTPClient* privet_client, 469 PrivetLocalPrintOperation::Delegate* delegate) 470 : privet_client_(privet_client), 471 delegate_(delegate), 472 use_pdf_(false), 473 has_extended_workflow_(false), 474 started_(false), 475 offline_(false), 476 dpi_(printing::kDefaultPdfDpi), 477 invalid_job_retries_(0), 478 weak_factory_(this) { 479} 480 481PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() { 482} 483 484void PrivetLocalPrintOperationImpl::Start() { 485 DCHECK(!started_); 486 487 // We need to get the /info response so we can know which APIs are available. 488 // TODO(noamsml): Use cached info when available. 489 info_operation_ = privet_client_->CreateInfoOperation( 490 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone, 491 base::Unretained(this))); 492 info_operation_->Start(); 493 494 started_ = true; 495} 496 497void PrivetLocalPrintOperationImpl::OnPrivetInfoDone( 498 const base::DictionaryValue* value) { 499 if (value && !value->HasKey(kPrivetKeyError)) { 500 has_extended_workflow_ = false; 501 bool has_printing = false; 502 503 const base::ListValue* api_list; 504 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) { 505 for (size_t i = 0; i < api_list->GetSize(); i++) { 506 std::string api; 507 api_list->GetString(i, &api); 508 if (api == kPrivetSubmitdocPath) { 509 has_printing = true; 510 } else if (api == kPrivetCreatejobPath) { 511 has_extended_workflow_ = true; 512 } 513 } 514 } 515 516 if (!has_printing) { 517 delegate_->OnPrivetPrintingError(this, -1); 518 return; 519 } 520 521 StartInitialRequest(); 522 } else { 523 delegate_->OnPrivetPrintingError(this, -1); 524 } 525} 526 527void PrivetLocalPrintOperationImpl::StartInitialRequest() { 528 use_pdf_ = false; 529 ContentTypesCapability content_types; 530 if (content_types.LoadFrom(capabilities_)) { 531 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) || 532 content_types.Contains(kPrivetContentTypeAny); 533 } 534 535 if (use_pdf_) { 536 StartPrinting(); 537 } else { 538 DpiCapability dpis; 539 if (dpis.LoadFrom(capabilities_)) { 540 dpi_ = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical); 541 } 542 StartConvertToPWG(); 543 } 544} 545 546void PrivetLocalPrintOperationImpl::DoCreatejob() { 547 current_response_ = base::Bind( 548 &PrivetLocalPrintOperationImpl::OnCreatejobResponse, 549 base::Unretained(this)); 550 551 url_fetcher_= privet_client_->CreateURLFetcher( 552 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this); 553 url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON, 554 ticket_.ToString()); 555 556 url_fetcher_->Start(); 557} 558 559void PrivetLocalPrintOperationImpl::DoSubmitdoc() { 560 current_response_ = base::Bind( 561 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse, 562 base::Unretained(this)); 563 564 GURL url = CreatePrivetURL(kPrivetSubmitdocPath); 565 566 url = net::AppendQueryParameter(url, 567 kPrivetURLKeyClientName, 568 kPrivetURLValueClientName); 569 570 if (!user_.empty()) { 571 url = net::AppendQueryParameter(url, 572 kPrivetURLKeyUserName, 573 user_); 574 } 575 576 base::string16 shortened_jobname; 577 578 gfx::ElideString(base::UTF8ToUTF16(jobname_), 579 kPrivetLocalPrintMaxJobNameLength, 580 &shortened_jobname); 581 582 if (!jobname_.empty()) { 583 url = net::AppendQueryParameter( 584 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname)); 585 } 586 587 if (!jobid_.empty()) { 588 url = net::AppendQueryParameter(url, 589 kPrivetKeyJobID, 590 jobid_); 591 } 592 593 if (offline_) { 594 url = net::AppendQueryParameter(url, 595 kPrivetURLKeyOffline, 596 kPrivetURLValueOffline); 597 } 598 599 url_fetcher_= privet_client_->CreateURLFetcher( 600 url, net::URLFetcher::POST, this); 601 602 if (!use_pdf_) { 603 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster, 604 pwg_file_path_); 605 } else { 606 // TODO(noamsml): Move to file-based upload data? 607 std::string data_str((const char*)data_->front(), data_->size()); 608 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str); 609 } 610 611 url_fetcher_->Start(); 612} 613 614void PrivetLocalPrintOperationImpl::StartPrinting() { 615 if (has_extended_workflow_ && jobid_.empty()) { 616 DoCreatejob(); 617 } else { 618 DoSubmitdoc(); 619 } 620} 621 622void PrivetLocalPrintOperationImpl::FillPwgRasterSettings( 623 printing::PwgRasterSettings* transform_settings) { 624 PwgRasterConfigCapability raster_capability; 625 // If the raster capability fails to load, raster_capability will contain 626 // the default value. 627 raster_capability.LoadFrom(capabilities_); 628 629 DuplexTicketItem duplex_item; 630 DuplexType duplex_value = NO_DUPLEX; 631 632 DocumentSheetBack document_sheet_back = 633 raster_capability.value().document_sheet_back; 634 635 if (duplex_item.LoadFrom(ticket_)) { 636 duplex_value = duplex_item.value(); 637 } 638 639 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL; 640 switch (duplex_value) { 641 case NO_DUPLEX: 642 transform_settings->odd_page_transform = printing::TRANSFORM_NORMAL; 643 break; 644 case LONG_EDGE: 645 if (document_sheet_back == ROTATED) { 646 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180; 647 } else if (document_sheet_back == FLIPPED) { 648 transform_settings->odd_page_transform = 649 printing::TRANSFORM_FLIP_VERTICAL; 650 } 651 break; 652 case SHORT_EDGE: 653 if (document_sheet_back == MANUAL_TUMBLE) { 654 transform_settings->odd_page_transform = printing::TRANSFORM_ROTATE_180; 655 } else if (document_sheet_back == FLIPPED) { 656 transform_settings->odd_page_transform = 657 printing::TRANSFORM_FLIP_HORIZONTAL; 658 } 659 } 660 661 transform_settings->rotate_all_pages = 662 raster_capability.value().rotate_all_pages; 663 664 transform_settings->reverse_page_order = 665 raster_capability.value().reverse_order_streaming; 666} 667 668void PrivetLocalPrintOperationImpl::StartConvertToPWG() { 669 printing::PwgRasterSettings transform_settings; 670 671 FillPwgRasterSettings(&transform_settings); 672 673 if (!pwg_raster_converter_) 674 pwg_raster_converter_ = PWGRasterConverter::CreateDefault(); 675 676 double scale = dpi_; 677 scale /= printing::kPointsPerInch; 678 // Make vertical rectangle to optimize streaming to printer. Fix orientation 679 // by autorotate. 680 gfx::Rect area(std::min(page_size_.width(), page_size_.height()) * scale, 681 std::max(page_size_.width(), page_size_.height()) * scale); 682 pwg_raster_converter_->Start( 683 data_, 684 printing::PdfRenderSettings(area, dpi_, true), 685 transform_settings, 686 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted, 687 base::Unretained(this))); 688} 689 690void PrivetLocalPrintOperationImpl::OnSubmitdocResponse( 691 bool has_error, 692 const base::DictionaryValue* value) { 693 std::string error; 694 // This error is only relevant in the case of extended workflow: 695 // If the print job ID is invalid, retry createjob and submitdoc, 696 // rather than simply retrying the current request. 697 if (has_error && value->GetString(kPrivetKeyError, &error)) { 698 if (has_extended_workflow_ && 699 error == kPrivetErrorInvalidPrintJob && 700 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) { 701 invalid_job_retries_++; 702 703 int timeout = kPrivetLocalPrintDefaultTimeout; 704 value->GetInteger(kPrivetKeyTimeout, &timeout); 705 706 double random_scaling_factor = 707 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition; 708 709 timeout = static_cast<int>(timeout * random_scaling_factor); 710 711 timeout = std::max(timeout, kPrivetMinimumTimeout); 712 713 base::MessageLoop::current()->PostDelayedTask( 714 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob, 715 weak_factory_.GetWeakPtr()), 716 base::TimeDelta::FromSeconds(timeout)); 717 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) { 718 use_pdf_ = false; 719 StartConvertToPWG(); 720 } else { 721 delegate_->OnPrivetPrintingError(this, 200); 722 } 723 724 return; 725 } 726 727 // If we've gotten this far, there are no errors, so we've effectively 728 // succeeded. 729 delegate_->OnPrivetPrintingDone(this); 730} 731 732void PrivetLocalPrintOperationImpl::OnCreatejobResponse( 733 bool has_error, 734 const base::DictionaryValue* value) { 735 if (has_error) { 736 delegate_->OnPrivetPrintingError(this, 200); 737 return; 738 } 739 740 // Try to get job ID from value. If not, jobid_ will be empty and we will use 741 // simple printing. 742 value->GetString(kPrivetKeyJobID, &jobid_); 743 744 DoSubmitdoc(); 745} 746 747void PrivetLocalPrintOperationImpl::OnPWGRasterConverted( 748 bool success, 749 const base::FilePath& pwg_file_path) { 750 if (!success) { 751 delegate_->OnPrivetPrintingError(this, -1); 752 return; 753 } 754 755 DCHECK(!pwg_file_path.empty()); 756 757 pwg_file_path_ = pwg_file_path; 758 StartPrinting(); 759} 760 761PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() { 762 return privet_client_; 763} 764 765void PrivetLocalPrintOperationImpl::OnError( 766 PrivetURLFetcher* fetcher, 767 PrivetURLFetcher::ErrorType error) { 768 delegate_->OnPrivetPrintingError(this, -1); 769} 770 771void PrivetLocalPrintOperationImpl::OnParsedJson( 772 PrivetURLFetcher* fetcher, 773 const base::DictionaryValue& value, 774 bool has_error) { 775 DCHECK(!current_response_.is_null()); 776 current_response_.Run(has_error, &value); 777} 778 779void PrivetLocalPrintOperationImpl::OnNeedPrivetToken( 780 PrivetURLFetcher* fetcher, 781 const PrivetURLFetcher::TokenCallback& callback) { 782 privet_client_->RefreshPrivetToken(callback); 783} 784 785void PrivetLocalPrintOperationImpl::SetData(base::RefCountedBytes* data) { 786 DCHECK(!started_); 787 data_ = data; 788} 789 790void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) { 791 DCHECK(!started_); 792 ticket_.InitFromString(ticket); 793} 794 795void PrivetLocalPrintOperationImpl::SetCapabilities( 796 const std::string& capabilities) { 797 DCHECK(!started_); 798 capabilities_.InitFromString(capabilities); 799} 800 801void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) { 802 DCHECK(!started_); 803 user_= user; 804} 805 806void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) { 807 DCHECK(!started_); 808 jobname_ = jobname; 809} 810 811void PrivetLocalPrintOperationImpl::SetOffline(bool offline) { 812 DCHECK(!started_); 813 offline_ = offline; 814} 815 816void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) { 817 DCHECK(!started_); 818 page_size_ = page_size; 819} 820 821void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( 822 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { 823 pwg_raster_converter_ = pwg_raster_converter.Pass(); 824} 825 826PrivetHTTPClientImpl::PrivetHTTPClientImpl( 827 const std::string& name, 828 const net::HostPortPair& host_port, 829 net::URLRequestContextGetter* request_context) 830 : name_(name), request_context_(request_context), host_port_(host_port) {} 831 832PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { 833} 834 835const std::string& PrivetHTTPClientImpl::GetName() { 836 return name_; 837} 838 839scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation( 840 const PrivetJSONOperation::ResultCallback& callback) { 841 return scoped_ptr<PrivetJSONOperation>( 842 new PrivetInfoOperationImpl(this, callback)); 843} 844 845scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher( 846 const GURL& url, 847 net::URLFetcher::RequestType request_type, 848 PrivetURLFetcher::Delegate* delegate) { 849 GURL::Replacements replacements; 850 replacements.SetHostStr(host_port_.host()); 851 std::string port(base::IntToString(host_port_.port())); // Keep string alive. 852 replacements.SetPortStr(port); 853 return scoped_ptr<PrivetURLFetcher>( 854 new PrivetURLFetcher(url.ReplaceComponents(replacements), 855 request_type, 856 request_context_.get(), 857 delegate)); 858} 859 860void PrivetHTTPClientImpl::RefreshPrivetToken( 861 const PrivetURLFetcher::TokenCallback& callback) { 862 token_callbacks_.push_back(callback); 863 864 if (!info_operation_) { 865 info_operation_ = CreateInfoOperation( 866 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone, 867 base::Unretained(this))); 868 info_operation_->Start(); 869 } 870} 871 872void PrivetHTTPClientImpl::OnPrivetInfoDone( 873 const base::DictionaryValue* value) { 874 info_operation_.reset(); 875 std::string token; 876 877 // If this does not succeed, token will be empty, and an empty string 878 // is our sentinel value, since empty X-Privet-Tokens are not allowed. 879 if (value) { 880 value->GetString(kPrivetInfoKeyToken, &token); 881 } 882 883 TokenCallbackVector token_callbacks; 884 token_callbacks_.swap(token_callbacks); 885 886 for (TokenCallbackVector::iterator i = token_callbacks.begin(); 887 i != token_callbacks.end(); i++) { 888 i->Run(token); 889 } 890} 891 892PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl( 893 scoped_ptr<PrivetHTTPClient> info_client) 894 : info_client_(info_client.Pass()) { 895} 896 897PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() { 898} 899 900const std::string& PrivetV1HTTPClientImpl::GetName() { 901 return info_client()->GetName(); 902} 903 904scoped_ptr<PrivetJSONOperation> PrivetV1HTTPClientImpl::CreateInfoOperation( 905 const PrivetJSONOperation::ResultCallback& callback) { 906 return info_client()->CreateInfoOperation(callback); 907} 908 909scoped_ptr<PrivetRegisterOperation> 910PrivetV1HTTPClientImpl::CreateRegisterOperation( 911 const std::string& user, 912 PrivetRegisterOperation::Delegate* delegate) { 913 return scoped_ptr<PrivetRegisterOperation>( 914 new PrivetRegisterOperationImpl(info_client(), user, delegate)); 915} 916 917scoped_ptr<PrivetJSONOperation> 918PrivetV1HTTPClientImpl::CreateCapabilitiesOperation( 919 const PrivetJSONOperation::ResultCallback& callback) { 920 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl( 921 info_client(), kPrivetCapabilitiesPath, "", callback)); 922} 923 924scoped_ptr<PrivetLocalPrintOperation> 925PrivetV1HTTPClientImpl::CreateLocalPrintOperation( 926 PrivetLocalPrintOperation::Delegate* delegate) { 927 return scoped_ptr<PrivetLocalPrintOperation>( 928 new PrivetLocalPrintOperationImpl(info_client(), delegate)); 929} 930 931scoped_ptr<PrivetJSONOperation> 932PrivetV1HTTPClientImpl::CreateStorageListOperation( 933 const std::string& path, 934 const PrivetJSONOperation::ResultCallback& callback) { 935 std::string url_param = 936 base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str()); 937 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl( 938 info_client(), kPrivetStorageListPath, url_param, callback)); 939} 940 941scoped_ptr<PrivetDataReadOperation> 942PrivetV1HTTPClientImpl::CreateStorageReadOperation( 943 const std::string& path, 944 const PrivetDataReadOperation::ResultCallback& callback) { 945 std::string url_param = 946 base::StringPrintf(kPrivetStorageParamPathFormat, path.c_str()); 947 return scoped_ptr<PrivetDataReadOperation>(new PrivetDataReadOperationImpl( 948 info_client(), kPrivetStorageContentPath, url_param, callback)); 949} 950 951} // namespace local_discovery 952