1 /*
2  * Copyright (c) 2017 Ichito Nagata, Fastly, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 #ifndef h2o__httpclient_h
23 #define h2o__httpclient_h
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #include "quicly.h"
30 #include "h2o/header.h"
31 #include "h2o/hostinfo.h"
32 #include "h2o/http3_common.h"
33 #include "h2o/send_state.h"
34 #include "h2o/socket.h"
35 #include "h2o/socketpool.h"
36 
37 typedef struct st_h2o_httpclient_t h2o_httpclient_t;
38 
39 typedef void (*h2o_httpclient_forward_datagram_cb)(h2o_httpclient_t *client, h2o_iovec_t *datagrams, size_t num_datagrams);
40 
41 /**
42  * Additional properties related to the HTTP request being issued.
43  * When the connect callback is being called, the properties of the objects are set to their initial values. Applications MAY alter
44  * the properties to achieve desirable behavior. The reason we require the protocol stacks to initialize the values to their default
45  * values instead of requiring applications to set all the values correctly is to avoid requiring applications making changes
46  * every time a new field is added to the object.
47  */
48 typedef struct st_h2o_httpclient_properties_t {
49     /**
50      * When the value is a non-NULL pointer (at the moment, only happens with the HTTP/1 client), the application MAY set it to an
51      * iovec pointing to the payload of the PROXY protocol (i.e., the first line).
52      */
53     h2o_iovec_t *proxy_protocol;
54     /**
55      * When the value is a non-NULL pointer (at the moment, only happens with the HTTP/1 client), the application MAY set it to 1 to
56      * indicate that the request body should be encoded using the chunked transfer-encoding.
57      */
58     int *chunked;
59     /**
60      * When the value is a non-NULL pointer (at the moment, only happens with the HTTP/1 client), the application MAY set it to the
61      * value of the connection header field to be sent to the server. This can be used for upgrading an HTTP/1.1 connection.
62      */
63     h2o_iovec_t *connection_header;
64 } h2o_httpclient_properties_t;
65 
66 typedef struct st_h2o_httpclient_on_head_t {
67     int version;
68     int status;
69     h2o_iovec_t msg;
70     h2o_header_t *headers;
71     size_t num_headers;
72     int header_requires_dup;
73     struct {
74         h2o_httpclient_forward_datagram_cb write_, *read_;
75     } forward_datagram;
76 } h2o_httpclient_on_head_t;
77 
78 typedef void (*h2o_httpclient_proceed_req_cb)(h2o_httpclient_t *client, const char *errstr);
79 typedef int (*h2o_httpclient_body_cb)(h2o_httpclient_t *client, const char *errstr);
80 typedef h2o_httpclient_body_cb (*h2o_httpclient_head_cb)(h2o_httpclient_t *client, const char *errstr,
81                                                          h2o_httpclient_on_head_t *args);
82 /**
83  * Called when the protocol stack is ready to issue a request. Application must set all the output parameters (i.e. all except
84  * `client`, `errstr`, `origin`) and return a callback that will be called when the protocol stack receives the response headers
85  * from the server.
86  */
87 typedef h2o_httpclient_head_cb (*h2o_httpclient_connect_cb)(h2o_httpclient_t *client, const char *errstr, h2o_iovec_t *method,
88                                                             h2o_url_t *url, const h2o_header_t **headers, size_t *num_headers,
89                                                             h2o_iovec_t *body, h2o_httpclient_proceed_req_cb *proceed_req_cb,
90                                                             h2o_httpclient_properties_t *props, h2o_url_t *origin);
91 typedef int (*h2o_httpclient_informational_cb)(h2o_httpclient_t *client, int version, int status, h2o_iovec_t msg,
92                                                h2o_header_t *headers, size_t num_headers);
93 
94 typedef void (*h2o_httpclient_finish_cb)(h2o_httpclient_t *client);
95 
96 typedef struct st_h2o_httpclient_connection_pool_t {
97     /**
98      * used to establish connections and pool those when h1 is used.
99      * socketpool is shared among multiple threads while connection pool is dedicated to each thread
100      */
101     h2o_socketpool_t *socketpool;
102 
103     struct {
104         h2o_linklist_t conns;
105     } http2;
106 
107     struct {
108         h2o_linklist_t conns;
109     } http3;
110 
111 } h2o_httpclient_connection_pool_t;
112 
113 typedef struct st_h2o_httpclient_protocol_ratio_t {
114     /**
115      * If non-negative, indicates the percentage of requests for which use of HTTP/2 will be attempted. If set to negative, all
116      * connections are established with ALPN offering both H1 and H2, then the load is balanced between the different protocol
117      * versions. This behavior helps balance the load among a mixture of servers behind a load balancer, some supporting both H1 and
118      * H2 and some supporting only H1.
119      */
120     int8_t http2;
121     /**
122      * Indicates the percentage of requests for which HTTP/3 should be used. Unlike HTTP/2, this value cannot be negative, because
123      * unlike ALPN over TLS over TCP, the choice of the protocol is up to the client.
124      */
125     int8_t http3;
126 } h2o_httpclient_protocol_ratio_t;
127 
128 typedef struct st_h2o_http3client_ctx_t h2o_http3client_ctx_t;
129 
130 typedef struct st_h2o_httpclient_ctx_t {
131     h2o_loop_t *loop;
132     h2o_multithread_receiver_t *getaddr_receiver;
133     uint64_t io_timeout;
134     uint64_t connect_timeout;
135     uint64_t first_byte_timeout;
136     uint64_t keepalive_timeout; /* only used for http2 for now */
137     size_t max_buffer_size;
138     unsigned tunnel_enabled : 1;
139     unsigned force_cleartext_http2 : 1;
140 
141     struct st_h2o_httpclient_protocol_selector_t {
142         h2o_httpclient_protocol_ratio_t ratio;
143         /**
144          * Each deficit is initialized to zero, then incremented by the respective percentage, and the protocol corresponding to the
145          * one with the highest value is chosen. Then, the chosen variable is decremented by 100.
146          */
147         int16_t _deficits[4];
148     } protocol_selector;
149 
150     /**
151      * HTTP/2-specific settings
152      */
153     struct {
154         h2o_socket_latency_optimization_conditions_t latency_optimization;
155         uint32_t max_concurrent_streams;
156     } http2;
157 
158     /**
159      * HTTP/3-specific settings; 1-to(0|1) relationship, NULL when h3 is not used
160      */
161     h2o_http3client_ctx_t *http3;
162 
163 } h2o_httpclient_ctx_t;
164 
165 struct st_h2o_http3client_ctx_t {
166     ptls_context_t tls;
167     quicly_context_t quic;
168     h2o_quic_ctx_t h3;
169     /**
170      * Optional callback invoked by the HTTP/3 client implementation to obtain information used for resuming a connection. When the
171      * connection is to be resumed, the callback should set `*address_token` and `*session_ticket` to a vector that can be freed by
172      * calling free (3), as well as writing the resumed transport parameters to `*resumed_tp`. Otherwise, `*address_token`,
173      * `*session_ticket`, `*resumed_tp` can be left untouched, and a full handshake will be exercised. The function returns if the
174      * operation was successful. When false is returned, the connection attempt is aborted.
175      */
176     int (*load_session)(h2o_httpclient_ctx_t *ctx, struct sockaddr *server_addr, const char *server_name,
177                         ptls_iovec_t *address_token, ptls_iovec_t *session_ticket, quicly_transport_parameters_t *resumed_tp);
178 };
179 
180 typedef struct st_h2o_httpclient_timings_t {
181     struct timeval start_at;
182     struct timeval request_begin_at;
183     struct timeval request_end_at;
184     struct timeval response_start_at;
185     struct timeval response_end_at;
186 } h2o_httpclient_timings_t;
187 
188 /**
189  * Properties of a HTTP client connection.
190  */
191 typedef struct st_h2o_httpclient_conn_properties_t {
192     /**
193      * TLS properties. Definitions match that returned by corresponding h2o_socket function: `h2o_socket_ssl_*`.
194      */
195     struct {
196         const char *protocol_version;
197         int session_reused;
198         const char *cipher;
199         int cipher_bits;
200     } ssl;
201     /**
202      * Underlying TCP connection, if any.
203      */
204     h2o_socket_t *sock;
205 } h2o_httpclient_conn_properties_t;
206 
207 struct st_h2o_httpclient_t {
208     /**
209      * memory pool
210      */
211     h2o_mem_pool_t *pool;
212     /**
213      * context
214      */
215     h2o_httpclient_ctx_t *ctx;
216     /**
217      * connection pool
218      */
219     h2o_httpclient_connection_pool_t *connpool;
220     /**
221      * buffer in which response data is stored (see update_window)
222      */
223     h2o_buffer_t **buf;
224     /**
225      * application data pointer
226      */
227     void *data;
228     /**
229      * optional callback to receive informational response(s)
230      */
231     h2o_httpclient_informational_cb informational_cb;
232     /**
233      * server-timing data
234      */
235     h2o_httpclient_timings_t timings;
236     /**
237      * If the stream is to be converted to convey some other protocol, this value should be set to the name of the protocol, which
238      * will be indicated by the `upgrade` request header field. Additionally, intent to create a CONNECT tunnel is indicated by a
239      * special label called `h2o_httpclient_req_upgrade_connect`.
240      */
241     const char *upgrade_to;
242 
243     /**
244      * bytes written (above the TLS layer)
245      */
246     struct {
247         uint64_t header;
248         uint64_t body;
249         uint64_t total;
250     } bytes_written;
251 
252     /**
253      * bytes read (above the TLS layer)
254      */
255     struct {
256         uint64_t header;
257         uint64_t body;
258         uint64_t total;
259     } bytes_read;
260 
261     /**
262      * cancels a in-flight request
263      */
264     void (*cancel)(h2o_httpclient_t *client);
265     /**
266      * returns a pointer to the underlying h2o_socket_t
267      */
268     void (*get_conn_properties)(h2o_httpclient_t *client, h2o_httpclient_conn_properties_t *properties);
269     /**
270      * callback that should be called when some data is fetched out from `buf`.
271      */
272     void (*update_window)(h2o_httpclient_t *client);
273     /**
274      * Function for writing request body. `proceed_req_cb` supplied through the `on_connect` callback will be called when the
275      * given data is sent to the server. Regarding the usage, refer to the doc-comment of `h2o_write_req_cb`.
276      */
277     int (*write_req)(h2o_httpclient_t *client, h2o_iovec_t chunk, int is_end_stream);
278 
279     h2o_timer_t _timeout;
280     h2o_socketpool_connect_request_t *_connect_req;
281     union {
282         h2o_httpclient_connect_cb on_connect;
283         h2o_httpclient_head_cb on_head;
284         h2o_httpclient_body_cb on_body;
285     } _cb;
286 };
287 
288 /**
289  * public members of h2 client connection
290  */
291 typedef struct st_h2o_httpclient__h2_conn_t {
292     /**
293      * context
294      */
295     h2o_httpclient_ctx_t *ctx;
296     /**
297      * origin server (path is ignored)
298      */
299     h2o_url_t origin_url;
300     /**
301      * underlying socket
302      */
303     h2o_socket_t *sock;
304     /**
305      * number of open streams (FIXME can't we refer to khash?)
306      */
307     size_t num_streams;
308     /**
309      * linklist of connections anchored to h2o_httpclient_connection_pool_t::http2.conns. The link is in the ascending order of
310      * `num_streams`.
311      */
312     h2o_linklist_t link;
313 } h2o_httpclient__h2_conn_t;
314 
315 struct st_h2o_httpclient__h3_conn_t {
316     h2o_http3_conn_t super;
317     h2o_httpclient_ctx_t *ctx;
318     /**
319      * When the socket is associated to a global pool, used to identify the origin. If not associated to a global pool, the values
320      * are zero-filled.
321      */
322     struct {
323         /**
324          * the origin URL; null-termination of authority and host is guaranteed
325          */
326         h2o_url_t origin_url;
327         /**
328          * port number in C string
329          */
330         char named_serv[sizeof(H2O_UINT16_LONGEST_STR)];
331     } server;
332     ptls_handshake_properties_t handshake_properties;
333     h2o_timer_t timeout;
334     h2o_hostinfo_getaddr_req_t *getaddr_req;
335     /**
336      * linked to h2o_httpclient_ctx_t::http3.conns
337      */
338     h2o_linklist_t link;
339     /**
340      * linklist used to queue pending requests
341      */
342     h2o_linklist_t pending_requests;
343 };
344 
345 extern const char h2o_httpclient_error_is_eos[];
346 extern const char h2o_httpclient_error_refused_stream[];
347 extern const char h2o_httpclient_error_unknown_alpn_protocol[];
348 extern const char h2o_httpclient_error_io[];
349 extern const char h2o_httpclient_error_connect_timeout[];
350 extern const char h2o_httpclient_error_first_byte_timeout[];
351 extern const char h2o_httpclient_error_io_timeout[];
352 extern const char h2o_httpclient_error_invalid_content_length[];
353 extern const char h2o_httpclient_error_flow_control[];
354 extern const char h2o_httpclient_error_http1_line_folding[];
355 extern const char h2o_httpclient_error_http1_unexpected_transfer_encoding[];
356 extern const char h2o_httpclient_error_http1_parse_failed[];
357 extern const char h2o_httpclient_error_protocol_violation[];
358 extern const char h2o_httpclient_error_internal[];
359 extern const char h2o_httpclient_error_malformed_frame[];
360 
361 extern const char h2o_httpclient_upgrade_to_connect[];
362 
363 void h2o_httpclient_connection_pool_init(h2o_httpclient_connection_pool_t *connpool, h2o_socketpool_t *sockpool);
364 
365 /**
366  * issues a HTTP request using the connection pool. Either H1 or H2 may be used, depending on the given context.
367  * TODO: create H1- or H2-specific connect function that works without the connection pool?
368  */
369 void h2o_httpclient_connect(h2o_httpclient_t **client, h2o_mem_pool_t *pool, void *data, h2o_httpclient_ctx_t *ctx,
370                             h2o_httpclient_connection_pool_t *connpool, h2o_url_t *target, const char *upgrade_to,
371                             h2o_httpclient_connect_cb on_connect);
372 
373 void h2o_httpclient__h1_on_connect(h2o_httpclient_t *client, h2o_socket_t *sock, h2o_url_t *origin);
374 extern const size_t h2o_httpclient__h1_size;
375 
376 void h2o_httpclient__h2_on_connect(h2o_httpclient_t *client, h2o_socket_t *sock, h2o_url_t *origin);
377 uint32_t h2o_httpclient__h2_get_max_concurrent_streams(h2o_httpclient__h2_conn_t *conn);
378 extern const size_t h2o_httpclient__h2_size;
379 
380 void h2o_httpclient_set_conn_properties_of_socket(h2o_socket_t *sock, h2o_httpclient_conn_properties_t *properties);
381 
382 #ifdef quicly_h /* create http3client.h? */
383 
384 #include "h2o/http3_common.h"
385 
386 void h2o_httpclient_http3_notify_connection_update(h2o_quic_ctx_t *ctx, h2o_quic_conn_t *conn);
387 extern quicly_stream_open_t h2o_httpclient_http3_on_stream_open;
388 extern quicly_receive_datagram_frame_t h2o_httpclient_http3_on_receive_datagram_frame;
389 void h2o_httpclient__connect_h3(h2o_httpclient_t **client, h2o_mem_pool_t *pool, void *data, h2o_httpclient_ctx_t *ctx,
390                                 h2o_httpclient_connection_pool_t *connpool, h2o_url_t *target, const char *upgrade_to,
391                                 h2o_httpclient_connect_cb cb);
392 /**
393  * internal API for checking if the stream is to be turned into a tunnel
394  */
395 static int h2o_httpclient__tunnel_is_ready(h2o_httpclient_t *client, int status);
396 
397 /* inline definitions */
398 
h2o_httpclient__tunnel_is_ready(h2o_httpclient_t * client,int status)399 inline int h2o_httpclient__tunnel_is_ready(h2o_httpclient_t *client, int status)
400 {
401     if (client->upgrade_to != NULL) {
402         if (client->upgrade_to == h2o_httpclient_upgrade_to_connect && 200 <= status && status <= 299)
403             return 1;
404         if (status == 101)
405             return 1;
406     }
407     return 0;
408 }
409 
410 #endif
411 
412 #ifdef __cplusplus
413 }
414 #endif
415 
416 #endif
417