|
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | 15 | #include "google/cloud/storage/client.h" |
| 16 | +#include "google/cloud/storage/idempotency_policy.h" |
16 | 17 | #include "google/cloud/storage/internal/base64.h" |
17 | 18 | #include "google/cloud/storage/internal/connection_factory.h" |
| 19 | +#include "google/cloud/storage/internal/unified_rest_credentials.h" |
| 20 | +#include "google/cloud/storage/oauth2/credentials.h" |
| 21 | +#include "google/cloud/storage/oauth2/google_credentials.h" |
18 | 22 | #include "google/cloud/storage/oauth2/service_account_credentials.h" |
| 23 | +#include "google/cloud/storage/options.h" |
19 | 24 | #include "google/cloud/internal/absl_str_cat_quiet.h" |
| 25 | +#include "google/cloud/internal/absl_str_join_quiet.h" |
20 | 26 | #include "google/cloud/internal/curl_handle.h" |
21 | 27 | #include "google/cloud/internal/curl_options.h" |
22 | 28 | #include "google/cloud/internal/filesystem.h" |
| 29 | +#include "google/cloud/internal/getenv.h" |
23 | 30 | #include "google/cloud/internal/make_status.h" |
24 | 31 | #include "google/cloud/internal/opentelemetry.h" |
| 32 | +#include "google/cloud/internal/populate_common_options.h" |
| 33 | +#include "google/cloud/internal/rest_options.h" |
| 34 | +#include "google/cloud/internal/rest_response.h" |
| 35 | +#include "google/cloud/internal/service_endpoint.h" |
25 | 36 | #include "google/cloud/log.h" |
| 37 | +#include "google/cloud/opentelemetry_options.h" |
| 38 | +#include "google/cloud/universe_domain_options.h" |
26 | 39 | #include "absl/strings/str_split.h" |
| 40 | +#include <cstdlib> |
27 | 41 | #include <fstream> |
28 | 42 | #include <memory> |
| 43 | +#include <set> |
| 44 | +#include <sstream> |
29 | 45 | #include <string> |
30 | 46 | #include <thread> |
31 | 47 | #include <utility> |
@@ -387,8 +403,219 @@ std::string Client::EndpointAuthority() const { |
387 | 403 | return std::string(endpoint_authority); |
388 | 404 | } |
389 | 405 |
|
| 406 | +// This magic number was obtained by experimentation summarized in #2657 |
| 407 | +#ifndef GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_UPLOAD_BUFFER_SIZE |
| 408 | +#define GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_UPLOAD_BUFFER_SIZE (8 * 1024 * 1024) |
| 409 | +#endif // GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_UPLOAD_BUFFER_SIZE |
| 410 | + |
| 411 | +// This magic number was obtained by experimentation summarized in #2657 |
| 412 | +#ifndef GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_BUFFER_SIZE |
| 413 | +#define GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_BUFFER_SIZE \ |
| 414 | + (3 * 1024 * 1024 / 2) |
| 415 | +#endif // GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_BUFFER_SIZE |
| 416 | + |
| 417 | +// This is a result of experiments performed in #2657. |
| 418 | +#ifndef GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_MAXIMUM_SIMPLE_UPLOAD_SIZE |
| 419 | +#define GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_MAXIMUM_SIMPLE_UPLOAD_SIZE \ |
| 420 | + (20 * 1024 * 1024L) |
| 421 | +#endif // GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_MAXIMUM_SIMPLE_UPLOAD_SIZE |
| 422 | + |
| 423 | +#ifndef GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_STALL_TIMEOUT |
| 424 | +#define GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_STALL_TIMEOUT 120 |
| 425 | +#endif // GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_STALL_TIMEOUT |
| 426 | + |
| 427 | +// Define the defaults using a pre-processor macro, this allows the application |
| 428 | +// developers to change the defaults for their application by compiling with |
| 429 | +// different values. |
| 430 | +#ifndef STORAGE_CLIENT_DEFAULT_MAXIMUM_RETRY_PERIOD |
| 431 | +#define STORAGE_CLIENT_DEFAULT_MAXIMUM_RETRY_PERIOD std::chrono::minutes(15) |
| 432 | +#endif // STORAGE_CLIENT_DEFAULT_MAXIMUM_RETRY_PERIOD |
| 433 | + |
| 434 | +#ifndef STORAGE_CLIENT_DEFAULT_INITIAL_BACKOFF_DELAY |
| 435 | +#define STORAGE_CLIENT_DEFAULT_INITIAL_BACKOFF_DELAY std::chrono::seconds(1) |
| 436 | +#endif // STORAGE_CLIENT_DEFAULT_INITIAL_BACKOFF_DELAY |
| 437 | + |
| 438 | +#ifndef STORAGE_CLIENT_DEFAULT_MAXIMUM_BACKOFF_DELAY |
| 439 | +#define STORAGE_CLIENT_DEFAULT_MAXIMUM_BACKOFF_DELAY std::chrono::minutes(5) |
| 440 | +#endif // STORAGE_CLIENT_DEFAULT_MAXIMUM_BACKOFF_DELAY |
| 441 | + |
| 442 | +#ifndef STORAGE_CLIENT_DEFAULT_BACKOFF_SCALING |
| 443 | +#define STORAGE_CLIENT_DEFAULT_BACKOFF_SCALING 2.0 |
| 444 | +#endif // STORAGE_CLIENT_DEFAULT_BACKOFF_SCALING |
| 445 | + |
| 446 | +namespace { |
| 447 | + |
| 448 | +using ::google::cloud::internal::GetEnv; |
| 449 | + |
| 450 | +absl::optional<std::string> GetEmulator() { |
| 451 | + auto emulator = GetEnv("CLOUD_STORAGE_EMULATOR_ENDPOINT"); |
| 452 | + if (emulator) return emulator; |
| 453 | + return GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT"); |
| 454 | +} |
| 455 | + |
| 456 | +std::size_t DefaultConnectionPoolSize() { |
| 457 | + std::size_t nthreads = std::thread::hardware_concurrency(); |
| 458 | + if (nthreads == 0) { |
| 459 | + return 4; |
| 460 | + } |
| 461 | + return 4 * nthreads; |
| 462 | +} |
| 463 | + |
| 464 | +} // namespace |
| 465 | + |
390 | 466 | namespace internal { |
391 | 467 |
|
| 468 | +Options ApplyPolicy(Options opts, RetryPolicy const& p) { |
| 469 | + opts.set<RetryPolicyOption>(p.clone()); |
| 470 | + return opts; |
| 471 | +} |
| 472 | + |
| 473 | +Options ApplyPolicy(Options opts, BackoffPolicy const& p) { |
| 474 | + opts.set<BackoffPolicyOption>(p.clone()); |
| 475 | + return opts; |
| 476 | +} |
| 477 | + |
| 478 | +Options ApplyPolicy(Options opts, IdempotencyPolicy const& p) { |
| 479 | + opts.set<IdempotencyPolicyOption>(p.clone()); |
| 480 | + return opts; |
| 481 | +} |
| 482 | + |
| 483 | +Options DefaultOptions(std::shared_ptr<oauth2::Credentials> credentials, |
| 484 | + Options opts) { |
| 485 | + auto ud = GetEnv("GOOGLE_CLOUD_UNIVERSE_DOMAIN"); |
| 486 | + if (ud && !ud->empty()) { |
| 487 | + opts.set<google::cloud::internal::UniverseDomainOption>(*std::move(ud)); |
| 488 | + } |
| 489 | + auto gcs_ep = google::cloud::internal::UniverseDomainEndpoint( |
| 490 | + "https://storage.googleapis.com", opts); |
| 491 | + auto iam_ep = absl::StrCat(google::cloud::internal::UniverseDomainEndpoint( |
| 492 | + "https://iamcredentials.googleapis.com", opts), |
| 493 | + "/v1"); |
| 494 | + auto o = |
| 495 | + Options{} |
| 496 | + .set<Oauth2CredentialsOption>(std::move(credentials)) |
| 497 | + .set<RestEndpointOption>(std::move(gcs_ep)) |
| 498 | + .set<IamEndpointOption>(std::move(iam_ep)) |
| 499 | + .set<TargetApiVersionOption>("v1") |
| 500 | + .set<ConnectionPoolSizeOption>(DefaultConnectionPoolSize()) |
| 501 | + .set<DownloadBufferSizeOption>( |
| 502 | + GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_BUFFER_SIZE) |
| 503 | + .set<UploadBufferSizeOption>( |
| 504 | + GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_UPLOAD_BUFFER_SIZE) |
| 505 | + .set<MaximumSimpleUploadSizeOption>( |
| 506 | + GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_MAXIMUM_SIMPLE_UPLOAD_SIZE) |
| 507 | + .set<EnableCurlSslLockingOption>(true) |
| 508 | + .set<EnableCurlSigpipeHandlerOption>(true) |
| 509 | + .set<MaximumCurlSocketRecvSizeOption>(0) |
| 510 | + .set<MaximumCurlSocketSendSizeOption>(0) |
| 511 | + .set<TransferStallTimeoutOption>(std::chrono::seconds( |
| 512 | + GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_STALL_TIMEOUT)) |
| 513 | + .set<TransferStallMinimumRateOption>(1) |
| 514 | + .set<DownloadStallMinimumRateOption>(1) |
| 515 | + .set<RetryPolicyOption>( |
| 516 | + LimitedTimeRetryPolicy( |
| 517 | + STORAGE_CLIENT_DEFAULT_MAXIMUM_RETRY_PERIOD) |
| 518 | + .clone()) |
| 519 | + .set<BackoffPolicyOption>( |
| 520 | + ExponentialBackoffPolicy( |
| 521 | + STORAGE_CLIENT_DEFAULT_INITIAL_BACKOFF_DELAY, |
| 522 | + STORAGE_CLIENT_DEFAULT_MAXIMUM_BACKOFF_DELAY, |
| 523 | + STORAGE_CLIENT_DEFAULT_BACKOFF_SCALING) |
| 524 | + .clone()) |
| 525 | + .set<IdempotencyPolicyOption>(AlwaysRetryIdempotencyPolicy().clone()); |
| 526 | + |
| 527 | + o = google::cloud::internal::MergeOptions(std::move(opts), std::move(o)); |
| 528 | + // If the application did not set `DownloadStallTimeoutOption` then use the |
| 529 | + // same value as `TransferStallTimeoutOption` (which could be the default |
| 530 | + // value). Some applications need tighter timeouts for downloads, but longer |
| 531 | + // timeouts for other transfers. |
| 532 | + if (!o.has<DownloadStallTimeoutOption>()) { |
| 533 | + o.set<DownloadStallTimeoutOption>(o.get<TransferStallTimeoutOption>()); |
| 534 | + } |
| 535 | + |
| 536 | + auto emulator = GetEmulator(); |
| 537 | + if (emulator.has_value()) { |
| 538 | + o.set<RestEndpointOption>(*emulator).set<IamEndpointOption>(*emulator + |
| 539 | + "/iamapi"); |
| 540 | + } |
| 541 | + |
| 542 | + auto logging = GetEnv("CLOUD_STORAGE_ENABLE_TRACING"); |
| 543 | + if (logging) { |
| 544 | + for (auto c : absl::StrSplit(*logging, ',')) { |
| 545 | + GCP_LOG(INFO) << "Enabling logging for " << c; |
| 546 | + o.lookup<LoggingComponentsOption>().insert(std::string(c)); |
| 547 | + } |
| 548 | + } |
| 549 | + |
| 550 | + auto tracing = GetEnv("GOOGLE_CLOUD_CPP_OPENTELEMETRY_TRACING"); |
| 551 | + if (tracing && !tracing->empty()) { |
| 552 | + o.set<OpenTelemetryTracingOption>(true); |
| 553 | + } |
| 554 | + |
| 555 | + auto project_id = GetEnv("GOOGLE_CLOUD_PROJECT"); |
| 556 | + if (project_id.has_value()) { |
| 557 | + o.set<ProjectIdOption>(std::move(*project_id)); |
| 558 | + } |
| 559 | + |
| 560 | + // Always apply the RestClient defaults, even if it is not in use. Now that we |
| 561 | + // use the low-level initialization code in |
| 562 | + // google/cloud/internal/curl_wrappers.cc, these are always needed. |
| 563 | + namespace rest = ::google::cloud::rest_internal; |
| 564 | + auto rest_defaults = Options{} |
| 565 | + .set<rest::DownloadStallTimeoutOption>( |
| 566 | + o.get<DownloadStallTimeoutOption>()) |
| 567 | + .set<rest::DownloadStallMinimumRateOption>( |
| 568 | + o.get<DownloadStallMinimumRateOption>()) |
| 569 | + .set<rest::TransferStallTimeoutOption>( |
| 570 | + o.get<TransferStallTimeoutOption>()) |
| 571 | + .set<rest::TransferStallMinimumRateOption>( |
| 572 | + o.get<TransferStallMinimumRateOption>()) |
| 573 | + .set<rest::MaximumCurlSocketRecvSizeOption>( |
| 574 | + o.get<MaximumCurlSocketRecvSizeOption>()) |
| 575 | + .set<rest::MaximumCurlSocketSendSizeOption>( |
| 576 | + o.get<MaximumCurlSocketSendSizeOption>()) |
| 577 | + .set<rest::ConnectionPoolSizeOption>( |
| 578 | + o.get<ConnectionPoolSizeOption>()) |
| 579 | + .set<rest::EnableCurlSslLockingOption>( |
| 580 | + o.get<EnableCurlSslLockingOption>()) |
| 581 | + .set<rest::EnableCurlSigpipeHandlerOption>( |
| 582 | + o.get<EnableCurlSigpipeHandlerOption>()); |
| 583 | + |
| 584 | + // These two are not always present, but if they are, and only if they are, we |
| 585 | + // need to map their value to the corresponding option in `rest_internal::`. |
| 586 | + if (o.has<storage_experimental::HttpVersionOption>()) { |
| 587 | + rest_defaults.set<rest::HttpVersionOption>( |
| 588 | + o.get<storage_experimental::HttpVersionOption>()); |
| 589 | + } |
| 590 | + if (o.has<internal::CAPathOption>()) { |
| 591 | + rest_defaults.set<rest::CAPathOption>(o.get<internal::CAPathOption>()); |
| 592 | + } |
| 593 | + |
| 594 | + return google::cloud::internal::MergeOptions(std::move(o), |
| 595 | + std::move(rest_defaults)); |
| 596 | +} |
| 597 | + |
| 598 | +Options DefaultOptionsWithCredentials(Options opts) { |
| 599 | + if (opts.has<Oauth2CredentialsOption>()) { |
| 600 | + auto credentials = opts.get<Oauth2CredentialsOption>(); |
| 601 | + return internal::DefaultOptions(std::move(credentials), std::move(opts)); |
| 602 | + } |
| 603 | + if (opts.has<UnifiedCredentialsOption>()) { |
| 604 | + auto credentials = |
| 605 | + internal::MapCredentials(*opts.get<UnifiedCredentialsOption>()); |
| 606 | + return internal::DefaultOptions(std::move(credentials), std::move(opts)); |
| 607 | + } |
| 608 | + if (GetEmulator().has_value()) { |
| 609 | + return internal::DefaultOptions( |
| 610 | + internal::MapCredentials(*google::cloud::MakeInsecureCredentials()), |
| 611 | + std::move(opts)); |
| 612 | + } |
| 613 | + auto credentials = |
| 614 | + internal::MapCredentials(*google::cloud::MakeGoogleDefaultCredentials( |
| 615 | + google::cloud::internal::MakeAuthOptions(opts))); |
| 616 | + return internal::DefaultOptions(std::move(credentials), std::move(opts)); |
| 617 | +} |
| 618 | + |
392 | 619 | Client ClientImplDetails::CreateWithDecorations( |
393 | 620 | Options const& opts, std::shared_ptr<StorageConnection> connection) { |
394 | 621 | return Client( |
|
0 commit comments