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