1 // Copyright (c) 2012 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 "google_apis/gaia/oauth2_api_call_flow.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/strings/stringprintf.h"
12 #include "google_apis/gaia/gaia_auth_util.h"
13 #include "google_apis/gaia/gaia_urls.h"
14 #include "net/base/escape.h"
15 #include "net/base/load_flags.h"
16 #include "net/http/http_status_code.h"
17 #include "services/network/public/cpp/resource_request.h"
18 #include "services/network/public/cpp/shared_url_loader_factory.h"
19 #include "services/network/public/cpp/simple_url_loader.h"
20 #include "services/network/public/mojom/url_response_head.mojom.h"
21 
22 namespace {
23 static const char kAuthorizationValueFormat[] = "Bearer %s";
24 
MakeAuthorizationValue(const std::string & auth_token)25 static std::string MakeAuthorizationValue(const std::string& auth_token) {
26   return base::StringPrintf(kAuthorizationValueFormat, auth_token.c_str());
27 }
28 }  // namespace
29 
OAuth2ApiCallFlow()30 OAuth2ApiCallFlow::OAuth2ApiCallFlow() : state_(INITIAL) {
31 }
32 
~OAuth2ApiCallFlow()33 OAuth2ApiCallFlow::~OAuth2ApiCallFlow() {}
34 
Start(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,const std::string & access_token)35 void OAuth2ApiCallFlow::Start(
36     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
37     const std::string& access_token) {
38   CHECK(state_ == INITIAL);
39   state_ = API_CALL_STARTED;
40 
41   url_loader_ = CreateURLLoader(access_token);
42   url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
43       url_loader_factory.get(),
44       base::BindOnce(&OAuth2ApiCallFlow::OnURLLoadComplete,
45                      base::Unretained(this)));
46 }
47 
EndApiCall(std::unique_ptr<std::string> body)48 void OAuth2ApiCallFlow::EndApiCall(std::unique_ptr<std::string> body) {
49   CHECK_EQ(API_CALL_STARTED, state_);
50   std::unique_ptr<network::SimpleURLLoader> source = std::move(url_loader_);
51 
52   int status_code = 0;
53   if (source->ResponseInfo() && source->ResponseInfo()->headers)
54     status_code = source->ResponseInfo()->headers->response_code();
55   if (source->NetError() != net::OK ||
56       (status_code != net::HTTP_OK && status_code != net::HTTP_NO_CONTENT)) {
57     state_ = ERROR_STATE;
58     ProcessApiCallFailure(source->NetError(), source->ResponseInfo(),
59                           std::move(body));
60   } else {
61     state_ = API_CALL_DONE;
62     ProcessApiCallSuccess(source->ResponseInfo(), std::move(body));
63   }
64 }
65 
CreateApiCallBodyContentType()66 std::string OAuth2ApiCallFlow::CreateApiCallBodyContentType() {
67   return "application/x-www-form-urlencoded";
68 }
69 
GetRequestTypeForBody(const std::string & body)70 std::string OAuth2ApiCallFlow::GetRequestTypeForBody(const std::string& body) {
71   return body.empty() ? "GET" : "POST";
72 }
73 
OnURLLoadComplete(std::unique_ptr<std::string> body)74 void OAuth2ApiCallFlow::OnURLLoadComplete(std::unique_ptr<std::string> body) {
75   CHECK_EQ(API_CALL_STARTED, state_);
76   EndApiCall(std::move(body));
77 }
78 
CreateURLLoader(const std::string & access_token)79 std::unique_ptr<network::SimpleURLLoader> OAuth2ApiCallFlow::CreateURLLoader(
80     const std::string& access_token) {
81   std::string body = CreateApiCallBody();
82   std::string request_type = GetRequestTypeForBody(body);
83   net::NetworkTrafficAnnotationTag traffic_annotation =
84       CompleteNetworkTrafficAnnotation("oauth2_api_call_flow",
85                                        GetNetworkTrafficAnnotationTag(), R"(
86           policy {
87             cookies_allowed: NO
88           })");
89 
90   auto request = std::make_unique<network::ResourceRequest>();
91   request->url = CreateApiCallUrl();
92   request->method = request_type;
93   request->credentials_mode = network::mojom::CredentialsMode::kOmit;
94   request->headers.SetHeader("Authorization",
95                              MakeAuthorizationValue(access_token));
96   std::unique_ptr<network::SimpleURLLoader> result =
97       network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
98 
99   // Fetchers are sometimes cancelled because a network change was detected,
100   // especially at startup and after sign-in on ChromeOS. Retrying once should
101   // be enough in those cases; let the fetcher retry up to 3 times just in case.
102   // http://crbug.com/163710
103   result->SetRetryOptions(3, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
104   result->SetAllowHttpErrorResults(true);
105 
106   // Even if the the body is empty, we still set the Content-Type because an
107   // empty string may be a meaningful value. For example, a Protocol Buffer
108   // message with only default values will be serialized as an empty string.
109   if (request_type != "GET")
110     result->AttachStringForUpload(body, CreateApiCallBodyContentType());
111 
112   return result;
113 }
114