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 
5 #include "chrome/browser/nearby_sharing/client/nearby_share_api_call_flow_impl.h"
6 
7 #include "base/strings/string_number_conversions.h"
8 #include "chrome/browser/nearby_sharing/common/nearby_share_http_result.h"
9 #include "chrome/browser/nearby_sharing/logging/logging.h"
10 #include "net/base/net_errors.h"
11 #include "net/base/url_util.h"
12 #include "net/traffic_annotation/network_traffic_annotation.h"
13 #include "services/network/public/cpp/shared_url_loader_factory.h"
14 #include "services/network/public/mojom/url_response_head.mojom.h"
15 
16 namespace {
17 
18 const char kGet[] = "GET";
19 const char kPatch[] = "PATCH";
20 const char kPost[] = "POST";
21 const char kProtobufContentType[] = "application/x-protobuf";
22 const char kQueryParameterAlternateOutputKey[] = "alt";
23 const char kQueryParameterAlternateOutputProto[] = "proto";
24 
25 }  // namespace
26 
27 NearbyShareApiCallFlowImpl::NearbyShareApiCallFlowImpl() = default;
28 NearbyShareApiCallFlowImpl::~NearbyShareApiCallFlowImpl() = default;
29 
StartPostRequest(const GURL & request_url,const std::string & serialized_request,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,const std::string & access_token,ResultCallback && result_callback,ErrorCallback && error_callback)30 void NearbyShareApiCallFlowImpl::StartPostRequest(
31     const GURL& request_url,
32     const std::string& serialized_request,
33     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
34     const std::string& access_token,
35     ResultCallback&& result_callback,
36     ErrorCallback&& error_callback) {
37   request_url_ = request_url;
38   request_http_method_ = kPost;
39   serialized_request_ = serialized_request;
40   result_callback_ = std::move(result_callback);
41   error_callback_ = std::move(error_callback);
42   OAuth2ApiCallFlow::Start(std::move(url_loader_factory), access_token);
43 }
44 
StartPatchRequest(const GURL & request_url,const std::string & serialized_request,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,const std::string & access_token,ResultCallback && result_callback,ErrorCallback && error_callback)45 void NearbyShareApiCallFlowImpl::StartPatchRequest(
46     const GURL& request_url,
47     const std::string& serialized_request,
48     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
49     const std::string& access_token,
50     ResultCallback&& result_callback,
51     ErrorCallback&& error_callback) {
52   request_url_ = request_url;
53   request_http_method_ = kPatch;
54   serialized_request_ = serialized_request;
55   result_callback_ = std::move(result_callback);
56   error_callback_ = std::move(error_callback);
57   OAuth2ApiCallFlow::Start(std::move(url_loader_factory), access_token);
58 }
59 
StartGetRequest(const GURL & request_url,const QueryParameters & request_as_query_parameters,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,const std::string & access_token,ResultCallback && result_callback,ErrorCallback && error_callback)60 void NearbyShareApiCallFlowImpl::StartGetRequest(
61     const GURL& request_url,
62     const QueryParameters& request_as_query_parameters,
63     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
64     const std::string& access_token,
65     ResultCallback&& result_callback,
66     ErrorCallback&& error_callback) {
67   request_url_ = request_url;
68   request_http_method_ = kGet;
69   request_as_query_parameters_ = request_as_query_parameters;
70   result_callback_ = std::move(result_callback);
71   error_callback_ = std::move(error_callback);
72   OAuth2ApiCallFlow::Start(std::move(url_loader_factory), access_token);
73 }
74 
SetPartialNetworkTrafficAnnotation(const net::PartialNetworkTrafficAnnotationTag & partial_traffic_annotation)75 void NearbyShareApiCallFlowImpl::SetPartialNetworkTrafficAnnotation(
76     const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
77   partial_network_annotation_ =
78       std::make_unique<net::PartialNetworkTrafficAnnotationTag>(
79           partial_traffic_annotation);
80 }
81 
CreateApiCallUrl()82 GURL NearbyShareApiCallFlowImpl::CreateApiCallUrl() {
83   // Specifies that the server's response body should be formatted as a
84   // serialized proto.
85   request_url_ =
86       net::AppendQueryParameter(request_url_, kQueryParameterAlternateOutputKey,
87                                 kQueryParameterAlternateOutputProto);
88 
89   // GET requests encode the request proto as query parameters.
90   if (request_as_query_parameters_) {
91     for (const auto& key_value_pair : *request_as_query_parameters_) {
92       request_url_ = net::AppendQueryParameter(
93           request_url_, key_value_pair.first, key_value_pair.second);
94     }
95   }
96   NS_LOG(VERBOSE) << "Creating Nearby Share HTTP URL: " << request_url_;
97   return request_url_;
98 }
99 
CreateApiCallBody()100 std::string NearbyShareApiCallFlowImpl::CreateApiCallBody() {
101   return serialized_request_.value_or(std::string());
102 }
103 
CreateApiCallBodyContentType()104 std::string NearbyShareApiCallFlowImpl::CreateApiCallBodyContentType() {
105   return serialized_request_ ? kProtobufContentType : std::string();
106 }
107 
108 // Note: Unlike OAuth2ApiCallFlow, we do *not* determine the request type
109 // based on whether or not the body is empty.
GetRequestTypeForBody(const std::string & body)110 std::string NearbyShareApiCallFlowImpl::GetRequestTypeForBody(
111     const std::string& body) {
112   DCHECK(!request_http_method_.empty());
113   return request_http_method_;
114 }
115 
ProcessApiCallSuccess(const network::mojom::URLResponseHead * head,std::unique_ptr<std::string> body)116 void NearbyShareApiCallFlowImpl::ProcessApiCallSuccess(
117     const network::mojom::URLResponseHead* head,
118     std::unique_ptr<std::string> body) {
119   if (!body) {
120     std::move(error_callback_).Run(NearbyShareHttpError::kResponseMalformed);
121     return;
122   }
123   std::move(result_callback_).Run(std::move(*body));
124 }
125 
ProcessApiCallFailure(int net_error,const network::mojom::URLResponseHead * head,std::unique_ptr<std::string> body)126 void NearbyShareApiCallFlowImpl::ProcessApiCallFailure(
127     int net_error,
128     const network::mojom::URLResponseHead* head,
129     std::unique_ptr<std::string> body) {
130   base::Optional<NearbyShareHttpError> error;
131   std::string error_message;
132   if (net_error == net::OK) {
133     int response_code = -1;
134     if (head && head->headers)
135       response_code = head->headers->response_code();
136     error = NearbyShareHttpErrorForHttpResponseCode(response_code);
137   } else {
138     error = NearbyShareHttpError::kOffline;
139   }
140 
141   NS_LOG(ERROR) << "API call failed, error code: "
142                 << net::ErrorToString(net_error);
143   if (body)
144     NS_LOG(VERBOSE) << "API failure response body: " << *body;
145 
146   std::move(error_callback_).Run(*error);
147 }
148 net::PartialNetworkTrafficAnnotationTag
GetNetworkTrafficAnnotationTag()149 NearbyShareApiCallFlowImpl::GetNetworkTrafficAnnotationTag() {
150   DCHECK(partial_network_annotation_);
151   return *partial_network_annotation_;
152 }
153