| OLD | NEW |
| (Empty) |
| 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 <stddef.h> | |
| 8 #include <algorithm> | |
| 9 #include <utility> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/bind.h" | |
| 13 #include "base/command_line.h" | |
| 14 #include "base/location.h" | |
| 15 #include "base/rand_util.h" | |
| 16 #include "base/strings/string_number_conversions.h" | |
| 17 #include "base/strings/utf_string_conversions.h" | |
| 18 #include "base/thread_task_runner_handle.h" | |
| 19 #include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h" | |
| 20 #include "chrome/browser/local_discovery/privet_constants.h" | |
| 21 #include "chrome/common/chrome_content_client.h" | |
| 22 #include "chrome/common/chrome_switches.h" | |
| 23 #include "chrome/common/cloud_print/cloud_print_constants.h" | |
| 24 #include "net/base/url_util.h" | |
| 25 #include "url/gurl.h" | |
| 26 | |
| 27 #if defined(ENABLE_PRINT_PREVIEW) | |
| 28 #include "chrome/browser/local_discovery/pwg_raster_converter.h" | |
| 29 #include "components/cloud_devices/common/printer_description.h" | |
| 30 #include "printing/pdf_render_settings.h" | |
| 31 #include "printing/pwg_raster_settings.h" | |
| 32 #include "ui/gfx/text_elider.h" | |
| 33 #endif // ENABLE_PRINT_PREVIEW | |
| 34 | |
| 35 namespace local_discovery { | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 const char kUrlPlaceHolder[] = "http://host/"; | |
| 40 const char kPrivetRegisterActionArgName[] = "action"; | |
| 41 const char kPrivetRegisterUserArgName[] = "user"; | |
| 42 | |
| 43 const int kPrivetCancelationTimeoutSeconds = 3; | |
| 44 | |
| 45 #if defined(ENABLE_PRINT_PREVIEW) | |
| 46 const char kPrivetURLKeyUserName[] = "user_name"; | |
| 47 const char kPrivetURLKeyClientName[] = "client_name"; | |
| 48 const char kPrivetURLKeyJobname[] = "job_name"; | |
| 49 const char kPrivetURLKeyOffline[] = "offline"; | |
| 50 const char kPrivetURLValueOffline[] = "1"; | |
| 51 const char kPrivetURLValueClientName[] = "Chrome"; | |
| 52 | |
| 53 const char kPrivetContentTypePDF[] = "application/pdf"; | |
| 54 const char kPrivetContentTypePWGRaster[] = "image/pwg-raster"; | |
| 55 const char kPrivetContentTypeAny[] = "*/*"; | |
| 56 | |
| 57 const char kPrivetKeyJobID[] = "job_id"; | |
| 58 | |
| 59 const int kPrivetLocalPrintMaxRetries = 2; | |
| 60 const int kPrivetLocalPrintDefaultTimeout = 5; | |
| 61 | |
| 62 const size_t kPrivetLocalPrintMaxJobNameLength = 64; | |
| 63 #endif // ENABLE_PRINT_PREVIEW | |
| 64 | |
| 65 GURL CreatePrivetURL(const std::string& path) { | |
| 66 GURL url(kUrlPlaceHolder); | |
| 67 GURL::Replacements replacements; | |
| 68 replacements.SetPathStr(path); | |
| 69 return url.ReplaceComponents(replacements); | |
| 70 } | |
| 71 | |
| 72 GURL CreatePrivetRegisterURL(const std::string& action, | |
| 73 const std::string& user) { | |
| 74 GURL url = CreatePrivetURL(kPrivetRegisterPath); | |
| 75 url = net::AppendQueryParameter(url, kPrivetRegisterActionArgName, action); | |
| 76 return net::AppendQueryParameter(url, kPrivetRegisterUserArgName, user); | |
| 77 } | |
| 78 | |
| 79 GURL CreatePrivetParamURL(const std::string& path, | |
| 80 const std::string& query_params) { | |
| 81 GURL url(kUrlPlaceHolder); | |
| 82 GURL::Replacements replacements; | |
| 83 replacements.SetPathStr(path); | |
| 84 if (!query_params.empty()) { | |
| 85 replacements.SetQueryStr(query_params); | |
| 86 } | |
| 87 return url.ReplaceComponents(replacements); | |
| 88 } | |
| 89 | |
| 90 } // namespace | |
| 91 | |
| 92 PrivetInfoOperationImpl::PrivetInfoOperationImpl( | |
| 93 PrivetHTTPClient* privet_client, | |
| 94 const PrivetJSONOperation::ResultCallback& callback) | |
| 95 : privet_client_(privet_client), callback_(callback) { | |
| 96 } | |
| 97 | |
| 98 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { | |
| 99 } | |
| 100 | |
| 101 void PrivetInfoOperationImpl::Start() { | |
| 102 url_fetcher_ = privet_client_->CreateURLFetcher( | |
| 103 CreatePrivetURL(kPrivetInfoPath), net::URLFetcher::GET, this); | |
| 104 | |
| 105 url_fetcher_->DoNotRetryOnTransientError(); | |
| 106 url_fetcher_->SendEmptyPrivetToken(); | |
| 107 | |
| 108 url_fetcher_->Start(); | |
| 109 } | |
| 110 | |
| 111 PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() { | |
| 112 return privet_client_; | |
| 113 } | |
| 114 | |
| 115 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher, | |
| 116 PrivetURLFetcher::ErrorType error) { | |
| 117 callback_.Run(NULL); | |
| 118 } | |
| 119 | |
| 120 void PrivetInfoOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher, | |
| 121 const base::DictionaryValue& value, | |
| 122 bool has_error) { | |
| 123 callback_.Run(&value); | |
| 124 } | |
| 125 | |
| 126 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl( | |
| 127 PrivetHTTPClient* privet_client, | |
| 128 const std::string& user, | |
| 129 PrivetRegisterOperation::Delegate* delegate) | |
| 130 : user_(user), | |
| 131 delegate_(delegate), | |
| 132 privet_client_(privet_client), | |
| 133 ongoing_(false) { | |
| 134 } | |
| 135 | |
| 136 PrivetRegisterOperationImpl::~PrivetRegisterOperationImpl() { | |
| 137 } | |
| 138 | |
| 139 void PrivetRegisterOperationImpl::Start() { | |
| 140 ongoing_ = true; | |
| 141 next_response_handler_ = | |
| 142 base::Bind(&PrivetRegisterOperationImpl::StartResponse, | |
| 143 base::Unretained(this)); | |
| 144 SendRequest(kPrivetActionStart); | |
| 145 } | |
| 146 | |
| 147 void PrivetRegisterOperationImpl::Cancel() { | |
| 148 url_fetcher_.reset(); | |
| 149 | |
| 150 if (ongoing_) { | |
| 151 // Owned by the message loop. | |
| 152 Cancelation* cancelation = new Cancelation(privet_client_, user_); | |
| 153 | |
| 154 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 155 FROM_HERE, | |
| 156 base::Bind(&PrivetRegisterOperationImpl::Cancelation::Cleanup, | |
| 157 base::Owned(cancelation)), | |
| 158 base::TimeDelta::FromSeconds(kPrivetCancelationTimeoutSeconds)); | |
| 159 | |
| 160 ongoing_ = false; | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void PrivetRegisterOperationImpl::CompleteRegistration() { | |
| 165 next_response_handler_ = | |
| 166 base::Bind(&PrivetRegisterOperationImpl::CompleteResponse, | |
| 167 base::Unretained(this)); | |
| 168 SendRequest(kPrivetActionComplete); | |
| 169 } | |
| 170 | |
| 171 PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() { | |
| 172 return privet_client_; | |
| 173 } | |
| 174 | |
| 175 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher, | |
| 176 PrivetURLFetcher::ErrorType error) { | |
| 177 ongoing_ = false; | |
| 178 int visible_http_code = -1; | |
| 179 FailureReason reason = FAILURE_NETWORK; | |
| 180 | |
| 181 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) { | |
| 182 visible_http_code = fetcher->response_code(); | |
| 183 reason = FAILURE_HTTP_ERROR; | |
| 184 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) { | |
| 185 reason = FAILURE_MALFORMED_RESPONSE; | |
| 186 } else if (error == PrivetURLFetcher::TOKEN_ERROR) { | |
| 187 reason = FAILURE_TOKEN; | |
| 188 } else if (error == PrivetURLFetcher::UNKNOWN_ERROR) { | |
| 189 reason = FAILURE_UNKNOWN; | |
| 190 } | |
| 191 | |
| 192 delegate_->OnPrivetRegisterError(this, | |
| 193 current_action_, | |
| 194 reason, | |
| 195 visible_http_code, | |
| 196 NULL); | |
| 197 } | |
| 198 | |
| 199 void PrivetRegisterOperationImpl::OnParsedJson( | |
| 200 PrivetURLFetcher* fetcher, | |
| 201 const base::DictionaryValue& value, | |
| 202 bool has_error) { | |
| 203 if (has_error) { | |
| 204 std::string error; | |
| 205 value.GetString(kPrivetKeyError, &error); | |
| 206 | |
| 207 ongoing_ = false; | |
| 208 delegate_->OnPrivetRegisterError(this, | |
| 209 current_action_, | |
| 210 FAILURE_JSON_ERROR, | |
| 211 fetcher->response_code(), | |
| 212 &value); | |
| 213 return; | |
| 214 } | |
| 215 | |
| 216 // TODO(noamsml): Match the user&action with the user&action in the object, | |
| 217 // and fail if different. | |
| 218 | |
| 219 next_response_handler_.Run(value); | |
| 220 } | |
| 221 | |
| 222 void PrivetRegisterOperationImpl::OnNeedPrivetToken( | |
| 223 PrivetURLFetcher* fetcher, | |
| 224 const PrivetURLFetcher::TokenCallback& callback) { | |
| 225 privet_client_->RefreshPrivetToken(callback); | |
| 226 } | |
| 227 | |
| 228 void PrivetRegisterOperationImpl::SendRequest(const std::string& action) { | |
| 229 current_action_ = action; | |
| 230 url_fetcher_ = privet_client_->CreateURLFetcher( | |
| 231 CreatePrivetRegisterURL(action, user_), net::URLFetcher::POST, this); | |
| 232 url_fetcher_->Start(); | |
| 233 } | |
| 234 | |
| 235 void PrivetRegisterOperationImpl::StartResponse( | |
| 236 const base::DictionaryValue& value) { | |
| 237 next_response_handler_ = | |
| 238 base::Bind(&PrivetRegisterOperationImpl::GetClaimTokenResponse, | |
| 239 base::Unretained(this)); | |
| 240 | |
| 241 SendRequest(kPrivetActionGetClaimToken); | |
| 242 } | |
| 243 | |
| 244 void PrivetRegisterOperationImpl::GetClaimTokenResponse( | |
| 245 const base::DictionaryValue& value) { | |
| 246 std::string claimUrl; | |
| 247 std::string claimToken; | |
| 248 bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl); | |
| 249 bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken); | |
| 250 if (got_url || got_token) { | |
| 251 delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl)); | |
| 252 } else { | |
| 253 delegate_->OnPrivetRegisterError(this, | |
| 254 current_action_, | |
| 255 FAILURE_MALFORMED_RESPONSE, | |
| 256 -1, | |
| 257 NULL); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 void PrivetRegisterOperationImpl::CompleteResponse( | |
| 262 const base::DictionaryValue& value) { | |
| 263 std::string id; | |
| 264 value.GetString(kPrivetKeyDeviceID, &id); | |
| 265 ongoing_ = false; | |
| 266 expected_id_ = id; | |
| 267 StartInfoOperation(); | |
| 268 } | |
| 269 | |
| 270 void PrivetRegisterOperationImpl::OnPrivetInfoDone( | |
| 271 const base::DictionaryValue* value) { | |
| 272 // TODO(noamsml): Simplify error case and depracate HTTP error value in | |
| 273 // OnPrivetRegisterError. | |
| 274 if (!value) { | |
| 275 delegate_->OnPrivetRegisterError(this, | |
| 276 kPrivetActionNameInfo, | |
| 277 FAILURE_NETWORK, | |
| 278 -1, | |
| 279 NULL); | |
| 280 return; | |
| 281 } | |
| 282 | |
| 283 if (!value->HasKey(kPrivetInfoKeyID)) { | |
| 284 if (value->HasKey(kPrivetKeyError)) { | |
| 285 delegate_->OnPrivetRegisterError(this, | |
| 286 kPrivetActionNameInfo, | |
| 287 FAILURE_JSON_ERROR, | |
| 288 -1, | |
| 289 value); | |
| 290 } else { | |
| 291 delegate_->OnPrivetRegisterError(this, | |
| 292 kPrivetActionNameInfo, | |
| 293 FAILURE_MALFORMED_RESPONSE, | |
| 294 -1, | |
| 295 NULL); | |
| 296 } | |
| 297 return; | |
| 298 } | |
| 299 | |
| 300 std::string id; | |
| 301 | |
| 302 if (!value->GetString(kPrivetInfoKeyID, &id) || | |
| 303 id != expected_id_) { | |
| 304 delegate_->OnPrivetRegisterError(this, | |
| 305 kPrivetActionNameInfo, | |
| 306 FAILURE_MALFORMED_RESPONSE, | |
| 307 -1, | |
| 308 NULL); | |
| 309 } else { | |
| 310 delegate_->OnPrivetRegisterDone(this, id); | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 void PrivetRegisterOperationImpl::StartInfoOperation() { | |
| 315 info_operation_ = privet_client_->CreateInfoOperation( | |
| 316 base::Bind(&PrivetRegisterOperationImpl::OnPrivetInfoDone, | |
| 317 base::Unretained(this))); | |
| 318 info_operation_->Start(); | |
| 319 } | |
| 320 | |
| 321 PrivetRegisterOperationImpl::Cancelation::Cancelation( | |
| 322 PrivetHTTPClient* privet_client, | |
| 323 const std::string& user) { | |
| 324 url_fetcher_ = | |
| 325 privet_client->CreateURLFetcher( | |
| 326 CreatePrivetRegisterURL(kPrivetActionCancel, user), | |
| 327 net::URLFetcher::POST, this); | |
| 328 url_fetcher_->DoNotRetryOnTransientError(); | |
| 329 url_fetcher_->Start(); | |
| 330 } | |
| 331 | |
| 332 PrivetRegisterOperationImpl::Cancelation::~Cancelation() { | |
| 333 } | |
| 334 | |
| 335 void PrivetRegisterOperationImpl::Cancelation::OnError( | |
| 336 PrivetURLFetcher* fetcher, | |
| 337 PrivetURLFetcher::ErrorType error) { | |
| 338 } | |
| 339 | |
| 340 void PrivetRegisterOperationImpl::Cancelation::OnParsedJson( | |
| 341 PrivetURLFetcher* fetcher, | |
| 342 const base::DictionaryValue& value, | |
| 343 bool has_error) { | |
| 344 } | |
| 345 | |
| 346 void PrivetRegisterOperationImpl::Cancelation::Cleanup() { | |
| 347 // Nothing needs to be done, as base::Owned will delete this object, | |
| 348 // this callback is just here to pass ownership of the Cancelation to | |
| 349 // the message loop. | |
| 350 } | |
| 351 | |
| 352 PrivetJSONOperationImpl::PrivetJSONOperationImpl( | |
| 353 PrivetHTTPClient* privet_client, | |
| 354 const std::string& path, | |
| 355 const std::string& query_params, | |
| 356 const PrivetJSONOperation::ResultCallback& callback) | |
| 357 : privet_client_(privet_client), | |
| 358 path_(path), | |
| 359 query_params_(query_params), | |
| 360 callback_(callback) { | |
| 361 } | |
| 362 | |
| 363 PrivetJSONOperationImpl::~PrivetJSONOperationImpl() { | |
| 364 } | |
| 365 | |
| 366 void PrivetJSONOperationImpl::Start() { | |
| 367 url_fetcher_ = privet_client_->CreateURLFetcher( | |
| 368 CreatePrivetParamURL(path_, query_params_), net::URLFetcher::GET, this); | |
| 369 url_fetcher_->DoNotRetryOnTransientError(); | |
| 370 url_fetcher_->Start(); | |
| 371 } | |
| 372 | |
| 373 PrivetHTTPClient* PrivetJSONOperationImpl::GetHTTPClient() { | |
| 374 return privet_client_; | |
| 375 } | |
| 376 | |
| 377 void PrivetJSONOperationImpl::OnError( | |
| 378 PrivetURLFetcher* fetcher, | |
| 379 PrivetURLFetcher::ErrorType error) { | |
| 380 callback_.Run(NULL); | |
| 381 } | |
| 382 | |
| 383 void PrivetJSONOperationImpl::OnParsedJson(PrivetURLFetcher* fetcher, | |
| 384 const base::DictionaryValue& value, | |
| 385 bool has_error) { | |
| 386 callback_.Run(&value); | |
| 387 } | |
| 388 | |
| 389 void PrivetJSONOperationImpl::OnNeedPrivetToken( | |
| 390 PrivetURLFetcher* fetcher, | |
| 391 const PrivetURLFetcher::TokenCallback& callback) { | |
| 392 privet_client_->RefreshPrivetToken(callback); | |
| 393 } | |
| 394 | |
| 395 #if defined(ENABLE_PRINT_PREVIEW) | |
| 396 PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl( | |
| 397 PrivetHTTPClient* privet_client, | |
| 398 PrivetLocalPrintOperation::Delegate* delegate) | |
| 399 : privet_client_(privet_client), | |
| 400 delegate_(delegate), | |
| 401 use_pdf_(false), | |
| 402 has_extended_workflow_(false), | |
| 403 started_(false), | |
| 404 offline_(false), | |
| 405 invalid_job_retries_(0), | |
| 406 weak_factory_(this) { | |
| 407 } | |
| 408 | |
| 409 PrivetLocalPrintOperationImpl::~PrivetLocalPrintOperationImpl() { | |
| 410 } | |
| 411 | |
| 412 void PrivetLocalPrintOperationImpl::Start() { | |
| 413 DCHECK(!started_); | |
| 414 | |
| 415 // We need to get the /info response so we can know which APIs are available. | |
| 416 // TODO(noamsml): Use cached info when available. | |
| 417 info_operation_ = privet_client_->CreateInfoOperation( | |
| 418 base::Bind(&PrivetLocalPrintOperationImpl::OnPrivetInfoDone, | |
| 419 base::Unretained(this))); | |
| 420 info_operation_->Start(); | |
| 421 | |
| 422 started_ = true; | |
| 423 } | |
| 424 | |
| 425 void PrivetLocalPrintOperationImpl::OnPrivetInfoDone( | |
| 426 const base::DictionaryValue* value) { | |
| 427 if (value && !value->HasKey(kPrivetKeyError)) { | |
| 428 has_extended_workflow_ = false; | |
| 429 bool has_printing = false; | |
| 430 | |
| 431 const base::ListValue* api_list; | |
| 432 if (value->GetList(kPrivetInfoKeyAPIList, &api_list)) { | |
| 433 for (size_t i = 0; i < api_list->GetSize(); i++) { | |
| 434 std::string api; | |
| 435 api_list->GetString(i, &api); | |
| 436 if (api == kPrivetSubmitdocPath) { | |
| 437 has_printing = true; | |
| 438 } else if (api == kPrivetCreatejobPath) { | |
| 439 has_extended_workflow_ = true; | |
| 440 } | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 if (!has_printing) { | |
| 445 delegate_->OnPrivetPrintingError(this, -1); | |
| 446 return; | |
| 447 } | |
| 448 | |
| 449 StartInitialRequest(); | |
| 450 } else { | |
| 451 delegate_->OnPrivetPrintingError(this, -1); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 void PrivetLocalPrintOperationImpl::StartInitialRequest() { | |
| 456 use_pdf_ = false; | |
| 457 cloud_devices::printer::ContentTypesCapability content_types; | |
| 458 if (content_types.LoadFrom(capabilities_)) { | |
| 459 use_pdf_ = content_types.Contains(kPrivetContentTypePDF) || | |
| 460 content_types.Contains(kPrivetContentTypeAny); | |
| 461 } | |
| 462 | |
| 463 if (use_pdf_) { | |
| 464 StartPrinting(); | |
| 465 } else { | |
| 466 StartConvertToPWG(); | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 void PrivetLocalPrintOperationImpl::DoCreatejob() { | |
| 471 current_response_ = base::Bind( | |
| 472 &PrivetLocalPrintOperationImpl::OnCreatejobResponse, | |
| 473 base::Unretained(this)); | |
| 474 | |
| 475 url_fetcher_ = privet_client_->CreateURLFetcher( | |
| 476 CreatePrivetURL(kPrivetCreatejobPath), net::URLFetcher::POST, this); | |
| 477 url_fetcher_->SetUploadData(cloud_print::kContentTypeJSON, | |
| 478 ticket_.ToString()); | |
| 479 | |
| 480 url_fetcher_->Start(); | |
| 481 } | |
| 482 | |
| 483 void PrivetLocalPrintOperationImpl::DoSubmitdoc() { | |
| 484 current_response_ = base::Bind( | |
| 485 &PrivetLocalPrintOperationImpl::OnSubmitdocResponse, | |
| 486 base::Unretained(this)); | |
| 487 | |
| 488 GURL url = CreatePrivetURL(kPrivetSubmitdocPath); | |
| 489 | |
| 490 url = net::AppendQueryParameter(url, | |
| 491 kPrivetURLKeyClientName, | |
| 492 kPrivetURLValueClientName); | |
| 493 | |
| 494 if (!user_.empty()) { | |
| 495 url = net::AppendQueryParameter(url, | |
| 496 kPrivetURLKeyUserName, | |
| 497 user_); | |
| 498 } | |
| 499 | |
| 500 base::string16 shortened_jobname; | |
| 501 | |
| 502 gfx::ElideString(base::UTF8ToUTF16(jobname_), | |
| 503 kPrivetLocalPrintMaxJobNameLength, | |
| 504 &shortened_jobname); | |
| 505 | |
| 506 if (!jobname_.empty()) { | |
| 507 url = net::AppendQueryParameter( | |
| 508 url, kPrivetURLKeyJobname, base::UTF16ToUTF8(shortened_jobname)); | |
| 509 } | |
| 510 | |
| 511 if (!jobid_.empty()) { | |
| 512 url = net::AppendQueryParameter(url, | |
| 513 kPrivetKeyJobID, | |
| 514 jobid_); | |
| 515 } | |
| 516 | |
| 517 if (offline_) { | |
| 518 url = net::AppendQueryParameter(url, | |
| 519 kPrivetURLKeyOffline, | |
| 520 kPrivetURLValueOffline); | |
| 521 } | |
| 522 | |
| 523 url_fetcher_ = | |
| 524 privet_client_->CreateURLFetcher(url, net::URLFetcher::POST, this); | |
| 525 | |
| 526 if (!use_pdf_) { | |
| 527 url_fetcher_->SetUploadFilePath(kPrivetContentTypePWGRaster, | |
| 528 pwg_file_path_); | |
| 529 } else { | |
| 530 // TODO(noamsml): Move to file-based upload data? | |
| 531 std::string data_str(reinterpret_cast<const char*>(data_->front()), | |
| 532 data_->size()); | |
| 533 url_fetcher_->SetUploadData(kPrivetContentTypePDF, data_str); | |
| 534 } | |
| 535 | |
| 536 url_fetcher_->Start(); | |
| 537 } | |
| 538 | |
| 539 void PrivetLocalPrintOperationImpl::StartPrinting() { | |
| 540 if (has_extended_workflow_ && jobid_.empty()) { | |
| 541 DoCreatejob(); | |
| 542 } else { | |
| 543 DoSubmitdoc(); | |
| 544 } | |
| 545 } | |
| 546 | |
| 547 void PrivetLocalPrintOperationImpl::StartConvertToPWG() { | |
| 548 if (!pwg_raster_converter_) | |
| 549 pwg_raster_converter_ = PWGRasterConverter::CreateDefault(); | |
| 550 | |
| 551 pwg_raster_converter_->Start( | |
| 552 data_.get(), | |
| 553 PWGRasterConverter::GetConversionSettings(capabilities_, page_size_), | |
| 554 PWGRasterConverter::GetBitmapSettings(capabilities_, ticket_), | |
| 555 base::Bind(&PrivetLocalPrintOperationImpl::OnPWGRasterConverted, | |
| 556 base::Unretained(this))); | |
| 557 } | |
| 558 | |
| 559 void PrivetLocalPrintOperationImpl::OnSubmitdocResponse( | |
| 560 bool has_error, | |
| 561 const base::DictionaryValue* value) { | |
| 562 std::string error; | |
| 563 // This error is only relevant in the case of extended workflow: | |
| 564 // If the print job ID is invalid, retry createjob and submitdoc, | |
| 565 // rather than simply retrying the current request. | |
| 566 if (has_error && value->GetString(kPrivetKeyError, &error)) { | |
| 567 if (has_extended_workflow_ && | |
| 568 error == kPrivetErrorInvalidPrintJob && | |
| 569 invalid_job_retries_ < kPrivetLocalPrintMaxRetries) { | |
| 570 invalid_job_retries_++; | |
| 571 | |
| 572 int timeout = kPrivetLocalPrintDefaultTimeout; | |
| 573 value->GetInteger(kPrivetKeyTimeout, &timeout); | |
| 574 | |
| 575 double random_scaling_factor = | |
| 576 1 + base::RandDouble() * kPrivetMaximumTimeRandomAddition; | |
| 577 | |
| 578 timeout = static_cast<int>(timeout * random_scaling_factor); | |
| 579 | |
| 580 timeout = std::max(timeout, kPrivetMinimumTimeout); | |
| 581 | |
| 582 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 583 FROM_HERE, base::Bind(&PrivetLocalPrintOperationImpl::DoCreatejob, | |
| 584 weak_factory_.GetWeakPtr()), | |
| 585 base::TimeDelta::FromSeconds(timeout)); | |
| 586 } else if (use_pdf_ && error == kPrivetErrorInvalidDocumentType) { | |
| 587 use_pdf_ = false; | |
| 588 StartConvertToPWG(); | |
| 589 } else { | |
| 590 delegate_->OnPrivetPrintingError(this, 200); | |
| 591 } | |
| 592 | |
| 593 return; | |
| 594 } | |
| 595 | |
| 596 // If we've gotten this far, there are no errors, so we've effectively | |
| 597 // succeeded. | |
| 598 delegate_->OnPrivetPrintingDone(this); | |
| 599 } | |
| 600 | |
| 601 void PrivetLocalPrintOperationImpl::OnCreatejobResponse( | |
| 602 bool has_error, | |
| 603 const base::DictionaryValue* value) { | |
| 604 if (has_error) { | |
| 605 delegate_->OnPrivetPrintingError(this, 200); | |
| 606 return; | |
| 607 } | |
| 608 | |
| 609 // Try to get job ID from value. If not, jobid_ will be empty and we will use | |
| 610 // simple printing. | |
| 611 value->GetString(kPrivetKeyJobID, &jobid_); | |
| 612 | |
| 613 DoSubmitdoc(); | |
| 614 } | |
| 615 | |
| 616 void PrivetLocalPrintOperationImpl::OnPWGRasterConverted( | |
| 617 bool success, | |
| 618 const base::FilePath& pwg_file_path) { | |
| 619 if (!success) { | |
| 620 delegate_->OnPrivetPrintingError(this, -1); | |
| 621 return; | |
| 622 } | |
| 623 | |
| 624 DCHECK(!pwg_file_path.empty()); | |
| 625 | |
| 626 pwg_file_path_ = pwg_file_path; | |
| 627 StartPrinting(); | |
| 628 } | |
| 629 | |
| 630 PrivetHTTPClient* PrivetLocalPrintOperationImpl::GetHTTPClient() { | |
| 631 return privet_client_; | |
| 632 } | |
| 633 | |
| 634 void PrivetLocalPrintOperationImpl::OnError( | |
| 635 PrivetURLFetcher* fetcher, | |
| 636 PrivetURLFetcher::ErrorType error) { | |
| 637 delegate_->OnPrivetPrintingError(this, -1); | |
| 638 } | |
| 639 | |
| 640 void PrivetLocalPrintOperationImpl::OnParsedJson( | |
| 641 PrivetURLFetcher* fetcher, | |
| 642 const base::DictionaryValue& value, | |
| 643 bool has_error) { | |
| 644 DCHECK(!current_response_.is_null()); | |
| 645 current_response_.Run(has_error, &value); | |
| 646 } | |
| 647 | |
| 648 void PrivetLocalPrintOperationImpl::OnNeedPrivetToken( | |
| 649 PrivetURLFetcher* fetcher, | |
| 650 const PrivetURLFetcher::TokenCallback& callback) { | |
| 651 privet_client_->RefreshPrivetToken(callback); | |
| 652 } | |
| 653 | |
| 654 void PrivetLocalPrintOperationImpl::SetData( | |
| 655 const scoped_refptr<base::RefCountedBytes>& data) { | |
| 656 DCHECK(!started_); | |
| 657 data_ = data; | |
| 658 } | |
| 659 | |
| 660 void PrivetLocalPrintOperationImpl::SetTicket(const std::string& ticket) { | |
| 661 DCHECK(!started_); | |
| 662 ticket_.InitFromString(ticket); | |
| 663 } | |
| 664 | |
| 665 void PrivetLocalPrintOperationImpl::SetCapabilities( | |
| 666 const std::string& capabilities) { | |
| 667 DCHECK(!started_); | |
| 668 capabilities_.InitFromString(capabilities); | |
| 669 } | |
| 670 | |
| 671 void PrivetLocalPrintOperationImpl::SetUsername(const std::string& user) { | |
| 672 DCHECK(!started_); | |
| 673 user_ = user; | |
| 674 } | |
| 675 | |
| 676 void PrivetLocalPrintOperationImpl::SetJobname(const std::string& jobname) { | |
| 677 DCHECK(!started_); | |
| 678 jobname_ = jobname; | |
| 679 } | |
| 680 | |
| 681 void PrivetLocalPrintOperationImpl::SetOffline(bool offline) { | |
| 682 DCHECK(!started_); | |
| 683 offline_ = offline; | |
| 684 } | |
| 685 | |
| 686 void PrivetLocalPrintOperationImpl::SetPageSize(const gfx::Size& page_size) { | |
| 687 DCHECK(!started_); | |
| 688 page_size_ = page_size; | |
| 689 } | |
| 690 | |
| 691 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( | |
| 692 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { | |
| 693 pwg_raster_converter_ = std::move(pwg_raster_converter); | |
| 694 } | |
| 695 #endif // ENABLE_PRINT_PREVIEW | |
| 696 | |
| 697 PrivetHTTPClientImpl::PrivetHTTPClientImpl( | |
| 698 const std::string& name, | |
| 699 const net::HostPortPair& host_port, | |
| 700 const scoped_refptr<net::URLRequestContextGetter>& context_getter) | |
| 701 : name_(name), context_getter_(context_getter), host_port_(host_port) {} | |
| 702 | |
| 703 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { | |
| 704 } | |
| 705 | |
| 706 const std::string& PrivetHTTPClientImpl::GetName() { | |
| 707 return name_; | |
| 708 } | |
| 709 | |
| 710 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation( | |
| 711 const PrivetJSONOperation::ResultCallback& callback) { | |
| 712 return scoped_ptr<PrivetJSONOperation>( | |
| 713 new PrivetInfoOperationImpl(this, callback)); | |
| 714 } | |
| 715 | |
| 716 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher( | |
| 717 const GURL& url, | |
| 718 net::URLFetcher::RequestType request_type, | |
| 719 PrivetURLFetcher::Delegate* delegate) { | |
| 720 GURL::Replacements replacements; | |
| 721 std::string host = host_port_.HostForURL(); | |
| 722 replacements.SetHostStr(host); | |
| 723 std::string port = base::UintToString(host_port_.port()); | |
| 724 replacements.SetPortStr(port); | |
| 725 return scoped_ptr<PrivetURLFetcher>( | |
| 726 new PrivetURLFetcher(url.ReplaceComponents(replacements), request_type, | |
| 727 context_getter_, delegate)); | |
| 728 } | |
| 729 | |
| 730 void PrivetHTTPClientImpl::RefreshPrivetToken( | |
| 731 const PrivetURLFetcher::TokenCallback& callback) { | |
| 732 token_callbacks_.push_back(callback); | |
| 733 | |
| 734 if (!info_operation_) { | |
| 735 info_operation_ = CreateInfoOperation( | |
| 736 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone, | |
| 737 base::Unretained(this))); | |
| 738 info_operation_->Start(); | |
| 739 } | |
| 740 } | |
| 741 | |
| 742 void PrivetHTTPClientImpl::OnPrivetInfoDone( | |
| 743 const base::DictionaryValue* value) { | |
| 744 info_operation_.reset(); | |
| 745 std::string token; | |
| 746 | |
| 747 // If this does not succeed, token will be empty, and an empty string | |
| 748 // is our sentinel value, since empty X-Privet-Tokens are not allowed. | |
| 749 if (value) { | |
| 750 value->GetString(kPrivetInfoKeyToken, &token); | |
| 751 } | |
| 752 | |
| 753 TokenCallbackVector token_callbacks; | |
| 754 token_callbacks_.swap(token_callbacks); | |
| 755 | |
| 756 for (TokenCallbackVector::iterator i = token_callbacks.begin(); | |
| 757 i != token_callbacks.end(); i++) { | |
| 758 i->Run(token); | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 PrivetV1HTTPClientImpl::PrivetV1HTTPClientImpl( | |
| 763 scoped_ptr<PrivetHTTPClient> info_client) | |
| 764 : info_client_(std::move(info_client)) {} | |
| 765 | |
| 766 PrivetV1HTTPClientImpl::~PrivetV1HTTPClientImpl() { | |
| 767 } | |
| 768 | |
| 769 const std::string& PrivetV1HTTPClientImpl::GetName() { | |
| 770 return info_client()->GetName(); | |
| 771 } | |
| 772 | |
| 773 scoped_ptr<PrivetJSONOperation> PrivetV1HTTPClientImpl::CreateInfoOperation( | |
| 774 const PrivetJSONOperation::ResultCallback& callback) { | |
| 775 return info_client()->CreateInfoOperation(callback); | |
| 776 } | |
| 777 | |
| 778 scoped_ptr<PrivetRegisterOperation> | |
| 779 PrivetV1HTTPClientImpl::CreateRegisterOperation( | |
| 780 const std::string& user, | |
| 781 PrivetRegisterOperation::Delegate* delegate) { | |
| 782 return scoped_ptr<PrivetRegisterOperation>( | |
| 783 new PrivetRegisterOperationImpl(info_client(), user, delegate)); | |
| 784 } | |
| 785 | |
| 786 scoped_ptr<PrivetJSONOperation> | |
| 787 PrivetV1HTTPClientImpl::CreateCapabilitiesOperation( | |
| 788 const PrivetJSONOperation::ResultCallback& callback) { | |
| 789 return scoped_ptr<PrivetJSONOperation>(new PrivetJSONOperationImpl( | |
| 790 info_client(), kPrivetCapabilitiesPath, "", callback)); | |
| 791 } | |
| 792 | |
| 793 scoped_ptr<PrivetLocalPrintOperation> | |
| 794 PrivetV1HTTPClientImpl::CreateLocalPrintOperation( | |
| 795 PrivetLocalPrintOperation::Delegate* delegate) { | |
| 796 #if defined(ENABLE_PRINT_PREVIEW) | |
| 797 return scoped_ptr<PrivetLocalPrintOperation>( | |
| 798 new PrivetLocalPrintOperationImpl(info_client(), delegate)); | |
| 799 #else | |
| 800 return scoped_ptr<PrivetLocalPrintOperation>(); | |
| 801 #endif // ENABLE_PRINT_PREVIEW | |
| 802 } | |
| 803 | |
| 804 } // namespace local_discovery | |
| OLD | NEW |