endpoint_fetcher.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Copyright 2019 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 "components/endpoint_fetcher/endpoint_fetcher.h"
  5. #include "base/strings/string_util.h"
  6. #include "base/strings/stringprintf.h"
  7. #include "components/signin/public/identity_manager/access_token_info.h"
  8. #include "components/signin/public/identity_manager/identity_manager.h"
  9. #include "components/version_info/channel.h"
  10. #include "google_apis/gaia/gaia_urls.h"
  11. #include "google_apis/google_api_keys.h"
  12. #include "net/http/http_status_code.h"
  13. #include "services/network/public/cpp/resource_request.h"
  14. #include "services/network/public/cpp/shared_url_loader_factory.h"
  15. #include "services/network/public/cpp/simple_url_loader.h"
  16. #include "services/network/public/mojom/url_response_head.mojom.h"
  17. namespace {
  18. const char kContentTypeKey[] = "Content-Type";
  19. const char kDeveloperKey[] = "X-Developer-Key";
  20. const int kNumRetries = 3;
  21. const int64_t kDefaultTimeOutMs = 30000;
  22. } // namespace
  23. EndpointFetcher::EndpointFetcher(
  24. const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
  25. const std::string& oauth_consumer_name,
  26. const GURL& url,
  27. const std::string& http_method,
  28. const std::string& content_type,
  29. const std::vector<std::string>& scopes,
  30. int64_t timeout_ms,
  31. const std::string& post_data,
  32. const net::NetworkTrafficAnnotationTag& annotation_tag,
  33. signin::IdentityManager* const identity_manager)
  34. : EndpointFetcher(oauth_consumer_name,
  35. url,
  36. http_method,
  37. content_type,
  38. scopes,
  39. timeout_ms,
  40. post_data,
  41. annotation_tag,
  42. url_loader_factory,
  43. identity_manager) {}
  44. EndpointFetcher::EndpointFetcher(
  45. const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
  46. const GURL& url,
  47. const std::string& http_method,
  48. const std::string& content_type,
  49. int64_t timeout_ms,
  50. const std::string& post_data,
  51. const std::vector<std::string>& headers,
  52. const net::NetworkTrafficAnnotationTag& annotation_tag,
  53. bool is_stable_channel)
  54. : auth_type_(CHROME_API_KEY),
  55. url_(url),
  56. http_method_(http_method),
  57. content_type_(content_type),
  58. timeout_ms_(timeout_ms),
  59. post_data_(post_data),
  60. headers_(headers),
  61. annotation_tag_(annotation_tag),
  62. url_loader_factory_(url_loader_factory),
  63. identity_manager_(nullptr),
  64. sanitize_response_(true),
  65. is_stable_channel_(is_stable_channel) {}
  66. EndpointFetcher::EndpointFetcher(
  67. const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
  68. const GURL& url,
  69. const net::NetworkTrafficAnnotationTag& annotation_tag)
  70. : auth_type_(NO_AUTH),
  71. url_(url),
  72. http_method_("GET"),
  73. content_type_(std::string()),
  74. timeout_ms_(0),
  75. post_data_(std::string()),
  76. annotation_tag_(annotation_tag),
  77. url_loader_factory_(url_loader_factory),
  78. identity_manager_(nullptr),
  79. sanitize_response_(false) {}
  80. EndpointFetcher::EndpointFetcher(
  81. const std::string& oauth_consumer_name,
  82. const GURL& url,
  83. const std::string& http_method,
  84. const std::string& content_type,
  85. const std::vector<std::string>& scopes,
  86. int64_t timeout_ms,
  87. const std::string& post_data,
  88. const net::NetworkTrafficAnnotationTag& annotation_tag,
  89. const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
  90. signin::IdentityManager* const identity_manager)
  91. : auth_type_(OAUTH),
  92. oauth_consumer_name_(oauth_consumer_name),
  93. url_(url),
  94. http_method_(http_method),
  95. content_type_(content_type),
  96. timeout_ms_(timeout_ms),
  97. post_data_(post_data),
  98. annotation_tag_(annotation_tag),
  99. url_loader_factory_(url_loader_factory),
  100. identity_manager_(identity_manager),
  101. sanitize_response_(true) {
  102. for (auto scope : scopes) {
  103. oauth_scopes_.insert(scope);
  104. }
  105. }
  106. EndpointFetcher::EndpointFetcher(
  107. const GURL& url,
  108. const std::string& http_method,
  109. const std::string& content_type,
  110. int64_t timeout_ms,
  111. const std::string& post_data,
  112. const std::vector<std::string>& headers,
  113. const std::vector<std::string>& cors_exempt_headers,
  114. const net::NetworkTrafficAnnotationTag& annotation_tag,
  115. const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
  116. const bool is_oauth_fetch)
  117. : auth_type_(is_oauth_fetch ? OAUTH : CHROME_API_KEY),
  118. url_(url),
  119. http_method_(http_method),
  120. content_type_(content_type),
  121. timeout_ms_(timeout_ms),
  122. post_data_(post_data),
  123. headers_(headers),
  124. cors_exempt_headers_(cors_exempt_headers),
  125. annotation_tag_(annotation_tag),
  126. url_loader_factory_(url_loader_factory),
  127. identity_manager_(nullptr),
  128. sanitize_response_(true) {}
  129. EndpointFetcher::EndpointFetcher(
  130. const net::NetworkTrafficAnnotationTag& annotation_tag)
  131. : timeout_ms_(kDefaultTimeOutMs),
  132. annotation_tag_(annotation_tag),
  133. identity_manager_(nullptr),
  134. sanitize_response_(true) {}
  135. EndpointFetcher::~EndpointFetcher() = default;
  136. void EndpointFetcher::Fetch(EndpointFetcherCallback endpoint_fetcher_callback) {
  137. DCHECK(!access_token_fetcher_);
  138. DCHECK(!simple_url_loader_);
  139. DCHECK(identity_manager_);
  140. // Check if we have a primary account with the default consent level "sync"
  141. // before attempting to fetch a token.
  142. if (!identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync)) {
  143. auto response = std::make_unique<EndpointResponse>();
  144. VLOG(1) << __func__ << " No primary accounts found";
  145. response->response = "No primary accounts found";
  146. response->error_type =
  147. absl::make_optional<FetchErrorType>(FetchErrorType::kAuthError);
  148. // TODO(crbug.com/993393) Add more detailed error messaging
  149. std::move(endpoint_fetcher_callback).Run(std::move(response));
  150. return;
  151. }
  152. signin::AccessTokenFetcher::TokenCallback token_callback = base::BindOnce(
  153. &EndpointFetcher::OnAuthTokenFetched, weak_ptr_factory_.GetWeakPtr(),
  154. std::move(endpoint_fetcher_callback));
  155. // TODO(crbug.com/997018) Make access_token_fetcher_ local variable passed
  156. // to callback
  157. access_token_fetcher_ =
  158. std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
  159. oauth_consumer_name_, identity_manager_, oauth_scopes_,
  160. std::move(token_callback),
  161. signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
  162. }
  163. void EndpointFetcher::OnAuthTokenFetched(
  164. EndpointFetcherCallback endpoint_fetcher_callback,
  165. GoogleServiceAuthError error,
  166. signin::AccessTokenInfo access_token_info) {
  167. access_token_fetcher_.reset();
  168. if (error.state() != GoogleServiceAuthError::NONE) {
  169. auto response = std::make_unique<EndpointResponse>();
  170. response->response = "There was an authentication error";
  171. response->error_type =
  172. absl::make_optional<FetchErrorType>(FetchErrorType::kAuthError);
  173. // TODO(crbug.com/993393) Add more detailed error messaging
  174. std::move(endpoint_fetcher_callback).Run(std::move(response));
  175. return;
  176. }
  177. PerformRequest(std::move(endpoint_fetcher_callback),
  178. access_token_info.token.c_str());
  179. }
  180. void EndpointFetcher::PerformRequest(
  181. EndpointFetcherCallback endpoint_fetcher_callback,
  182. const char* key) {
  183. auto resource_request = std::make_unique<network::ResourceRequest>();
  184. resource_request->method = http_method_;
  185. resource_request->url = url_;
  186. resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
  187. if (base::EqualsCaseInsensitiveASCII(http_method_, "POST")) {
  188. resource_request->headers.SetHeader(kContentTypeKey, content_type_);
  189. }
  190. DCHECK(headers_.size() % 2 == 0);
  191. for (size_t i = 0; i + 1 < headers_.size(); i += 2) {
  192. resource_request->headers.SetHeader(headers_[i], headers_[i + 1]);
  193. }
  194. DCHECK(cors_exempt_headers_.size() % 2 == 0);
  195. for (size_t i = 0; i + 1 < cors_exempt_headers_.size(); i += 2) {
  196. resource_request->cors_exempt_headers.SetHeaderIfMissing(
  197. cors_exempt_headers_[i], cors_exempt_headers_[i + 1]);
  198. }
  199. switch (auth_type_) {
  200. case OAUTH:
  201. resource_request->headers.SetHeader(
  202. kDeveloperKey, GaiaUrls::GetInstance()->oauth2_chrome_client_id());
  203. resource_request->headers.SetHeader(
  204. net::HttpRequestHeaders::kAuthorization,
  205. base::StringPrintf("Bearer %s", key));
  206. break;
  207. case CHROME_API_KEY: {
  208. std::string api_key = is_stable_channel_
  209. ? google_apis::GetAPIKey()
  210. : google_apis::GetNonStableAPIKey();
  211. resource_request->headers.SetHeader("x-goog-api-key", api_key);
  212. break;
  213. }
  214. default:
  215. break;
  216. }
  217. // TODO(crbug.com/997018) Make simple_url_loader_ local variable passed to
  218. // callback
  219. simple_url_loader_ = network::SimpleURLLoader::Create(
  220. std::move(resource_request), annotation_tag_);
  221. if (base::EqualsCaseInsensitiveASCII(http_method_, "POST")) {
  222. simple_url_loader_->AttachStringForUpload(post_data_, content_type_);
  223. }
  224. simple_url_loader_->SetRetryOptions(kNumRetries,
  225. network::SimpleURLLoader::RETRY_ON_5XX);
  226. simple_url_loader_->SetTimeoutDuration(base::Milliseconds(timeout_ms_));
  227. simple_url_loader_->SetAllowHttpErrorResults(true);
  228. network::SimpleURLLoader::BodyAsStringCallback body_as_string_callback =
  229. base::BindOnce(&EndpointFetcher::OnResponseFetched,
  230. weak_ptr_factory_.GetWeakPtr(),
  231. std::move(endpoint_fetcher_callback));
  232. simple_url_loader_->DownloadToString(
  233. url_loader_factory_.get(), std::move(body_as_string_callback),
  234. network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
  235. }
  236. void EndpointFetcher::OnResponseFetched(
  237. EndpointFetcherCallback endpoint_fetcher_callback,
  238. std::unique_ptr<std::string> response_body) {
  239. int http_status_code = -1;
  240. if (simple_url_loader_->ResponseInfo() &&
  241. simple_url_loader_->ResponseInfo()->headers) {
  242. http_status_code =
  243. simple_url_loader_->ResponseInfo()->headers->response_code();
  244. }
  245. int net_error_code = simple_url_loader_->NetError();
  246. // The EndpointFetcher and its members will be destroyed after
  247. // any of the below callbacks. Do not access The EndpointFetcher
  248. // or its members after the callbacks.
  249. simple_url_loader_.reset();
  250. auto response = std::make_unique<EndpointResponse>();
  251. response->http_status_code = http_status_code;
  252. if (net_error_code != net::OK) {
  253. response->error_type =
  254. absl::make_optional<FetchErrorType>(FetchErrorType::kNetError);
  255. }
  256. if (response_body) {
  257. if (sanitize_response_) {
  258. data_decoder::JsonSanitizer::Sanitize(
  259. std::move(*response_body),
  260. base::BindOnce(&EndpointFetcher::OnSanitizationResult,
  261. weak_ptr_factory_.GetWeakPtr(), std::move(response),
  262. std::move(endpoint_fetcher_callback)));
  263. } else {
  264. response->response = *response_body;
  265. std::move(endpoint_fetcher_callback).Run(std::move(response));
  266. }
  267. } else {
  268. std::string net_error = net::ErrorToString(net_error_code);
  269. VLOG(1) << __func__ << " with response error: " << net_error;
  270. response->response = "There was a response error";
  271. std::move(endpoint_fetcher_callback).Run(std::move(response));
  272. }
  273. }
  274. void EndpointFetcher::OnSanitizationResult(
  275. std::unique_ptr<EndpointResponse> response,
  276. EndpointFetcherCallback endpoint_fetcher_callback,
  277. data_decoder::JsonSanitizer::Result result) {
  278. if (result.value.has_value()) {
  279. response->response = result.value.value();
  280. } else if (result.error.has_value()) {
  281. response->error_type =
  282. absl::make_optional<FetchErrorType>(FetchErrorType::kResultParseError);
  283. response->response =
  284. "There was a sanitization error: " + result.error.value();
  285. } else {
  286. response->error_type =
  287. absl::make_optional<FetchErrorType>(FetchErrorType::kResultParseError);
  288. response->response = "There was an unknown sanitization error";
  289. }
  290. // The EndpointFetcher and its members will be destroyed after
  291. // any the below callback. Do not access The EndpointFetcher
  292. // or its members after the callback.
  293. std::move(endpoint_fetcher_callback).Run(std::move(response));
  294. }
  295. std::string EndpointFetcher::GetUrlForTesting() {
  296. return url_.spec();
  297. }