xref: /aosp_15_r20/external/federated-compute/fcp/client/http/http_client.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*14675a02SAndroid Build Coastguard Worker  *
4*14675a02SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker  *
8*14675a02SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker  *
10*14675a02SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker  * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker  */
16*14675a02SAndroid Build Coastguard Worker #ifndef FCP_CLIENT_HTTP_HTTP_CLIENT_H_
17*14675a02SAndroid Build Coastguard Worker #define FCP_CLIENT_HTTP_HTTP_CLIENT_H_
18*14675a02SAndroid Build Coastguard Worker 
19*14675a02SAndroid Build Coastguard Worker #include <cstdint>
20*14675a02SAndroid Build Coastguard Worker #include <memory>
21*14675a02SAndroid Build Coastguard Worker #include <optional>
22*14675a02SAndroid Build Coastguard Worker #include <string>
23*14675a02SAndroid Build Coastguard Worker #include <utility>
24*14675a02SAndroid Build Coastguard Worker #include <vector>
25*14675a02SAndroid Build Coastguard Worker 
26*14675a02SAndroid Build Coastguard Worker #include "absl/base/attributes.h"
27*14675a02SAndroid Build Coastguard Worker #include "absl/container/flat_hash_map.h"
28*14675a02SAndroid Build Coastguard Worker #include "absl/status/status.h"
29*14675a02SAndroid Build Coastguard Worker #include "absl/status/statusor.h"
30*14675a02SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
31*14675a02SAndroid Build Coastguard Worker 
32*14675a02SAndroid Build Coastguard Worker namespace fcp {
33*14675a02SAndroid Build Coastguard Worker namespace client {
34*14675a02SAndroid Build Coastguard Worker namespace http {
35*14675a02SAndroid Build Coastguard Worker 
36*14675a02SAndroid Build Coastguard Worker using Header = std::pair<std::string, std::string>;
37*14675a02SAndroid Build Coastguard Worker // This is a vector of pairs and not a map since multiple request headers with
38*14675a02SAndroid Build Coastguard Worker // the same name are allowed (see RFC2616 section 4.2).
39*14675a02SAndroid Build Coastguard Worker using HeaderList = std::vector<Header>;
40*14675a02SAndroid Build Coastguard Worker 
41*14675a02SAndroid Build Coastguard Worker class HttpRequest;          // forward declaration
42*14675a02SAndroid Build Coastguard Worker class HttpRequestCallback;  // forward declaration
43*14675a02SAndroid Build Coastguard Worker class HttpRequestHandle;    // forward declaration
44*14675a02SAndroid Build Coastguard Worker class HttpResponse;         // forward declaration
45*14675a02SAndroid Build Coastguard Worker 
46*14675a02SAndroid Build Coastguard Worker // An interface that allows the callers to make HTTP requests and receive their
47*14675a02SAndroid Build Coastguard Worker // responses.
48*14675a02SAndroid Build Coastguard Worker //
49*14675a02SAndroid Build Coastguard Worker // Platforms will be required to pass an instance of this class to
50*14675a02SAndroid Build Coastguard Worker // `RunFederatedComputation(...)`, and such instances must remain alive for at
51*14675a02SAndroid Build Coastguard Worker // least the duration of those calls.
52*14675a02SAndroid Build Coastguard Worker //
53*14675a02SAndroid Build Coastguard Worker // Instances of this class must support being called from any thread. In such
54*14675a02SAndroid Build Coastguard Worker // cases implementations should ideally handle multiple requests in parallel, at
55*14675a02SAndroid Build Coastguard Worker // least up to an implementation-defined max number of parallel requests (i.e.
56*14675a02SAndroid Build Coastguard Worker // ideally two `PerformRequests` calls on different threads can be handled in
57*14675a02SAndroid Build Coastguard Worker // parallel, rather than having the 2nd call block until the 1st call is
58*14675a02SAndroid Build Coastguard Worker // completed).
59*14675a02SAndroid Build Coastguard Worker //
60*14675a02SAndroid Build Coastguard Worker // Besides the requirements documented further below, the following high-level
61*14675a02SAndroid Build Coastguard Worker // behavior is required of any `HttpClient` implementation:
62*14675a02SAndroid Build Coastguard Worker // - Underlying protocols:
63*14675a02SAndroid Build Coastguard Worker //   * Implementations must support at least HTTP/1.1 over TLS 1.2.
64*14675a02SAndroid Build Coastguard Worker //   * Implementations are also allowed to serve requests using HTTP/2, QUIC or
65*14675a02SAndroid Build Coastguard Worker //     other newer protocols.
66*14675a02SAndroid Build Coastguard Worker //   * Implementations must support both IPv4 and IPv6 (but they are allowed to
67*14675a02SAndroid Build Coastguard Worker //     fall back to IPv4).
68*14675a02SAndroid Build Coastguard Worker // - Certificate validation:
69*14675a02SAndroid Build Coastguard Worker //   * Implementations are responsible for TLS certificate validation and for
70*14675a02SAndroid Build Coastguard Worker //     maintaining an up-to-date set of root certificates as well as an
71*14675a02SAndroid Build Coastguard Worker //     up-to-date HTTP/TLS implementation.
72*14675a02SAndroid Build Coastguard Worker //   * Implementations should not include user-added CAs, and should consider
73*14675a02SAndroid Build Coastguard Worker //     restricting the set of CAs further to only those needed for connecting to
74*14675a02SAndroid Build Coastguard Worker //     the expected endpoints.
75*14675a02SAndroid Build Coastguard Worker // - Cookies:
76*14675a02SAndroid Build Coastguard Worker //   * Implementations must not supply any cookies in requests (beyond those
77*14675a02SAndroid Build Coastguard Worker //     that may be specified in the `HttpRequest::headers()` method).
78*14675a02SAndroid Build Coastguard Worker //   * Implementations must not store any cookies returned by the server.
79*14675a02SAndroid Build Coastguard Worker //   * Instead, they must return any server-specified "Set-Cookie" response
80*14675a02SAndroid Build Coastguard Worker //     header via `HttpResponse::headers()`.
81*14675a02SAndroid Build Coastguard Worker // - Redirects:
82*14675a02SAndroid Build Coastguard Worker //   *  Implementations must follow HTTP redirects responses, up to an
83*14675a02SAndroid Build Coastguard Worker //      implementation-defined maximum.
84*14675a02SAndroid Build Coastguard Worker //   *  In such cases the response headers & body returned via the interfaces
85*14675a02SAndroid Build Coastguard Worker //      below should be those of the final response.
86*14675a02SAndroid Build Coastguard Worker //   *  See `HttpRequestCallback` docs below for more details.
87*14675a02SAndroid Build Coastguard Worker // - Caching:
88*14675a02SAndroid Build Coastguard Worker //   *  Implementations should not implement a cache as it is expected that
89*14675a02SAndroid Build Coastguard Worker //      naive HTTP-level caching will not be effective (and since a cache may
90*14675a02SAndroid Build Coastguard Worker //      ultimately be implemented over this interface, in the Federated Compute
91*14675a02SAndroid Build Coastguard Worker //      library itself).
92*14675a02SAndroid Build Coastguard Worker //   *  If implementations do implement one, however, they are expected to abide
93*14675a02SAndroid Build Coastguard Worker //      by the standard HTTP caching rules (see the `HttpRequest::Method` docs
94*14675a02SAndroid Build Coastguard Worker //      for more details).
95*14675a02SAndroid Build Coastguard Worker // - Response body decompression & decoding:
96*14675a02SAndroid Build Coastguard Worker //   *  If no "Accept-Encoding" request header is explicitly specified in
97*14675a02SAndroid Build Coastguard Worker //      `HttpRequest::headers()`, then implementations must advertise an
98*14675a02SAndroid Build Coastguard Worker //      "Accept-Encoding" request header themselves whose value includes at
99*14675a02SAndroid Build Coastguard Worker //      least "gzip" (additional encodings are allowed to be specified in
100*14675a02SAndroid Build Coastguard Worker //      addition to "gzip"), and must transparently decompress any compressed
101*14675a02SAndroid Build Coastguard Worker //      server responses before returning the data via these interfaces.
102*14675a02SAndroid Build Coastguard Worker //      Implementations are also allowed to advertise/support additional
103*14675a02SAndroid Build Coastguard Worker //      encoding methods.
104*14675a02SAndroid Build Coastguard Worker //   *  In such cases where no "Accept-Encoding" header is specified,
105*14675a02SAndroid Build Coastguard Worker //      implementations must remove the "Content-Encoding" and
106*14675a02SAndroid Build Coastguard Worker //      "Content-Length" headers from headers returned via
107*14675a02SAndroid Build Coastguard Worker //      `HttpResponse::headers()` (since those wouldn't reflect the payload
108*14675a02SAndroid Build Coastguard Worker //      delivered via this interface).
109*14675a02SAndroid Build Coastguard Worker //   *  However, if an "Accept-Encoding" request header *is* explicitly
110*14675a02SAndroid Build Coastguard Worker //      specified, then implementations must use that header verbatim and they
111*14675a02SAndroid Build Coastguard Worker //      must not decompress the response (even if they natively support the
112*14675a02SAndroid Build Coastguard Worker //      compression method), and they must leave the "Content-Encoding" and
113*14675a02SAndroid Build Coastguard Worker //      "Content-Length" headers intact.
114*14675a02SAndroid Build Coastguard Worker //   *  This ensures that the caller of this interface can take full control of
115*14675a02SAndroid Build Coastguard Worker //      the decompression and/or choose to store decompressed payloads on disk
116*14675a02SAndroid Build Coastguard Worker //      if it so chooses.
117*14675a02SAndroid Build Coastguard Worker //   *  Implementations must transparently decode server responses served with
118*14675a02SAndroid Build Coastguard Worker //      "Transfer-Encoding: chunked". In such cases they must remove the
119*14675a02SAndroid Build Coastguard Worker //      "Transfer-Encoding" response header.
120*14675a02SAndroid Build Coastguard Worker // - Request body compression & encoding:
121*14675a02SAndroid Build Coastguard Worker //   *  If implementations receive a "Content-Encoding" request header, this
122*14675a02SAndroid Build Coastguard Worker //      means that the request body stream they receive has already been
123*14675a02SAndroid Build Coastguard Worker //      compressed. The implementation must leave the header and request body
124*14675a02SAndroid Build Coastguard Worker //      intact in such cases (i.e. not re-compress it).
125*14675a02SAndroid Build Coastguard Worker //   *  If implementations receive a "Content-Length" request header, they must
126*14675a02SAndroid Build Coastguard Worker //      use it verbatim and they should then assume that the request body will
127*14675a02SAndroid Build Coastguard Worker //      be of exactly that size.
128*14675a02SAndroid Build Coastguard Worker //   *  If they do not receive such a header then they must use the
129*14675a02SAndroid Build Coastguard Worker //      "Transfer-encoding: chunked" mechanism to transmit the request body
130*14675a02SAndroid Build Coastguard Worker //      (i.e. they shouldn't specify a "Content-Length" header and they should
131*14675a02SAndroid Build Coastguard Worker //      transmit the body in chunks), or use an equivalent method of streaming
132*14675a02SAndroid Build Coastguard Worker //      the data (such as HTTP/2's data streaming).
133*14675a02SAndroid Build Coastguard Worker class HttpClient {
134*14675a02SAndroid Build Coastguard Worker  public:
135*14675a02SAndroid Build Coastguard Worker   virtual ~HttpClient() = default;
136*14675a02SAndroid Build Coastguard Worker 
137*14675a02SAndroid Build Coastguard Worker   // Enqueues an HTTP request, without starting it yet. To start the request the
138*14675a02SAndroid Build Coastguard Worker   // `HttpRequestHandle` must be passed to `PerformRequests`. Each
139*14675a02SAndroid Build Coastguard Worker   // `HttpRequestHandle` must be passed to at most one `PerformRequests` call.
140*14675a02SAndroid Build Coastguard Worker   //
141*14675a02SAndroid Build Coastguard Worker   // The `HttpClient` implementation assumes ownership of the `HttpRequest`
142*14675a02SAndroid Build Coastguard Worker   // object, and the implementation must delete the object when the
143*14675a02SAndroid Build Coastguard Worker   // `HttpRequestHandle` is deleted.
144*14675a02SAndroid Build Coastguard Worker   ABSL_MUST_USE_RESULT
145*14675a02SAndroid Build Coastguard Worker   virtual std::unique_ptr<HttpRequestHandle> EnqueueRequest(
146*14675a02SAndroid Build Coastguard Worker       std::unique_ptr<HttpRequest> request) = 0;
147*14675a02SAndroid Build Coastguard Worker 
148*14675a02SAndroid Build Coastguard Worker   // Performs the given requests. Results will be returned to each
149*14675a02SAndroid Build Coastguard Worker   // corresponding `HttpRequestCallback` while this method is blocked. This
150*14675a02SAndroid Build Coastguard Worker   // method must block until all requests have finished or have been cancelled,
151*14675a02SAndroid Build Coastguard Worker   // and until all corresponding request callbacks have returned.
152*14675a02SAndroid Build Coastguard Worker   //
153*14675a02SAndroid Build Coastguard Worker   // By decoupling the enqueueing and starting of (groups of) requests,
154*14675a02SAndroid Build Coastguard Worker   // implementations may be able to handle concurrent requests more optimally
155*14675a02SAndroid Build Coastguard Worker   // (e.g. by issuing them over a shared HTTP connection). Having separate
156*14675a02SAndroid Build Coastguard Worker   // per-request `HttpRequestHandle` objects also makes it easier to support
157*14675a02SAndroid Build Coastguard Worker   // canceling specific requests, releasing resources for specific requests,
158*14675a02SAndroid Build Coastguard Worker   // accessing stats for specific requests, etc.
159*14675a02SAndroid Build Coastguard Worker   //
160*14675a02SAndroid Build Coastguard Worker   // The `HttpRequestHandle` and `HttpRequestCallback` instances must outlive
161*14675a02SAndroid Build Coastguard Worker   // the call to `PerformRequests`, but may be deleted any time after this call
162*14675a02SAndroid Build Coastguard Worker   // has returned.
163*14675a02SAndroid Build Coastguard Worker   //
164*14675a02SAndroid Build Coastguard Worker   // Returns an `INVALID_ARGUMENT` error if a `HttpRequestHandle` was previously
165*14675a02SAndroid Build Coastguard Worker   // already passed to another `PerformRequests` call, or if an
166*14675a02SAndroid Build Coastguard Worker   // `HttpRequestHandle`'s `Cancel` method was already called before being
167*14675a02SAndroid Build Coastguard Worker   // passed to this call.
168*14675a02SAndroid Build Coastguard Worker   virtual absl::Status PerformRequests(
169*14675a02SAndroid Build Coastguard Worker       std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>>
170*14675a02SAndroid Build Coastguard Worker           requests) = 0;
171*14675a02SAndroid Build Coastguard Worker };
172*14675a02SAndroid Build Coastguard Worker 
173*14675a02SAndroid Build Coastguard Worker // An HTTP request for a single resource. Implemented by the caller of
174*14675a02SAndroid Build Coastguard Worker // `HttpClient`.
175*14675a02SAndroid Build Coastguard Worker //
176*14675a02SAndroid Build Coastguard Worker // Once instances are passed to `EnqueueRequest`, their lifetime is managed by
177*14675a02SAndroid Build Coastguard Worker // the `HttpClient` implementation. Implementations must tie the `HttpRequest`
178*14675a02SAndroid Build Coastguard Worker // instance lifetime to the lifetime of the `HttpRequestHandle` they return
179*14675a02SAndroid Build Coastguard Worker // (i.e. they should delete the `HttpRequest` from the `HttpRequestHandle`
180*14675a02SAndroid Build Coastguard Worker // destructor).
181*14675a02SAndroid Build Coastguard Worker //
182*14675a02SAndroid Build Coastguard Worker // Methods of this class may get called from any thread (and subsequent calls
183*14675a02SAndroid Build Coastguard Worker // are not required to all happen on the same thread).
184*14675a02SAndroid Build Coastguard Worker class HttpRequest {
185*14675a02SAndroid Build Coastguard Worker  public:
186*14675a02SAndroid Build Coastguard Worker   // Note: the request methods imply a set of standard request properties such
187*14675a02SAndroid Build Coastguard Worker   // as cacheability, safety, and idempotency. See
188*14675a02SAndroid Build Coastguard Worker   // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods.
189*14675a02SAndroid Build Coastguard Worker   //
190*14675a02SAndroid Build Coastguard Worker   // The caller of `HttpClient` may implement its own caching layer in the
191*14675a02SAndroid Build Coastguard Worker   // future, so implementations are not expected to cache cacheable requests
192*14675a02SAndroid Build Coastguard Worker   // (although they are technically allowed to).
193*14675a02SAndroid Build Coastguard Worker   //
194*14675a02SAndroid Build Coastguard Worker   // Implementations should not automatically retry requests, even if the
195*14675a02SAndroid Build Coastguard Worker   // request method implies it is safe or idempotent. The caller of `HttpClient`
196*14675a02SAndroid Build Coastguard Worker   // will own the responsibility for retrying requests.
197*14675a02SAndroid Build Coastguard Worker   enum class Method { kHead, kGet, kPost, kPut, kPatch, kDelete };
198*14675a02SAndroid Build Coastguard Worker 
199*14675a02SAndroid Build Coastguard Worker   // Must not be called until any corresponding `HttpRequestHandle` has been
200*14675a02SAndroid Build Coastguard Worker   // deleted.
201*14675a02SAndroid Build Coastguard Worker   virtual ~HttpRequest() = default;
202*14675a02SAndroid Build Coastguard Worker 
203*14675a02SAndroid Build Coastguard Worker   // The URI to request. Will always have an "https://" scheme (but this may be
204*14675a02SAndroid Build Coastguard Worker   // extended in the future).
205*14675a02SAndroid Build Coastguard Worker   virtual absl::string_view uri() const = 0;
206*14675a02SAndroid Build Coastguard Worker 
207*14675a02SAndroid Build Coastguard Worker   // The HTTP method to use for this request.
208*14675a02SAndroid Build Coastguard Worker   virtual Method method() const = 0;
209*14675a02SAndroid Build Coastguard Worker 
210*14675a02SAndroid Build Coastguard Worker   // Extra request headers to include with this request, in addition to any
211*14675a02SAndroid Build Coastguard Worker   // headers specified by the `HttpClient` implementation.
212*14675a02SAndroid Build Coastguard Worker   //
213*14675a02SAndroid Build Coastguard Worker   // See the `HttpClient` comment for the expected behavior w.r.t. a few
214*14675a02SAndroid Build Coastguard Worker   // specific headers.
215*14675a02SAndroid Build Coastguard Worker   virtual const HeaderList& extra_headers() const = 0;
216*14675a02SAndroid Build Coastguard Worker 
217*14675a02SAndroid Build Coastguard Worker   // Returns true if the request has a request body (which can be read using
218*14675a02SAndroid Build Coastguard Worker   // `ReadBody`). If the request body payload size is known ahead of time, then
219*14675a02SAndroid Build Coastguard Worker   // the "Content-Length" header will be set in `extra_headers()`. If it isn't
220*14675a02SAndroid Build Coastguard Worker   // known yet then the `HttpClient` implementation should use the
221*14675a02SAndroid Build Coastguard Worker   // "Transfer-Encoding: chunked" encoding to transmit the request body to the
222*14675a02SAndroid Build Coastguard Worker   // server in chunks (or use an equivalent method of streaming the data, e.g.
223*14675a02SAndroid Build Coastguard Worker   // if the connection uses HTTP/2). See the `HttpClient` comment for more
224*14675a02SAndroid Build Coastguard Worker   // details.
225*14675a02SAndroid Build Coastguard Worker   virtual bool HasBody() const = 0;
226*14675a02SAndroid Build Coastguard Worker 
227*14675a02SAndroid Build Coastguard Worker   // HttpRequests that up to `requested` bytes of the request body be read into
228*14675a02SAndroid Build Coastguard Worker   // `buffer`, and that the actual amount of bytes read is returned. The caller
229*14675a02SAndroid Build Coastguard Worker   // retains ownership of the buffer.
230*14675a02SAndroid Build Coastguard Worker   //
231*14675a02SAndroid Build Coastguard Worker   // Callees must return at least 1 byte, but may otherwise return less than the
232*14675a02SAndroid Build Coastguard Worker   // requested amount of data, if more data isn't available yet. Callees should
233*14675a02SAndroid Build Coastguard Worker   // return `OUT_OF_RANGE` when the end of data has been reached, in which case
234*14675a02SAndroid Build Coastguard Worker   // `buffer` should not be modified.
235*14675a02SAndroid Build Coastguard Worker   //
236*14675a02SAndroid Build Coastguard Worker   // Callees should return data ASAP, as delaying this for too long may cause
237*14675a02SAndroid Build Coastguard Worker   // the network stream to fall idle/run out of data to transmit.
238*14675a02SAndroid Build Coastguard Worker   //
239*14675a02SAndroid Build Coastguard Worker   // May also return other errors, in which case the request will be ended and
240*14675a02SAndroid Build Coastguard Worker   // `HttpRequestCallback::OnResponseError` will be called with the same error.
241*14675a02SAndroid Build Coastguard Worker   virtual absl::StatusOr<int64_t> ReadBody(char* buffer, int64_t requested) = 0;
242*14675a02SAndroid Build Coastguard Worker };
243*14675a02SAndroid Build Coastguard Worker 
244*14675a02SAndroid Build Coastguard Worker // A handle to a pending `HttpRequest`, allowing a caller of `HttpClient` to
245*14675a02SAndroid Build Coastguard Worker // access stats for the request or to cancel ongoing requests. Implemented by
246*14675a02SAndroid Build Coastguard Worker // the `HttpClient` implementer.
247*14675a02SAndroid Build Coastguard Worker //
248*14675a02SAndroid Build Coastguard Worker // The lifetimes of instances of this class are owned by the caller of
249*14675a02SAndroid Build Coastguard Worker // `HttpClient`.
250*14675a02SAndroid Build Coastguard Worker //
251*14675a02SAndroid Build Coastguard Worker // Methods of this class may get called from any thread (and subsequent calls
252*14675a02SAndroid Build Coastguard Worker // are not required to all happen on the same thread).
253*14675a02SAndroid Build Coastguard Worker class HttpRequestHandle {
254*14675a02SAndroid Build Coastguard Worker  public:
255*14675a02SAndroid Build Coastguard Worker   // When this is called, `HttpClient` implementations should delete all their
256*14675a02SAndroid Build Coastguard Worker   // owned resources as well as the associated `HttpRequest`.
257*14675a02SAndroid Build Coastguard Worker   virtual ~HttpRequestHandle() = default;
258*14675a02SAndroid Build Coastguard Worker 
259*14675a02SAndroid Build Coastguard Worker   // The total amount of data sent/received over the network for this request up
260*14675a02SAndroid Build Coastguard Worker   // to this point. These numbers should reflect as close as possible the amount
261*14675a02SAndroid Build Coastguard Worker   // of bytes sent "over the wire". This means, for example, that if the data is
262*14675a02SAndroid Build Coastguard Worker   // compressed or if a `Transfer-Encoding` is used, the numbers should reflect
263*14675a02SAndroid Build Coastguard Worker   // the compressed and/or encoded size of the data (if the implementation is
264*14675a02SAndroid Build Coastguard Worker   // able to account for that). Implementations are allowed to account for the
265*14675a02SAndroid Build Coastguard Worker   // overhead of TLS encoding in these numbers, but are not required to (since
266*14675a02SAndroid Build Coastguard Worker   // many HTTP libraries also do not provide stats at that level of
267*14675a02SAndroid Build Coastguard Worker   // granularity).
268*14675a02SAndroid Build Coastguard Worker   //
269*14675a02SAndroid Build Coastguard Worker   // If the request was served from a cache then this should reflect only the
270*14675a02SAndroid Build Coastguard Worker   // actual bytes sent over the network (e.g. 0 if returned from disk directly,
271*14675a02SAndroid Build Coastguard Worker   // or if a cache validation request was sent only those bytes used by the
272*14675a02SAndroid Build Coastguard Worker   // validation request/response).
273*14675a02SAndroid Build Coastguard Worker   //
274*14675a02SAndroid Build Coastguard Worker   // If the request involved redirects, the numbers returned here should include
275*14675a02SAndroid Build Coastguard Worker   // the bytes sent/received for those redirects, if the implementation supports
276*14675a02SAndroid Build Coastguard Worker   // this. Otherwise they are allowed to reflect only the final
277*14675a02SAndroid Build Coastguard Worker   // request/response's bytes sent/received.
278*14675a02SAndroid Build Coastguard Worker   //
279*14675a02SAndroid Build Coastguard Worker   // Implementations should strive to return as up-to-date numbers are possible
280*14675a02SAndroid Build Coastguard Worker   // from these methods (e.g. ideally the 'sent' number should reflect the
281*14675a02SAndroid Build Coastguard Worker   // amount of request body data that has been uploaded so far, even if the
282*14675a02SAndroid Build Coastguard Worker   // upload hasn't completed fully yet; similarly the 'received' number should
283*14675a02SAndroid Build Coastguard Worker   // reflect the amount of response body data received so far, even if the
284*14675a02SAndroid Build Coastguard Worker   // response hasn't been fully received yet).
285*14675a02SAndroid Build Coastguard Worker   //
286*14675a02SAndroid Build Coastguard Worker   // The numbers returned here are not required to increase monotonically
287*14675a02SAndroid Build Coastguard Worker   // between each call to the method. E.g. implementations are allowed to return
288*14675a02SAndroid Build Coastguard Worker   // best-available estimates while the request is still in flight, and then
289*14675a02SAndroid Build Coastguard Worker   // revise the numbers down to a more accurate number once the request has been
290*14675a02SAndroid Build Coastguard Worker   // completed.
291*14675a02SAndroid Build Coastguard Worker   struct SentReceivedBytes {
292*14675a02SAndroid Build Coastguard Worker     int64_t sent_bytes;
293*14675a02SAndroid Build Coastguard Worker     int64_t received_bytes;
294*14675a02SAndroid Build Coastguard Worker   };
295*14675a02SAndroid Build Coastguard Worker   virtual SentReceivedBytes TotalSentReceivedBytes() const = 0;
296*14675a02SAndroid Build Coastguard Worker 
297*14675a02SAndroid Build Coastguard Worker   // Used to indicate that the request should be cancelled and that
298*14675a02SAndroid Build Coastguard Worker   // implementations may release resources associated with this request (e.g.
299*14675a02SAndroid Build Coastguard Worker   // the socket used by the request).
300*14675a02SAndroid Build Coastguard Worker   //
301*14675a02SAndroid Build Coastguard Worker   // Callers are still only allowed to delete this instance once after any
302*14675a02SAndroid Build Coastguard Worker   // corresponding `PerformRequests()` call has completed, and not before.
303*14675a02SAndroid Build Coastguard Worker   //
304*14675a02SAndroid Build Coastguard Worker   // If a `PerformRequests` call is ongoing for this handle, then the
305*14675a02SAndroid Build Coastguard Worker   // corresponding `HttpRequestCallback` instance may still receive further
306*14675a02SAndroid Build Coastguard Worker   // method invocations after this call returns (e.g. because an invocation may
307*14675a02SAndroid Build Coastguard Worker   // already have been in flight).
308*14675a02SAndroid Build Coastguard Worker   //
309*14675a02SAndroid Build Coastguard Worker   // If a `PerformRequests` call is ongoing for this handle, and if the
310*14675a02SAndroid Build Coastguard Worker   // `HttpRequestCallback::OnResponseStarted` method was not called yet, then
311*14675a02SAndroid Build Coastguard Worker   // the `HttpRequestCallback::OnResponseError` method must be called with
312*14675a02SAndroid Build Coastguard Worker   // status `CANCELLED`.
313*14675a02SAndroid Build Coastguard Worker   //
314*14675a02SAndroid Build Coastguard Worker   // Otherwise, if a `PerformRequests` call is ongoing for this handle, and if
315*14675a02SAndroid Build Coastguard Worker   // the `HttpRequestCallback::OnResponseCompleted` method was not called yet,
316*14675a02SAndroid Build Coastguard Worker   // then the `HttpRequestCallback::OnResponseBodyError` method must be called
317*14675a02SAndroid Build Coastguard Worker   // with status `CANCELLED`.
318*14675a02SAndroid Build Coastguard Worker   virtual void Cancel() = 0;
319*14675a02SAndroid Build Coastguard Worker };
320*14675a02SAndroid Build Coastguard Worker 
321*14675a02SAndroid Build Coastguard Worker // The callback interface that `HttpClient` implementations must use to deliver
322*14675a02SAndroid Build Coastguard Worker // the response to a `HttpRequest`. Implemented by the caller of `HttpClient`.
323*14675a02SAndroid Build Coastguard Worker //
324*14675a02SAndroid Build Coastguard Worker // The lifetimes of instances of this class are owned by the caller of
325*14675a02SAndroid Build Coastguard Worker // `HttpClient`. Instances must remain alive for at least as long as their
326*14675a02SAndroid Build Coastguard Worker // corresponding `PerformRequests` call.
327*14675a02SAndroid Build Coastguard Worker //
328*14675a02SAndroid Build Coastguard Worker // Methods of this class may get called from any thread (incl. concurrently),
329*14675a02SAndroid Build Coastguard Worker // but callers of this class must always call the callback methods for a
330*14675a02SAndroid Build Coastguard Worker // specific `HttpRequest` in the order specified in each method's documentation.
331*14675a02SAndroid Build Coastguard Worker // Implementations of this class therefore likely should use internal
332*14675a02SAndroid Build Coastguard Worker // synchronization.
333*14675a02SAndroid Build Coastguard Worker //
334*14675a02SAndroid Build Coastguard Worker // For example, a call to `OnResponseBody` for a given `HttpRequest` A will
335*14675a02SAndroid Build Coastguard Worker // always be preceded by a completed call to `OnResponseStarted` for that same
336*14675a02SAndroid Build Coastguard Worker // request A. However, callbacks for different `HttpRequest` objects may happen
337*14675a02SAndroid Build Coastguard Worker // concurrently, so for example, `OnResponseStarted` may be called concurrently
338*14675a02SAndroid Build Coastguard Worker // for two different requests A and B. This latter scenario means that if the
339*14675a02SAndroid Build Coastguard Worker // same `HttpRequestCallback` object is used to handle callbacks for both
340*14675a02SAndroid Build Coastguard Worker // requests, then the object has to handle concurrent calls correctly.
341*14675a02SAndroid Build Coastguard Worker class HttpRequestCallback {
342*14675a02SAndroid Build Coastguard Worker  public:
343*14675a02SAndroid Build Coastguard Worker   virtual ~HttpRequestCallback() = default;
344*14675a02SAndroid Build Coastguard Worker 
345*14675a02SAndroid Build Coastguard Worker   // Called when the final HTTP response headers have been received (i.e. after
346*14675a02SAndroid Build Coastguard Worker   // any redirects have been followed but before the response body may have been
347*14675a02SAndroid Build Coastguard Worker   // received fully) for the given `HttpRequest`. The response data can be
348*14675a02SAndroid Build Coastguard Worker   // accessed via the given `HttpResponse`, which will remain alive for the
349*14675a02SAndroid Build Coastguard Worker   // lifetime of the corresponding `HttpRequestHandle`.
350*14675a02SAndroid Build Coastguard Worker   //
351*14675a02SAndroid Build Coastguard Worker   // Note that all the data in the `HttpResponse` object should reflect the
352*14675a02SAndroid Build Coastguard Worker   // last/final response (i.e. it shouldn't reflect any already-followed
353*14675a02SAndroid Build Coastguard Worker   // redirects).
354*14675a02SAndroid Build Coastguard Worker   //
355*14675a02SAndroid Build Coastguard Worker   // If the response has a body then after this method is called
356*14675a02SAndroid Build Coastguard Worker   // `OnResponseBody` will be called one or more times to deliver the response
357*14675a02SAndroid Build Coastguard Worker   // body (or `OnResponseBodyError` if an error occurs).
358*14675a02SAndroid Build Coastguard Worker   //
359*14675a02SAndroid Build Coastguard Worker   // Note that responses with an HTTP status code other than 200 ("OK") may
360*14675a02SAndroid Build Coastguard Worker   // still have response bodies, and implementations must deliver these via the
361*14675a02SAndroid Build Coastguard Worker   // `OnResponseBody` callback, just as they should for a successful response.
362*14675a02SAndroid Build Coastguard Worker   //
363*14675a02SAndroid Build Coastguard Worker   // If this method returns an error then the `HttpClient` implementation should
364*14675a02SAndroid Build Coastguard Worker   // consider the `HttpRequest` canceled. No further methods must be called on
365*14675a02SAndroid Build Coastguard Worker   // this `HttpRequestCallback` instance for the given `HttpRequest` after in
366*14675a02SAndroid Build Coastguard Worker   // this case.
367*14675a02SAndroid Build Coastguard Worker   virtual absl::Status OnResponseStarted(const HttpRequest& request,
368*14675a02SAndroid Build Coastguard Worker                                          const HttpResponse& response) = 0;
369*14675a02SAndroid Build Coastguard Worker 
370*14675a02SAndroid Build Coastguard Worker   // Called when the request encountered an error or timed out, before receiving
371*14675a02SAndroid Build Coastguard Worker   // the response headers completely. No further methods must be called on this
372*14675a02SAndroid Build Coastguard Worker   // `HttpRequestCallback` instance for the given `HttpRequest` after this
373*14675a02SAndroid Build Coastguard Worker   // method is called.
374*14675a02SAndroid Build Coastguard Worker   //
375*14675a02SAndroid Build Coastguard Worker   // If the implementation is able to discern that the error may have been
376*14675a02SAndroid Build Coastguard Worker   // transient, they should return `UNAVAILABLE`.
377*14675a02SAndroid Build Coastguard Worker   //
378*14675a02SAndroid Build Coastguard Worker   // If more than the implementation's defined max number of redirects occurred
379*14675a02SAndroid Build Coastguard Worker   // (without reaching the final response), then implementations should return
380*14675a02SAndroid Build Coastguard Worker   // `OUT_OF_RANGE` here.
381*14675a02SAndroid Build Coastguard Worker   //
382*14675a02SAndroid Build Coastguard Worker   // If the implementation hit an implementation-specific timeout (even though
383*14675a02SAndroid Build Coastguard Worker   // implementations are discouraged from imposing such timeouts), then this
384*14675a02SAndroid Build Coastguard Worker   // should be `DEADLINE_EXCEEDED`.
385*14675a02SAndroid Build Coastguard Worker   //
386*14675a02SAndroid Build Coastguard Worker   // If the `HttpRequestHandle::Cancel` method was called before
387*14675a02SAndroid Build Coastguard Worker   // `OnResponseStarted` was called for the given `HttpRequest`, then this
388*14675a02SAndroid Build Coastguard Worker   // method will be called with a `CANCELLED` status.
389*14675a02SAndroid Build Coastguard Worker   //
390*14675a02SAndroid Build Coastguard Worker   // If the request's `HttpRequest::ReadBody` returned an unexpected error,
391*14675a02SAndroid Build Coastguard Worker   // then method will be called with that error.
392*14675a02SAndroid Build Coastguard Worker   virtual void OnResponseError(const HttpRequest& request,
393*14675a02SAndroid Build Coastguard Worker                                const absl::Status& error) = 0;
394*14675a02SAndroid Build Coastguard Worker 
395*14675a02SAndroid Build Coastguard Worker   // Called (possibly multiple times per request) when a block of response data
396*14675a02SAndroid Build Coastguard Worker   // is available in `data`. This method must only be called after
397*14675a02SAndroid Build Coastguard Worker   // `OnResponseStarted` was called for the given `HttpRequest`.
398*14675a02SAndroid Build Coastguard Worker   //
399*14675a02SAndroid Build Coastguard Worker   // Callees must process the data ASAP, as delaying this for too long may
400*14675a02SAndroid Build Coastguard Worker   // prevent additional data from arriving on the network stream.
401*14675a02SAndroid Build Coastguard Worker   //
402*14675a02SAndroid Build Coastguard Worker   // If this method returns an error then the `HttpClient` implementation should
403*14675a02SAndroid Build Coastguard Worker   // consider the `HttpRequest` canceled. No further methods must be called on
404*14675a02SAndroid Build Coastguard Worker   // this `HttpRequestCallback` instance for the given `HttpRequest` after in
405*14675a02SAndroid Build Coastguard Worker   // this case.
406*14675a02SAndroid Build Coastguard Worker   virtual absl::Status OnResponseBody(const HttpRequest& request,
407*14675a02SAndroid Build Coastguard Worker                                       const HttpResponse& response,
408*14675a02SAndroid Build Coastguard Worker                                       absl::string_view data) = 0;
409*14675a02SAndroid Build Coastguard Worker 
410*14675a02SAndroid Build Coastguard Worker   // Called when the request encountered an error or timed out while receiving
411*14675a02SAndroid Build Coastguard Worker   // the response body (i.e. after `OnResponseStarted` was called). No further
412*14675a02SAndroid Build Coastguard Worker   // methods must be called on this `HttpRequestCallback` instance for the given
413*14675a02SAndroid Build Coastguard Worker   // `HttpRequest` after this method is called.
414*14675a02SAndroid Build Coastguard Worker   //
415*14675a02SAndroid Build Coastguard Worker   // If the implementation is able to discern that the error may have been
416*14675a02SAndroid Build Coastguard Worker   // transient, they should return `UNAVAILABLE`.
417*14675a02SAndroid Build Coastguard Worker   //
418*14675a02SAndroid Build Coastguard Worker   // If the implementation hit an implementation-specific timeout (even though
419*14675a02SAndroid Build Coastguard Worker   // implementations are discouraged from imposing such timeouts), then this
420*14675a02SAndroid Build Coastguard Worker   // should be `DEADLINE_EXCEEDED`.
421*14675a02SAndroid Build Coastguard Worker   //
422*14675a02SAndroid Build Coastguard Worker   // If the `HttpRequestHandle::Cancel` method was called before
423*14675a02SAndroid Build Coastguard Worker   // `OnResponseCompleted` was called for the given `HttpRequest`, then this
424*14675a02SAndroid Build Coastguard Worker   // method will be called with a `CANCELLED` status.
425*14675a02SAndroid Build Coastguard Worker   virtual void OnResponseBodyError(const HttpRequest& request,
426*14675a02SAndroid Build Coastguard Worker                                    const HttpResponse& response,
427*14675a02SAndroid Build Coastguard Worker                                    const absl::Status& error) = 0;
428*14675a02SAndroid Build Coastguard Worker 
429*14675a02SAndroid Build Coastguard Worker   // Called when the request has completed successfully (i.e. the response
430*14675a02SAndroid Build Coastguard Worker   // headers were delivered, and if there was a response body then it was also
431*14675a02SAndroid Build Coastguard Worker   // delivered successfully). Must not be called if one of the error callbacks
432*14675a02SAndroid Build Coastguard Worker   // was already called for the given `HttpRequest`, and no further methods must
433*14675a02SAndroid Build Coastguard Worker   // be called on this `HttpRequestCallback` instance for the given
434*14675a02SAndroid Build Coastguard Worker   // `HttpRequest` after this method is called.
435*14675a02SAndroid Build Coastguard Worker   virtual void OnResponseCompleted(const HttpRequest& request,
436*14675a02SAndroid Build Coastguard Worker                                    const HttpResponse& response) = 0;
437*14675a02SAndroid Build Coastguard Worker };
438*14675a02SAndroid Build Coastguard Worker 
439*14675a02SAndroid Build Coastguard Worker // A response to a given `HttpRequest`. Implemented by the `HttpClient`
440*14675a02SAndroid Build Coastguard Worker // implementer.
441*14675a02SAndroid Build Coastguard Worker //
442*14675a02SAndroid Build Coastguard Worker // The lifetimes of instances of this class are managed by the `HttpClient`
443*14675a02SAndroid Build Coastguard Worker // implementer. Instances of this class must remain alive for at least long as
444*14675a02SAndroid Build Coastguard Worker // the corresponding `HttpRequestHandle` is alive.
445*14675a02SAndroid Build Coastguard Worker //
446*14675a02SAndroid Build Coastguard Worker // Note that all the data in this object should be for the last/final response.
447*14675a02SAndroid Build Coastguard Worker // I.e. any responses corresponding to redirects should not be reflected here.
448*14675a02SAndroid Build Coastguard Worker class HttpResponse {
449*14675a02SAndroid Build Coastguard Worker  public:
450*14675a02SAndroid Build Coastguard Worker   virtual ~HttpResponse() = default;
451*14675a02SAndroid Build Coastguard Worker 
452*14675a02SAndroid Build Coastguard Worker   // The response code returned by the server (e.g. 200).
453*14675a02SAndroid Build Coastguard Worker   virtual int code() const = 0;
454*14675a02SAndroid Build Coastguard Worker 
455*14675a02SAndroid Build Coastguard Worker   // The response headers. Implementations are allowed to either coalesce
456*14675a02SAndroid Build Coastguard Worker   // repeated headers using commas (as per RFC2616 section 4.2), or to return
457*14675a02SAndroid Build Coastguard Worker   // them as separate entries.
458*14675a02SAndroid Build Coastguard Worker   //
459*14675a02SAndroid Build Coastguard Worker   // See `HttpClient` comment for the expected behavior w.r.t. a few specific
460*14675a02SAndroid Build Coastguard Worker   // headers.
461*14675a02SAndroid Build Coastguard Worker   virtual const HeaderList& headers() const = 0;
462*14675a02SAndroid Build Coastguard Worker };
463*14675a02SAndroid Build Coastguard Worker 
464*14675a02SAndroid Build Coastguard Worker }  // namespace http
465*14675a02SAndroid Build Coastguard Worker }  // namespace client
466*14675a02SAndroid Build Coastguard Worker }  // namespace fcp
467*14675a02SAndroid Build Coastguard Worker 
468*14675a02SAndroid Build Coastguard Worker #endif  // FCP_CLIENT_HTTP_HTTP_CLIENT_H_
469