xref: /aosp_15_r20/external/federated-compute/fcp/client/http/protocol_request_helper.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef FCP_CLIENT_HTTP_PROTOCOL_REQUEST_HELPER_H_
17 #define FCP_CLIENT_HTTP_PROTOCOL_REQUEST_HELPER_H_
18 
19 #include "absl/container/flat_hash_set.h"
20 #include "absl/status/status.h"
21 #include "absl/status/statusor.h"
22 #include "fcp/base/clock.h"
23 #include "fcp/base/wall_clock_stopwatch.h"
24 #include "fcp/client/http/http_client.h"
25 #include "fcp/client/http/in_memory_request_response.h"
26 #include "fcp/protos/federatedcompute/common.pb.h"
27 // #include "google/longrunning/operations.pb.h"
28 
29 namespace fcp {
30 namespace client {
31 namespace http {
32 
33 // Note the uri query parameters should be percent encoded.
34 using QueryParams = absl::flat_hash_map<std::string, std::string>;
35 
36 // A helper for creating HTTP request with base uri, request headers and
37 // compression setting.
38 class ProtocolRequestCreator {
39  public:
40   ProtocolRequestCreator(absl::string_view request_base_uri,
41                          absl::string_view api_key, HeaderList request_headers,
42                          bool use_compression);
43 
44   // Creates a `ProtocolRequestCreator` based on the forwarding info.
45   // Validates and extracts the base URI and headers to use for the subsequent
46   // request(s).
47   static absl::StatusOr<std::unique_ptr<ProtocolRequestCreator>> Create(
48       absl::string_view api_key,
49       const ::google::internal::federatedcompute::v1::ForwardingInfo&
50           forwarding_info,
51       bool use_compression);
52 
53   // Creates an `HttpRequest` with base uri, request headers and compression
54   // setting. The `uri_path_suffix` argument must always either be empty or
55   // start with a leading '/'. The method will return `InvalidArgumentError` if
56   // this isn't the case.  The `uri_path_suffix` should not contain any query
57   // parameters, instead, query parameters should be specified in `params`.
58   //
59   // The URI to which the protocol request will be sent will be constructed by
60   // joining `next_request_base_uri_` with `uri_path_suffix` (see
61   // `JoinBaseUriWithSuffix` for details), and any query parameters if `params`
62   // is not empty.
63   //
64   // When `is_protobuf_encoded` is true, `%24alt=proto` will be added to the uri
65   // as a query parameter to indicate that the proto encoded payload is
66   // expected. When the `request_body` is not empty, a `Content-Type` header
67   // will also be added to the request
68   absl::StatusOr<std::unique_ptr<HttpRequest>> CreateProtocolRequest(
69       absl::string_view uri_path_suffix, QueryParams params,
70       HttpRequest::Method method, std::string request_body,
71       bool is_protobuf_encoded) const;
72 
73   // Creates an `HttpRequest` for getting the result of a
74   // `google.longrunning.operation`. Note that the request body is empty,
75   // because its only field (`name`) is included in the URI instead. Also note
76   // that the `next_request_headers_` will be attached to this request.
77   absl::StatusOr<std::unique_ptr<HttpRequest>> CreateGetOperationRequest(
78       absl::string_view operation_name) const;
79 
80   // Creates an `HttpRequest` for canceling a `google.longrunning.operation`.
81   // Note that the request body is empty, because its only field (`name`) is
82   // included in the URI instead. Also note that the `next_request_headers_`
83   // will be attached to this request.
84   absl::StatusOr<std::unique_ptr<HttpRequest>> CreateCancelOperationRequest(
85       absl::string_view operation_name) const;
86 
87  private:
88   absl::StatusOr<std::unique_ptr<HttpRequest>> CreateHttpRequest(
89       absl::string_view uri_path_suffix, QueryParams params,
90       HttpRequest::Method method, std::string request_body,
91       bool is_protobuf_encoded, bool use_compression) const;
92   // The URI to use for the next protocol request. See `ForwardingInfo`.
93   std::string next_request_base_uri_;
94   // The API key used for requests.
95   const std::string api_key_;
96   // The set of headers to attach to the next protocol request. See
97   // `ForwardingInfo`.
98   HeaderList next_request_headers_;
99   const bool use_compression_;
100 };
101 
102 // A helper for issuing protocol requests.
103 class ProtocolRequestHelper {
104  public:
105   ProtocolRequestHelper(HttpClient* http_client, int64_t* bytes_downloaded,
106                         int64_t* bytes_uploaded,
107                         WallClockStopwatch* network_stopwatch, Clock* clock);
108 
109   // Performs the given request (handling any interruptions that may occur) and
110   // updates the network stats.
111   absl::StatusOr<InMemoryHttpResponse> PerformProtocolRequest(
112       std::unique_ptr<HttpRequest> request, InterruptibleRunner& runner);
113 
114   // Performs the vector of requests (handling any interruptions that may occur)
115   // concurrently and updates the network stats.
116   // The returned vector of responses has the same order of the issued requests.
117   absl::StatusOr<std::vector<absl::StatusOr<InMemoryHttpResponse>>>
118   PerformMultipleProtocolRequests(
119       std::vector<std::unique_ptr<HttpRequest>> requests,
120       InterruptibleRunner& runner);
121 
122   // Helper function for handling an HTTP response that contains an `Operation`
123   // proto.
124   //
125   // Takes an HTTP response (which must have been produced by a call to
126   // `PerformRequestInMemory`), parses the proto, and returns it if its
127   // `Operation.done` field is true. If the field is false then this method
128   // keeps polling the Operation via performing requests created by
129   // `CreateGetOperationRequest` until it a response is received where the field
130   // is true, at which point that most recent response is returned. If at any
131   // point an HTTP or response parsing error is encountered, then that error is
132   // returned instead.
133   //   absl::StatusOr<::google::longrunning::Operation>
134   //   PollOperationResponseUntilDone(
135   //       const ::google::longrunning::Operation& initial_operation,
136   //       const ProtocolRequestCreator& request_creator,
137   //       InterruptibleRunner& runner);
138 
139   //   // Helper function for cancelling an operation.
140   //   absl::StatusOr<InMemoryHttpResponse> CancelOperation(
141   //       absl::string_view operation_name,
142   //       const ProtocolRequestCreator& request_creator,
143   //       InterruptibleRunner& runner);
144 
145  private:
146   HttpClient& http_client_;
147   int64_t& bytes_downloaded_;
148   int64_t& bytes_uploaded_;
149   WallClockStopwatch& network_stopwatch_;
150   Clock& clock_;
151 };
152 
153 // Parse a google::longrunning::Operation out of a InMemoryHttpResponse.
154 // If the initial http_response is not OK, this method will immediately return
155 // with the error status.
156 // absl::StatusOr<google::longrunning::Operation>
157 // ParseOperationProtoFromHttpResponse(
158 //     absl::StatusOr<InMemoryHttpResponse> http_response);
159 
160 // // Extract the operation name from Operation proto.
161 // // If the operation name is not started with "operations/", invalid argument
162 // // error will be returned.
163 // absl::StatusOr<std::string> ExtractOperationName(
164 //     const google::longrunning::Operation& operation);
165 
166 }  // namespace http
167 }  // namespace client
168 }  // namespace fcp
169 
170 #endif  // FCP_CLIENT_HTTP_PROTOCOL_REQUEST_HELPER_H_
171