protobuf_http_client.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2020 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. #include "remoting/base/protobuf_http_client.h"
  5. #include "base/strings/stringprintf.h"
  6. #include "net/base/load_flags.h"
  7. #include "net/base/net_errors.h"
  8. #include "remoting/base/oauth_token_getter.h"
  9. #include "remoting/base/protobuf_http_request_base.h"
  10. #include "remoting/base/protobuf_http_request_config.h"
  11. #include "remoting/base/protobuf_http_status.h"
  12. #include "services/network/public/cpp/resource_request.h"
  13. #include "services/network/public/cpp/shared_url_loader_factory.h"
  14. #include "services/network/public/cpp/simple_url_loader.h"
  15. #include "third_party/protobuf/src/google/protobuf/message_lite.h"
  16. #include "url/gurl.h"
  17. namespace {
  18. constexpr char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
  19. constexpr char kApiKeyHeaderFormat[] = "x-goog-api-key: %s";
  20. } // namespace
  21. namespace remoting {
  22. ProtobufHttpClient::ProtobufHttpClient(
  23. const std::string& server_endpoint,
  24. OAuthTokenGetter* token_getter,
  25. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
  26. : server_endpoint_(server_endpoint),
  27. token_getter_(token_getter),
  28. url_loader_factory_(url_loader_factory) {}
  29. ProtobufHttpClient::~ProtobufHttpClient() {
  30. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  31. }
  32. void ProtobufHttpClient::ExecuteRequest(
  33. std::unique_ptr<ProtobufHttpRequestBase> request) {
  34. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  35. if (!request->config().authenticated) {
  36. DoExecuteRequest(std::move(request), OAuthTokenGetter::Status::SUCCESS, {},
  37. {});
  38. return;
  39. }
  40. DCHECK(token_getter_);
  41. token_getter_->CallWithToken(
  42. base::BindOnce(&ProtobufHttpClient::DoExecuteRequest,
  43. weak_factory_.GetWeakPtr(), std::move(request)));
  44. }
  45. void ProtobufHttpClient::CancelPendingRequests() {
  46. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  47. weak_factory_.InvalidateWeakPtrs();
  48. pending_requests_.clear();
  49. }
  50. bool ProtobufHttpClient::HasPendingRequests() const {
  51. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  52. return !pending_requests_.empty();
  53. }
  54. void ProtobufHttpClient::DoExecuteRequest(
  55. std::unique_ptr<ProtobufHttpRequestBase> request,
  56. OAuthTokenGetter::Status status,
  57. const std::string& user_email,
  58. const std::string& access_token) {
  59. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  60. if (status != OAuthTokenGetter::Status::SUCCESS) {
  61. std::string error_message =
  62. base::StringPrintf("Failed to fetch access token. Status: %d", status);
  63. LOG(ERROR) << error_message;
  64. ProtobufHttpStatus::Code code;
  65. switch (status) {
  66. case OAuthTokenGetter::Status::AUTH_ERROR:
  67. code = ProtobufHttpStatus::Code::UNAUTHENTICATED;
  68. break;
  69. case OAuthTokenGetter::Status::NETWORK_ERROR:
  70. code = ProtobufHttpStatus::Code::UNAVAILABLE;
  71. break;
  72. default:
  73. NOTREACHED() << "Unknown OAuthTokenGetter Status: " << status;
  74. code = ProtobufHttpStatus::Code::UNKNOWN;
  75. }
  76. request->OnAuthFailed(ProtobufHttpStatus(code, error_message));
  77. return;
  78. }
  79. auto resource_request = std::make_unique<network::ResourceRequest>();
  80. resource_request->url =
  81. GURL("https://" + server_endpoint_ + request->config().path);
  82. resource_request->load_flags =
  83. net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE;
  84. resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
  85. resource_request->method = net::HttpRequestHeaders::kPostMethod;
  86. if (status == OAuthTokenGetter::Status::SUCCESS && !access_token.empty()) {
  87. resource_request->headers.AddHeaderFromString(
  88. base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
  89. } else {
  90. VLOG(1) << "Attempting to execute request without access token";
  91. }
  92. if (!request->config().api_key.empty()) {
  93. resource_request->headers.AddHeaderFromString(base::StringPrintf(
  94. kApiKeyHeaderFormat, request->config().api_key.c_str()));
  95. }
  96. std::unique_ptr<network::SimpleURLLoader> send_url_loader =
  97. network::SimpleURLLoader::Create(std::move(resource_request),
  98. request->config().traffic_annotation);
  99. base::TimeDelta timeout_duration = request->GetRequestTimeoutDuration();
  100. if (!timeout_duration.is_zero()) {
  101. send_url_loader->SetTimeoutDuration(request->GetRequestTimeoutDuration());
  102. }
  103. send_url_loader->AttachStringForUpload(
  104. request->config().request_message->SerializeAsString(),
  105. "application/x-protobuf");
  106. send_url_loader->SetAllowHttpErrorResults(true);
  107. auto* unowned_request = request.get();
  108. base::OnceClosure invalidator = base::BindOnce(
  109. &ProtobufHttpClient::CancelRequest, weak_factory_.GetWeakPtr(),
  110. pending_requests_.insert(pending_requests_.end(), std::move(request)));
  111. unowned_request->StartRequest(url_loader_factory_.get(),
  112. std::move(send_url_loader),
  113. std::move(invalidator));
  114. }
  115. void ProtobufHttpClient::CancelRequest(
  116. const PendingRequestListIterator& request_iterator) {
  117. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  118. pending_requests_.erase(request_iterator);
  119. }
  120. } // namespace remoting