1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#ifdef USE_NGTCP2
26#include <ngtcp2/ngtcp2.h>
27#include <ngtcp2/ngtcp2_crypto.h>
28#include <nghttp3/nghttp3.h>
29#include <openssl/err.h>
30#include "urldata.h"
31#include "sendf.h"
32#include "strdup.h"
33#include "rand.h"
34#include "ngtcp2.h"
35#include "multiif.h"
36#include "strcase.h"
37#include "connect.h"
38#include "strerror.h"
39
40/* The last 3 #include files should be in this order */
41#include "curl_printf.h"
42#include "curl_memory.h"
43#include "memdebug.h"
44
45/* #define DEBUG_NGTCP2 */
46#ifdef CURLDEBUG
47#define DEBUG_HTTP3
48#endif
49#ifdef DEBUG_HTTP3
50#define H3BUGF(x) x
51#else
52#define H3BUGF(x) do { } WHILE_FALSE
53#endif
54
55/*
56 * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
57 * It is used as a circular buffer. Add new bytes at the end until it reaches
58 * the far end, then start over at index 0 again.
59 */
60
61#define H3_SEND_SIZE (20*1024)
62struct h3out {
63 uint8_t buf[H3_SEND_SIZE];
64 size_t used; /* number of bytes used in the buffer */
65 size_t windex; /* index in the buffer where to start writing the next
66 data block */
67};
68
69#define QUIC_MAX_STREAMS (256*1024)
70#define QUIC_MAX_DATA (1*1024*1024)
71#define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */
72#define QUIC_CIPHERS \
73 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
74 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
75#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
76
77static CURLcode ng_process_ingress(struct connectdata *conn,
78 curl_socket_t sockfd,
79 struct quicsocket *qs);
80static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
81 struct quicsocket *qs);
82static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
83 size_t datalen, void *user_data,
84 void *stream_user_data);
85
86static ngtcp2_tstamp timestamp(void)
87{
88 struct curltime ct = Curl_now();
89 return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
90}
91
92#ifdef DEBUG_NGTCP2
93static void quic_printf(void *user_data, const char *fmt, ...)
94{
95 va_list ap;
96 (void)user_data; /* TODO, use this to do infof() instead long-term */
97 va_start(ap, fmt);
98 vfprintf(stderr, fmt, ap);
99 va_end(ap);
100 fprintf(stderr, "\n");
101}
102#endif
103
104static ngtcp2_crypto_level
105quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
106{
107 switch(ossl_level) {
108 case ssl_encryption_initial:
109 return NGTCP2_CRYPTO_LEVEL_INITIAL;
110 case ssl_encryption_early_data:
111 return NGTCP2_CRYPTO_LEVEL_EARLY;
112 case ssl_encryption_handshake:
113 return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
114 case ssl_encryption_application:
115 return NGTCP2_CRYPTO_LEVEL_APP;
116 default:
117 assert(0);
118 }
119}
120
121static int setup_initial_crypto_context(struct quicsocket *qs)
122{
123 const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(qs->qconn);
124
125 if(ngtcp2_crypto_derive_and_install_initial_key(
126 qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid,
127 NGTCP2_CRYPTO_SIDE_CLIENT) != 0)
128 return -1;
129
130 return 0;
131}
132
133static void quic_settings(ngtcp2_settings *s,
134 uint64_t stream_buffer_size)
135{
136 ngtcp2_settings_default(s);
137#ifdef DEBUG_NGTCP2
138 s->log_printf = quic_printf;
139#else
140 s->log_printf = NULL;
141#endif
142 s->initial_ts = timestamp();
143 s->transport_params.initial_max_stream_data_bidi_local = stream_buffer_size;
144 s->transport_params.initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
145 s->transport_params.initial_max_stream_data_uni = QUIC_MAX_STREAMS;
146 s->transport_params.initial_max_data = QUIC_MAX_DATA;
147 s->transport_params.initial_max_streams_bidi = 1;
148 s->transport_params.initial_max_streams_uni = 3;
149 s->transport_params.idle_timeout = QUIC_IDLE_TIMEOUT;
150}
151
152static FILE *keylog_file; /* not thread-safe */
153static void keylog_callback(const SSL *ssl, const char *line)
154{
155 (void)ssl;
156 fputs(line, keylog_file);
157 fputc('\n', keylog_file);
158 fflush(keylog_file);
159}
160
161static int init_ngh3_conn(struct quicsocket *qs);
162
163static int quic_set_encryption_secrets(SSL *ssl,
164 OSSL_ENCRYPTION_LEVEL ossl_level,
165 const uint8_t *rx_secret,
166 const uint8_t *tx_secret,
167 size_t secretlen)
168{
169 struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
170 int level = quic_from_ossl_level(ossl_level);
171
172 if(ngtcp2_crypto_derive_and_install_key(
173 qs->qconn, ssl, NULL, NULL, NULL, NULL, NULL, NULL, level, rx_secret,
174 tx_secret, secretlen, NGTCP2_CRYPTO_SIDE_CLIENT) != 0)
175 return 0;
176
177 if(level == NGTCP2_CRYPTO_LEVEL_APP) {
178 if(init_ngh3_conn(qs) != CURLE_OK)
179 return 0;
180
181 /* malloc an area big enough for both secrets */
182 qs->rx_secret = malloc(secretlen * 2);
183 if(!qs->rx_secret)
184 return 0;
185 memcpy(qs->rx_secret, rx_secret, secretlen);
186 memcpy(&qs->rx_secret[secretlen], tx_secret, secretlen);
187 qs->tx_secret = &qs->rx_secret[secretlen];
188 qs->rx_secretlen = secretlen;
189 }
190
191 return 1;
192}
193
194static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
195 const uint8_t *data, size_t len)
196{
197 struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
198 struct quic_handshake *crypto_data;
199 ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level);
200 int rv;
201
202 crypto_data = &qs->crypto_data[level];
203 if(crypto_data->buf == NULL) {
204 crypto_data->buf = malloc(4096);
205 if(!crypto_data->buf)
206 return 0;
207 crypto_data->alloclen = 4096;
208 }
209
210 /* TODO Just pretend that handshake does not grow more than 4KiB for
211 now */
212 assert(crypto_data->len + len <= crypto_data->alloclen);
213
214 memcpy(&crypto_data->buf[crypto_data->len], data, len);
215 crypto_data->len += len;
216
217 rv = ngtcp2_conn_submit_crypto_data(
218 qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len),
219 len);
220 if(rv) {
221 H3BUGF(fprintf(stderr, "write_client_handshake failed\n"));
222 }
223 assert(0 == rv);
224
225 return 1;
226}
227
228static int quic_flush_flight(SSL *ssl)
229{
230 (void)ssl;
231 return 1;
232}
233
234static int quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level,
235 uint8_t alert)
236{
237 struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
238 (void)level;
239
240 qs->tls_alert = alert;
241 return 1;
242}
243
244static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets,
245 quic_add_handshake_data,
246 quic_flush_flight, quic_send_alert};
247
248static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
249{
250 SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
251 const char *keylog_filename;
252
253 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
254 SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
255
256 SSL_CTX_set_default_verify_paths(ssl_ctx);
257
258 if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) {
259 failf(data, "SSL_CTX_set_ciphersuites: %s",
260 ERR_error_string(ERR_get_error(), NULL));
261 return NULL;
262 }
263
264 if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) {
265 failf(data, "SSL_CTX_set1_groups_list failed");
266 return NULL;
267 }
268
269 SSL_CTX_set_quic_method(ssl_ctx, &quic_method);
270
271 keylog_filename = getenv("SSLKEYLOGFILE");
272 if(keylog_filename) {
273 keylog_file = fopen(keylog_filename, "wb");
274 if(keylog_file) {
275 SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
276 }
277 }
278
279 return ssl_ctx;
280}
281
282/** SSL callbacks ***/
283
284static int quic_init_ssl(struct quicsocket *qs)
285{
286 const uint8_t *alpn = NULL;
287 size_t alpnlen = 0;
288 /* this will need some attention when HTTPS proxy over QUIC get fixed */
289 const char * const hostname = qs->conn->host.name;
290
291 if(qs->ssl)
292 SSL_free(qs->ssl);
293
294 qs->ssl = SSL_new(qs->sslctx);
295
296 SSL_set_app_data(qs->ssl, qs);
297 SSL_set_connect_state(qs->ssl);
298
299 switch(qs->version) {
300#ifdef NGTCP2_PROTO_VER
301 case NGTCP2_PROTO_VER:
302 alpn = (const uint8_t *)NGTCP2_ALPN_H3;
303 alpnlen = sizeof(NGTCP2_ALPN_H3) - 1;
304 break;
305#endif
306 }
307 if(alpn)
308 SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
309
310 /* set SNI */
311 SSL_set_tlsext_host_name(qs->ssl, hostname);
312 return 0;
313}
314
315static int cb_initial(ngtcp2_conn *quic, void *user_data)
316{
317 struct quicsocket *qs = (struct quicsocket *)user_data;
318
319 if(ngtcp2_crypto_read_write_crypto_data(
320 quic, qs->ssl, NGTCP2_CRYPTO_LEVEL_INITIAL, NULL, 0) != 0)
321 return NGTCP2_ERR_CALLBACK_FAILURE;
322
323 return 0;
324}
325
326static int
327cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
328 uint64_t offset,
329 const uint8_t *data, size_t datalen,
330 void *user_data)
331{
332 struct quicsocket *qs = (struct quicsocket *)user_data;
333 (void)offset;
334
335 if(ngtcp2_crypto_read_write_crypto_data(tconn, qs->ssl, crypto_level, data,
336 datalen) != 0)
337 return NGTCP2_ERR_CRYPTO;
338
339 return 0;
340}
341
342static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
343{
344 struct quicsocket *qs = (struct quicsocket *)user_data;
345 (void)tconn;
346 infof(qs->conn->data, "QUIC handshake is completed\n");
347
348 return 0;
349}
350
351static void extend_stream_window(ngtcp2_conn *tconn,
352 struct HTTP *stream)
353{
354 size_t thismuch = stream->unacked_window;
355 ngtcp2_conn_extend_max_stream_offset(tconn, stream->stream3_id, thismuch);
356 ngtcp2_conn_extend_max_offset(tconn, thismuch);
357 stream->unacked_window = 0;
358}
359
360
361static int cb_recv_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
362 int fin, uint64_t offset,
363 const uint8_t *buf, size_t buflen,
364 void *user_data, void *stream_user_data)
365{
366 struct quicsocket *qs = (struct quicsocket *)user_data;
367 ssize_t nconsumed;
368 (void)offset;
369 (void)stream_user_data;
370
371 nconsumed =
372 nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
373 if(nconsumed < 0) {
374 failf(qs->conn->data, "nghttp3_conn_read_stream returned error: %s\n",
375 nghttp3_strerror((int)nconsumed));
376 return NGTCP2_ERR_CALLBACK_FAILURE;
377 }
378
379 /* number of bytes inside buflen which consists of framing overhead
380 * including QPACK HEADERS. In other words, it does not consume payload of
381 * DATA frame. */
382 ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
383 ngtcp2_conn_extend_max_offset(tconn, nconsumed);
384
385 return 0;
386}
387
388static int
389cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
390 uint64_t offset, size_t datalen, void *user_data,
391 void *stream_user_data)
392{
393 struct quicsocket *qs = (struct quicsocket *)user_data;
394 int rv;
395 (void)stream_id;
396 (void)tconn;
397 (void)offset;
398 (void)datalen;
399 (void)stream_user_data;
400
401 rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
402 if(rv != 0) {
403 failf(qs->conn->data, "nghttp3_conn_add_ack_offset returned error: %s\n",
404 nghttp3_strerror(rv));
405 return NGTCP2_ERR_CALLBACK_FAILURE;
406 }
407
408 return 0;
409}
410
411static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
412 uint64_t app_error_code,
413 void *user_data, void *stream_user_data)
414{
415 struct quicsocket *qs = (struct quicsocket *)user_data;
416 int rv;
417 (void)tconn;
418 (void)stream_user_data;
419 /* stream is closed... */
420
421 rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
422 app_error_code);
423 if(rv != 0) {
424 failf(qs->conn->data, "nghttp3_conn_close_stream returned error: %s\n",
425 nghttp3_strerror(rv));
426 return NGTCP2_ERR_CALLBACK_FAILURE;
427 }
428
429 return 0;
430}
431
432static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
433 uint64_t final_size, uint64_t app_error_code,
434 void *user_data, void *stream_user_data)
435{
436 struct quicsocket *qs = (struct quicsocket *)user_data;
437 int rv;
438 (void)tconn;
439 (void)final_size;
440 (void)app_error_code;
441 (void)stream_user_data;
442
443 rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
444 if(rv != 0) {
445 failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s\n",
446 nghttp3_strerror(rv));
447 return NGTCP2_ERR_CALLBACK_FAILURE;
448 }
449
450 return 0;
451}
452
453static int cb_recv_retry(ngtcp2_conn *tconn, const ngtcp2_pkt_hd *hd,
454 const ngtcp2_pkt_retry *retry, void *user_data)
455{
456 /* Re-generate handshake secrets here because connection ID might change. */
457 struct quicsocket *qs = (struct quicsocket *)user_data;
458 (void)tconn;
459 (void)hd;
460 (void)retry;
461
462 setup_initial_crypto_context(qs);
463
464 return 0;
465}
466
467static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
468 uint64_t max_streams,
469 void *user_data)
470{
471 (void)tconn;
472 (void)max_streams;
473 (void)user_data;
474
475 return 0;
476}
477
478static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
479 uint64_t max_data, void *user_data,
480 void *stream_user_data)
481{
482 struct quicsocket *qs = (struct quicsocket *)user_data;
483 int rv;
484 (void)tconn;
485 (void)max_data;
486 (void)stream_user_data;
487
488 rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
489 if(rv != 0) {
490 failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s\n",
491 nghttp3_strerror(rv));
492 return NGTCP2_ERR_CALLBACK_FAILURE;
493 }
494
495 return 0;
496}
497
498static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
499 uint8_t *token, size_t cidlen,
500 void *user_data)
501{
502 struct quicsocket *qs = (struct quicsocket *)user_data;
503 CURLcode result;
504 (void)tconn;
505
506 result = Curl_rand(qs->conn->data, cid->data, cidlen);
507 if(result)
508 return NGTCP2_ERR_CALLBACK_FAILURE;
509 cid->datalen = cidlen;
510
511 result = Curl_rand(qs->conn->data, token, NGTCP2_STATELESS_RESET_TOKENLEN);
512 if(result)
513 return NGTCP2_ERR_CALLBACK_FAILURE;
514
515 return 0;
516}
517
518static int cb_update_key(ngtcp2_conn *tconn, uint8_t *rx_key,
519 uint8_t *rx_iv, uint8_t *tx_key,
520 uint8_t *tx_iv, void *user_data)
521{
522 struct quicsocket *qs = (struct quicsocket *)user_data;
523 uint8_t rx_secret[64];
524 uint8_t tx_secret[64];
525
526 if(ngtcp2_crypto_update_key(tconn, rx_secret, tx_secret,
527 rx_key, rx_iv, tx_key, tx_iv, qs->rx_secret,
528 qs->tx_secret, qs->rx_secretlen) != 0)
529 return NGTCP2_ERR_CALLBACK_FAILURE;
530
531 /* store the updated secrets */
532 memcpy(qs->rx_secret, rx_secret, qs->rx_secretlen);
533 memcpy(qs->tx_secret, tx_secret, qs->rx_secretlen);
534 return 0;
535}
536
537static ngtcp2_conn_callbacks ng_callbacks = {
538 cb_initial,
539 NULL, /* recv_client_initial */
540 cb_recv_crypto_data,
541 cb_handshake_completed,
542 NULL, /* recv_version_negotiation */
543 ngtcp2_crypto_encrypt_cb,
544 ngtcp2_crypto_decrypt_cb,
545 ngtcp2_crypto_hp_mask_cb,
546 cb_recv_stream_data,
547 NULL, /* acked_crypto_offset */
548 cb_acked_stream_data_offset,
549 NULL, /* stream_open */
550 cb_stream_close,
551 NULL, /* recv_stateless_reset */
552 cb_recv_retry,
553 cb_extend_max_local_streams_bidi,
554 NULL, /* extend_max_local_streams_uni */
555 NULL, /* rand */
556 cb_get_new_connection_id,
557 NULL, /* remove_connection_id */
558 cb_update_key, /* update_key */
559 NULL, /* path_validation */
560 NULL, /* select_preferred_addr */
561 cb_stream_reset,
562 NULL, /* extend_max_remote_streams_bidi */
563 NULL, /* extend_max_remote_streams_uni */
564 cb_extend_max_stream_data,
565};
566
567/*
568 * Might be called twice for happy eyeballs.
569 */
570CURLcode Curl_quic_connect(struct connectdata *conn,
571 curl_socket_t sockfd,
572 int sockindex,
573 const struct sockaddr *addr,
574 socklen_t addrlen)
575{
576 int rc;
577 int rv;
578 CURLcode result;
579 ngtcp2_path path; /* TODO: this must be initialized properly */
580 struct Curl_easy *data = conn->data;
581 struct quicsocket *qs = &conn->hequic[sockindex];
582 char ipbuf[40];
583 long port;
584 uint8_t paramsbuf[64];
585 ngtcp2_transport_params params;
586 ssize_t nwrite;
587
588 qs->conn = conn;
589
590 /* extract the used address as a string */
591 if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) {
592 char buffer[STRERROR_LEN];
593 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
594 SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
595 return CURLE_BAD_FUNCTION_ARGUMENT;
596 }
597
598 infof(data, "Connect socket %d over QUIC to %s:%ld\n",
599 sockfd, ipbuf, port);
600
601 qs->version = NGTCP2_PROTO_VER;
602 qs->sslctx = quic_ssl_ctx(data);
603 if(!qs->sslctx)
604 return CURLE_FAILED_INIT; /* TODO: better return code */
605
606 if(quic_init_ssl(qs))
607 return CURLE_FAILED_INIT; /* TODO: better return code */
608
609 qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
610 result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
611 if(result)
612 return result;
613
614 qs->scid.datalen = NGTCP2_MAX_CIDLEN;
615 result = Curl_rand(data, qs->scid.data, NGTCP2_MAX_CIDLEN);
616 if(result)
617 return result;
618
619 quic_settings(&qs->settings, data->set.buffer_size);
620
621 qs->local_addrlen = sizeof(qs->local_addr);
622 rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
623 &qs->local_addrlen);
624 if(rv == -1)
625 return CURLE_FAILED_INIT;
626
627 ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr, qs->local_addrlen,
628 NULL);
629 ngtcp2_addr_init(&path.remote, (uint8_t*)addr, addrlen, NULL);
630
631#ifdef NGTCP2_PROTO_VER
632#define QUICVER NGTCP2_PROTO_VER
633#else
634#error "unsupported ngtcp2 version"
635#endif
636 rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, QUICVER,
637 &ng_callbacks, &qs->settings, NULL, qs);
638 if(rc)
639 return CURLE_FAILED_INIT; /* TODO: create a QUIC error code */
640
641 ngtcp2_conn_get_local_transport_params(qs->qconn, &params);
642 nwrite = ngtcp2_encode_transport_params(
643 paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
644 &params);
645 if(nwrite < 0) {
646 failf(data, "ngtcp2_encode_transport_params: %s\n",
647 ngtcp2_strerror((int)nwrite));
648 return CURLE_FAILED_INIT;
649 }
650
651 if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite))
652 return CURLE_FAILED_INIT;
653
654 rc = setup_initial_crypto_context(qs);
655 if(rc)
656 return CURLE_FAILED_INIT; /* TODO: better return code */
657
658 return CURLE_OK;
659}
660
661/*
662 * Store ngtp2 version info in this buffer, Prefix with a space. Return total
663 * length written.
664 */
665int Curl_quic_ver(char *p, size_t len)
666{
667 ngtcp2_info *ng2 = ngtcp2_version(0);
668 nghttp3_info *ht3 = nghttp3_version(0);
669 return msnprintf(p, len, " ngtcp2/%s nghttp3/%s",
670 ng2->version_str, ht3->version_str);
671}
672
673static int ng_getsock(struct connectdata *conn, curl_socket_t *socks)
674{
675 struct SingleRequest *k = &conn->data->req;
676 int bitmap = GETSOCK_BLANK;
677
678 socks[0] = conn->sock[FIRSTSOCKET];
679
680 /* in a HTTP/2 connection we can basically always get a frame so we should
681 always be ready for one */
682 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
683
684 /* we're still uploading or the HTTP/2 layer wants to send data */
685 if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND)
686 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
687
688 return bitmap;
689}
690
691static int ng_perform_getsock(const struct connectdata *conn,
692 curl_socket_t *socks)
693{
694 return ng_getsock((struct connectdata *)conn, socks);
695}
696
697static CURLcode ng_disconnect(struct connectdata *conn,
698 bool dead_connection)
699{
700 int i;
701 struct quicsocket *qs = &conn->hequic[0];
702 (void)dead_connection;
703 free(qs->rx_secret);
704 if(qs->ssl)
705 SSL_free(qs->ssl);
706 for(i = 0; i < 3; i++)
707 free(qs->crypto_data[i].buf);
708 nghttp3_conn_del(qs->h3conn);
709 ngtcp2_conn_del(qs->qconn);
710 SSL_CTX_free(qs->sslctx);
711 return CURLE_OK;
712}
713
714static unsigned int ng_conncheck(struct connectdata *conn,
715 unsigned int checks_to_perform)
716{
717 (void)conn;
718 (void)checks_to_perform;
719 return CONNRESULT_NONE;
720}
721
722static const struct Curl_handler Curl_handler_http3 = {
723 "HTTPS", /* scheme */
724 ZERO_NULL, /* setup_connection */
725 Curl_http, /* do_it */
726 Curl_http_done, /* done */
727 ZERO_NULL, /* do_more */
728 ZERO_NULL, /* connect_it */
729 ZERO_NULL, /* connecting */
730 ZERO_NULL, /* doing */
731 ng_getsock, /* proto_getsock */
732 ng_getsock, /* doing_getsock */
733 ZERO_NULL, /* domore_getsock */
734 ng_perform_getsock, /* perform_getsock */
735 ng_disconnect, /* disconnect */
736 ZERO_NULL, /* readwrite */
737 ng_conncheck, /* connection_check */
738 PORT_HTTP, /* defport */
739 CURLPROTO_HTTPS, /* protocol */
740 PROTOPT_SSL | PROTOPT_STREAM /* flags */
741};
742
743static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
744 uint64_t app_error_code, void *user_data,
745 void *stream_user_data)
746{
747 struct Curl_easy *data = stream_user_data;
748 struct HTTP *stream = data->req.protop;
749 (void)conn;
750 (void)stream_id;
751 (void)app_error_code;
752 (void)user_data;
753 H3BUGF(infof(data, "cb_h3_stream_close CALLED\n"));
754
755 stream->closed = TRUE;
756 Curl_expire(data, 0, EXPIRE_QUIC);
757 /* make sure that ngh3_stream_recv is called again to complete the transfer
758 even if there are no more packets to be received from the server. */
759 data->state.drain = 1;
760 return 0;
761}
762
763/* Minimum size of the overflow buffer */
764#define OVERFLOWSIZE 1024
765
766/*
767 * allocate_overflow() ensures that there is room for incoming data in the
768 * overflow buffer, growing it to accommodate the new data if necessary. We
769 * may need to use the overflow buffer because we can't precisely limit the
770 * amount of HTTP/3 header data we receive using QUIC flow control mechanisms.
771 */
772static CURLcode allocate_overflow(struct Curl_easy *data,
773 struct HTTP *stream,
774 size_t length)
775{
776 size_t maxleft;
777 size_t newsize;
778 /* length can be arbitrarily large, so take care not to overflow newsize */
779 maxleft = CURL_MAX_READ_SIZE - stream->overflow_buflen;
780 if(length > maxleft) {
781 /* The reason to have a max limit for this is to avoid the risk of a bad
782 server feeding libcurl with a highly compressed list of headers that
783 will cause our overflow buffer to grow too large */
784 failf(data, "Rejected %zu bytes of overflow data (max is %d)!",
785 stream->overflow_buflen + length, CURL_MAX_READ_SIZE);
786 return CURLE_OUT_OF_MEMORY;
787 }
788 newsize = stream->overflow_buflen + length;
789 if(newsize > stream->overflow_bufsize) {
790 /* We enlarge the overflow buffer as it is too small */
791 char *newbuff;
792 newsize = CURLMAX(newsize * 3 / 2, stream->overflow_bufsize*2);
793 newsize = CURLMIN(CURLMAX(OVERFLOWSIZE, newsize), CURL_MAX_READ_SIZE);
794 newbuff = realloc(stream->overflow_buf, newsize);
795 if(!newbuff) {
796 failf(data, "Failed to alloc memory for overflow buffer!");
797 return CURLE_OUT_OF_MEMORY;
798 }
799 stream->overflow_buf = newbuff;
800 stream->overflow_bufsize = newsize;
801 infof(data, "Grew HTTP/3 overflow buffer to %zu bytes\n", newsize);
802 }
803 return CURLE_OK;
804}
805
806/*
807 * write_data() copies data to the stream's receive buffer. If not enough
808 * space is available in the receive buffer, it copies the rest to the
809 * stream's overflow buffer.
810 */
811static CURLcode write_data(struct Curl_easy *data,
812 struct HTTP *stream,
813 const void *mem, size_t memlen)
814{
815 CURLcode result = CURLE_OK;
816 const char *buf = mem;
817 size_t ncopy = memlen;
818 /* copy as much as possible to the receive buffer */
819 if(stream->len) {
820 size_t len = CURLMIN(ncopy, stream->len);
821#if 0 /* extra debugging of incoming h3 data */
822 fprintf(stderr, "!! Copies %zd bytes to %p (total %zd)\n",
823 len, stream->mem, stream->memlen);
824#endif
825 memcpy(stream->mem, buf, len);
826 stream->len -= len;
827 stream->memlen += len;
828 stream->mem += len;
829 buf += len;
830 ncopy -= len;
831 }
832 /* copy the rest to the overflow buffer */
833 if(ncopy) {
834 result = allocate_overflow(data, stream, ncopy);
835 if(result) {
836 return result;
837 }
838#if 0 /* extra debugging of incoming h3 data */
839 fprintf(stderr, "!! Copies %zd overflow bytes to %p (total %zd)\n",
840 ncopy, stream->overflow_buf, stream->overflow_buflen);
841#endif
842 memcpy(stream->overflow_buf + stream->overflow_buflen, buf, ncopy);
843 stream->overflow_buflen += ncopy;
844 }
845#if 0 /* extra debugging of incoming h3 data */
846 {
847 size_t i;
848 for(i = 0; i < memlen; i++) {
849 fprintf(stderr, "!! data[%d]: %02x '%c'\n", i, buf[i], buf[i]);
850 }
851 }
852#endif
853 return result;
854}
855
856static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
857 const uint8_t *buf, size_t buflen,
858 void *user_data, void *stream_user_data)
859{
860 struct Curl_easy *data = stream_user_data;
861 struct HTTP *stream = data->req.protop;
862 CURLcode result = CURLE_OK;
863 (void)conn;
864
865 result = write_data(data, stream, buf, buflen);
866 if(result) {
867 return -1;
868 }
869 stream->unacked_window += buflen;
870 (void)stream_id;
871 (void)user_data;
872 return 0;
873}
874
875static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
876 size_t consumed, void *user_data,
877 void *stream_user_data)
878{
879 struct quicsocket *qs = user_data;
880 (void)conn;
881 (void)stream_user_data;
882 (void)stream_id;
883
884 ngtcp2_conn_extend_max_stream_offset(qs->qconn, stream_id, consumed);
885 ngtcp2_conn_extend_max_offset(qs->qconn, consumed);
886 return 0;
887}
888
889/* Decode HTTP status code. Returns -1 if no valid status code was
890 decoded. (duplicate from http2.c) */
891static int decode_status_code(const uint8_t *value, size_t len)
892{
893 int i;
894 int res;
895
896 if(len != 3) {
897 return -1;
898 }
899
900 res = 0;
901
902 for(i = 0; i < 3; ++i) {
903 char c = value[i];
904
905 if(c < '0' || c > '9') {
906 return -1;
907 }
908
909 res *= 10;
910 res += c - '0';
911 }
912
913 return res;
914}
915
916static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
917 void *user_data, void *stream_user_data)
918{
919 struct Curl_easy *data = stream_user_data;
920 struct HTTP *stream = data->req.protop;
921 CURLcode result = CURLE_OK;
922 (void)conn;
923 (void)stream_id;
924 (void)user_data;
925
926 /* add a CRLF only if we've received some headers */
927 if(stream->firstheader) {
928 result = write_data(data, stream, "\r\n", 2);
929 if(result) {
930 return -1;
931 }
932 }
933 return 0;
934}
935
936static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
937 int32_t token, nghttp3_rcbuf *name,
938 nghttp3_rcbuf *value, uint8_t flags,
939 void *user_data, void *stream_user_data)
940{
941 nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
942 nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
943 struct Curl_easy *data = stream_user_data;
944 struct HTTP *stream = data->req.protop;
945 CURLcode result = CURLE_OK;
946 (void)conn;
947 (void)stream_id;
948 (void)token;
949 (void)flags;
950 (void)user_data;
951
952 if(h3name.len == sizeof(":status") - 1 &&
953 !memcmp(":status", h3name.base, h3name.len)) {
954 char line[14]; /* status line is always 13 characters long */
955 size_t ncopy;
956 int status = decode_status_code(h3val.base, h3val.len);
957 DEBUGASSERT(status != -1);
958 ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status);
959 result = write_data(data, stream, line, ncopy);
960 if(result) {
961 return -1;
962 }
963 }
964 else {
965 /* store as a HTTP1-style header */
966 result = write_data(data, stream, h3name.base, h3name.len);
967 if(result) {
968 return -1;
969 }
970 result = write_data(data, stream, ": ", 2);
971 if(result) {
972 return -1;
973 }
974 result = write_data(data, stream, h3val.base, h3val.len);
975 if(result) {
976 return -1;
977 }
978 result = write_data(data, stream, "\r\n", 2);
979 if(result) {
980 return -1;
981 }
982 }
983
984 stream->firstheader = TRUE;
985 return 0;
986}
987
988static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id,
989 uint64_t app_error_code,
990 void *user_data,
991 void *stream_user_data)
992{
993 (void)conn;
994 (void)stream_id;
995 (void)app_error_code;
996 (void)user_data;
997 (void)stream_user_data;
998 return 0;
999}
1000
1001static nghttp3_conn_callbacks ngh3_callbacks = {
1002 cb_h3_acked_stream_data, /* acked_stream_data */
1003 cb_h3_stream_close,
1004 cb_h3_recv_data,
1005 cb_h3_deferred_consume,
1006 NULL, /* begin_headers */
1007 cb_h3_recv_header,
1008 cb_h3_end_headers,
1009 NULL, /* begin_trailers */
1010 cb_h3_recv_header,
1011 NULL, /* end_trailers */
1012 NULL, /* http_begin_push_promise */
1013 NULL, /* http_recv_push_promise */
1014 NULL, /* http_end_push_promise */
1015 NULL, /* http_cancel_push */
1016 cb_h3_send_stop_sending,
1017 NULL, /* push_stream */
1018 NULL, /* end_stream */
1019};
1020
1021static int init_ngh3_conn(struct quicsocket *qs)
1022{
1023 CURLcode result;
1024 int rc;
1025 int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
1026
1027 if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
1028 failf(qs->conn->data, "too few available QUIC streams");
1029 return CURLE_FAILED_INIT;
1030 }
1031
1032 nghttp3_conn_settings_default(&qs->h3settings);
1033
1034 rc = nghttp3_conn_client_new(&qs->h3conn,
1035 &ngh3_callbacks,
1036 &qs->h3settings,
1037 nghttp3_mem_default(),
1038 qs);
1039 if(rc) {
1040 result = CURLE_OUT_OF_MEMORY;
1041 goto fail;
1042 }
1043
1044 rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL);
1045 if(rc) {
1046 result = CURLE_FAILED_INIT;
1047 goto fail;
1048 }
1049
1050 rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id);
1051 if(rc) {
1052 result = CURLE_FAILED_INIT;
1053 goto fail;
1054 }
1055
1056 rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL);
1057 if(rc) {
1058 result = CURLE_FAILED_INIT;
1059 goto fail;
1060 }
1061
1062 rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL);
1063 if(rc) {
1064 result = CURLE_FAILED_INIT;
1065 goto fail;
1066 }
1067
1068 rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id,
1069 qpack_dec_stream_id);
1070 if(rc) {
1071 result = CURLE_FAILED_INIT;
1072 goto fail;
1073 }
1074
1075 return CURLE_OK;
1076 fail:
1077
1078 return result;
1079}
1080
1081static Curl_recv ngh3_stream_recv;
1082static Curl_send ngh3_stream_send;
1083
1084static size_t drain_overflow_buffer(struct HTTP *stream)
1085{
1086 size_t ncopy = CURLMIN(stream->overflow_buflen, stream->len);
1087 if(ncopy > 0) {
1088 memcpy(stream->mem, stream->overflow_buf, ncopy);
1089 stream->len -= ncopy;
1090 stream->mem += ncopy;
1091 stream->memlen += ncopy;
1092 stream->overflow_buflen -= ncopy;
1093 memmove(stream->overflow_buf, stream->overflow_buf + ncopy,
1094 stream->overflow_buflen);
1095 }
1096 return ncopy;
1097}
1098
1099/* incoming data frames on the h3 stream */
1100static ssize_t ngh3_stream_recv(struct connectdata *conn,
1101 int sockindex,
1102 char *buf,
1103 size_t buffersize,
1104 CURLcode *curlcode)
1105{
1106 curl_socket_t sockfd = conn->sock[sockindex];
1107 struct HTTP *stream = conn->data->req.protop;
1108 struct quicsocket *qs = conn->quic;
1109
1110 if(!stream->memlen) {
1111 /* remember where to store incoming data for this stream and how big the
1112 buffer is */
1113 stream->mem = buf;
1114 stream->len = buffersize;
1115 }
1116 /* else, there's data in the buffer already */
1117
1118 /* if there's data in the overflow buffer from a previous call, copy as much
1119 as possible to the receive buffer before receiving more */
1120 drain_overflow_buffer(stream);
1121
1122 if(ng_process_ingress(conn, sockfd, qs)) {
1123 *curlcode = CURLE_RECV_ERROR;
1124 return -1;
1125 }
1126 if(ng_flush_egress(conn, sockfd, qs)) {
1127 *curlcode = CURLE_SEND_ERROR;
1128 return -1;
1129 }
1130
1131 if(stream->memlen) {
1132 ssize_t memlen = stream->memlen;
1133 /* data arrived */
1134 *curlcode = CURLE_OK;
1135 /* reset to allow more data to come */
1136 stream->memlen = 0;
1137 stream->mem = buf;
1138 stream->len = buffersize;
1139 /* extend the stream window with the data we're consuming and send out
1140 any additional packets to tell the server that we can receive more */
1141 extend_stream_window(qs->qconn, stream);
1142 if(ng_flush_egress(conn, sockfd, qs)) {
1143 *curlcode = CURLE_SEND_ERROR;
1144 return -1;
1145 }
1146 return memlen;
1147 }
1148
1149 if(stream->closed) {
1150 *curlcode = CURLE_OK;
1151 return 0;
1152 }
1153
1154 infof(conn->data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n");
1155 *curlcode = CURLE_AGAIN;
1156 return -1;
1157}
1158
1159/* this amount of data has now been acked on this stream */
1160static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1161 size_t datalen, void *user_data,
1162 void *stream_user_data)
1163{
1164 struct Curl_easy *data = stream_user_data;
1165 struct HTTP *stream = data->req.protop;
1166 (void)conn;
1167 (void)stream_id;
1168 (void)user_data;
1169
1170 if(!data->set.postfields) {
1171 stream->h3out->used -= datalen;
1172 H3BUGF(infof(data,
1173 "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n",
1174 datalen, stream->h3out->used));
1175 DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
1176 }
1177 return 0;
1178}
1179
1180static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
1181 nghttp3_vec *vec, size_t veccnt,
1182 uint32_t *pflags, void *user_data,
1183 void *stream_user_data)
1184{
1185 struct Curl_easy *data = stream_user_data;
1186 size_t nread;
1187 struct HTTP *stream = data->req.protop;
1188 (void)conn;
1189 (void)stream_id;
1190 (void)user_data;
1191 (void)veccnt;
1192
1193 if(data->set.postfields) {
1194 vec[0].base = data->set.postfields;
1195 vec[0].len = data->state.infilesize;
1196 *pflags = NGHTTP3_DATA_FLAG_EOF;
1197 return 1;
1198 }
1199
1200 nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
1201 if(nread > 0) {
1202 /* nghttp3 wants us to hold on to the data until it tells us it is okay to
1203 delete it. Append the data at the end of the h3out buffer. Since we can
1204 only return consecutive data, copy the amount that fits and the next
1205 part comes in next invoke. */
1206 struct h3out *out = stream->h3out;
1207 if(nread + out->windex > H3_SEND_SIZE)
1208 nread = H3_SEND_SIZE - out->windex;
1209
1210 memcpy(&out->buf[out->windex], stream->upload_mem, nread);
1211 out->windex += nread;
1212 out->used += nread;
1213
1214 /* that's the chunk we return to nghttp3 */
1215 vec[0].base = &out->buf[out->windex];
1216 vec[0].len = nread;
1217
1218 if(out->windex == H3_SEND_SIZE)
1219 out->windex = 0; /* wrap */
1220 stream->upload_mem += nread;
1221 stream->upload_len -= nread;
1222 if(data->state.infilesize != -1) {
1223 stream->upload_left -= nread;
1224 if(!stream->upload_left)
1225 *pflags = NGHTTP3_DATA_FLAG_EOF;
1226 }
1227 H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)\n",
1228 nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
1229 out->used));
1230 }
1231 if(stream->upload_done && !stream->upload_len &&
1232 (stream->upload_left <= 0)) {
1233 H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n"));
1234 *pflags = NGHTTP3_DATA_FLAG_EOF;
1235 return 0;
1236 }
1237 else if(!nread) {
1238 return NGHTTP3_ERR_WOULDBLOCK;
1239 }
1240 return 1;
1241}
1242
1243/* Index where :authority header field will appear in request header
1244 field list. */
1245#define AUTHORITY_DST_IDX 3
1246
1247static CURLcode http_request(struct connectdata *conn, const void *mem,
1248 size_t len)
1249{
1250 struct HTTP *stream = conn->data->req.protop;
1251 size_t nheader;
1252 size_t i;
1253 size_t authority_idx;
1254 char *hdbuf = (char *)mem;
1255 char *end, *line_end;
1256 struct quicsocket *qs = conn->quic;
1257 CURLcode result = CURLE_OK;
1258 struct Curl_easy *data = conn->data;
1259 nghttp3_nv *nva = NULL;
1260 int64_t stream3_id;
1261 int rc;
1262 struct h3out *h3out = NULL;
1263
1264 rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL);
1265 if(rc) {
1266 failf(conn->data, "can get bidi streams");
1267 result = CURLE_SEND_ERROR;
1268 goto fail;
1269 }
1270
1271 stream->stream3_id = stream3_id;
1272 stream->h3req = TRUE; /* senf off! */
1273
1274 /* Calculate number of headers contained in [mem, mem + len). Assumes a
1275 correctly generated HTTP header field block. */
1276 nheader = 0;
1277 for(i = 1; i < len; ++i) {
1278 if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
1279 ++nheader;
1280 ++i;
1281 }
1282 }
1283 if(nheader < 2)
1284 goto fail;
1285
1286 /* We counted additional 2 \r\n in the first and last line. We need 3
1287 new headers: :method, :path and :scheme. Therefore we need one
1288 more space. */
1289 nheader += 1;
1290 nva = malloc(sizeof(nghttp3_nv) * nheader);
1291 if(!nva) {
1292 result = CURLE_OUT_OF_MEMORY;
1293 goto fail;
1294 }
1295
1296 /* Extract :method, :path from request line
1297 We do line endings with CRLF so checking for CR is enough */
1298 line_end = memchr(hdbuf, '\r', len);
1299 if(!line_end) {
1300 result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */
1301 goto fail;
1302 }
1303
1304 /* Method does not contain spaces */
1305 end = memchr(hdbuf, ' ', line_end - hdbuf);
1306 if(!end || end == hdbuf)
1307 goto fail;
1308 nva[0].name = (unsigned char *)":method";
1309 nva[0].namelen = strlen((char *)nva[0].name);
1310 nva[0].value = (unsigned char *)hdbuf;
1311 nva[0].valuelen = (size_t)(end - hdbuf);
1312 nva[0].flags = NGHTTP3_NV_FLAG_NONE;
1313
1314 hdbuf = end + 1;
1315
1316 /* Path may contain spaces so scan backwards */
1317 end = NULL;
1318 for(i = (size_t)(line_end - hdbuf); i; --i) {
1319 if(hdbuf[i - 1] == ' ') {
1320 end = &hdbuf[i - 1];
1321 break;
1322 }
1323 }
1324 if(!end || end == hdbuf)
1325 goto fail;
1326 nva[1].name = (unsigned char *)":path";
1327 nva[1].namelen = strlen((char *)nva[1].name);
1328 nva[1].value = (unsigned char *)hdbuf;
1329 nva[1].valuelen = (size_t)(end - hdbuf);
1330 nva[1].flags = NGHTTP3_NV_FLAG_NONE;
1331
1332 nva[2].name = (unsigned char *)":scheme";
1333 nva[2].namelen = strlen((char *)nva[2].name);
1334 if(conn->handler->flags & PROTOPT_SSL)
1335 nva[2].value = (unsigned char *)"https";
1336 else
1337 nva[2].value = (unsigned char *)"http";
1338 nva[2].valuelen = strlen((char *)nva[2].value);
1339 nva[2].flags = NGHTTP3_NV_FLAG_NONE;
1340
1341
1342 authority_idx = 0;
1343 i = 3;
1344 while(i < nheader) {
1345 size_t hlen;
1346
1347 hdbuf = line_end + 2;
1348
1349 /* check for next CR, but only within the piece of data left in the given
1350 buffer */
1351 line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
1352 if(!line_end || (line_end == hdbuf))
1353 goto fail;
1354
1355 /* header continuation lines are not supported */
1356 if(*hdbuf == ' ' || *hdbuf == '\t')
1357 goto fail;
1358
1359 for(end = hdbuf; end < line_end && *end != ':'; ++end)
1360 ;
1361 if(end == hdbuf || end == line_end)
1362 goto fail;
1363 hlen = end - hdbuf;
1364
1365 if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
1366 authority_idx = i;
1367 nva[i].name = (unsigned char *)":authority";
1368 nva[i].namelen = strlen((char *)nva[i].name);
1369 }
1370 else {
1371 nva[i].namelen = (size_t)(end - hdbuf);
1372 /* Lower case the header name for HTTP/3 */
1373 Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
1374 nva[i].name = (unsigned char *)hdbuf;
1375 }
1376 nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1377 hdbuf = end + 1;
1378 while(*hdbuf == ' ' || *hdbuf == '\t')
1379 ++hdbuf;
1380 end = line_end;
1381
1382#if 0 /* This should probably go in more or less like this */
1383 switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
1384 end - hdbuf)) {
1385 case HEADERINST_IGNORE:
1386 /* skip header fields prohibited by HTTP/2 specification. */
1387 --nheader;
1388 continue;
1389 case HEADERINST_TE_TRAILERS:
1390 nva[i].value = (uint8_t*)"trailers";
1391 nva[i].value_len = sizeof("trailers") - 1;
1392 break;
1393 default:
1394 nva[i].value = (unsigned char *)hdbuf;
1395 nva[i].value_len = (size_t)(end - hdbuf);
1396 }
1397#endif
1398 nva[i].value = (unsigned char *)hdbuf;
1399 nva[i].valuelen = (size_t)(end - hdbuf);
1400 nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1401
1402 ++i;
1403 }
1404
1405 /* :authority must come before non-pseudo header fields */
1406 if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
1407 nghttp3_nv authority = nva[authority_idx];
1408 for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
1409 nva[i] = nva[i - 1];
1410 }
1411 nva[i] = authority;
1412 }
1413
1414 /* Warn stream may be rejected if cumulative length of headers is too
1415 large. */
1416#define MAX_ACC 60000 /* <64KB to account for some overhead */
1417 {
1418 size_t acc = 0;
1419 for(i = 0; i < nheader; ++i)
1420 acc += nva[i].namelen + nva[i].valuelen;
1421
1422 if(acc > MAX_ACC) {
1423 infof(data, "http_request: Warning: The cumulative length of all "
1424 "headers exceeds %zu bytes and that could cause the "
1425 "stream to be rejected.\n", MAX_ACC);
1426 }
1427 }
1428
1429 switch(data->set.httpreq) {
1430 case HTTPREQ_POST:
1431 case HTTPREQ_POST_FORM:
1432 case HTTPREQ_POST_MIME:
1433 case HTTPREQ_PUT: {
1434 nghttp3_data_reader data_reader;
1435 if(data->state.infilesize != -1)
1436 stream->upload_left = data->state.infilesize;
1437 else
1438 /* data sending without specifying the data amount up front */
1439 stream->upload_left = -1; /* unknown, but not zero */
1440
1441 data_reader.read_data = cb_h3_readfunction;
1442
1443 h3out = calloc(sizeof(struct h3out), 1);
1444 if(!h3out) {
1445 result = CURLE_OUT_OF_MEMORY;
1446 goto fail;
1447 }
1448 stream->h3out = h3out;
1449
1450 rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1451 nva, nheader, &data_reader,
1452 conn->data);
1453 if(rc) {
1454 result = CURLE_SEND_ERROR;
1455 goto fail;
1456 }
1457 break;
1458 }
1459 default:
1460 stream->upload_left = 0; /* nothing left to send */
1461 rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1462 nva, nheader,
1463 NULL, /* no body! */
1464 conn->data);
1465 if(rc) {
1466 result = CURLE_SEND_ERROR;
1467 goto fail;
1468 }
1469 break;
1470 }
1471
1472 Curl_safefree(nva);
1473
1474 infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
1475 stream3_id, (void *)data);
1476
1477 return CURLE_OK;
1478
1479fail:
1480 free(nva);
1481 return result;
1482}
1483static ssize_t ngh3_stream_send(struct connectdata *conn,
1484 int sockindex,
1485 const void *mem,
1486 size_t len,
1487 CURLcode *curlcode)
1488{
1489 ssize_t sent;
1490 struct quicsocket *qs = conn->quic;
1491 curl_socket_t sockfd = conn->sock[sockindex];
1492 struct HTTP *stream = conn->data->req.protop;
1493
1494 if(!stream->h3req) {
1495 CURLcode result = http_request(conn, mem, len);
1496 if(result) {
1497 *curlcode = CURLE_SEND_ERROR;
1498 return -1;
1499 }
1500 sent = len;
1501 }
1502 else {
1503 H3BUGF(infof(conn->data, "ngh3_stream_send() wants to send %zd bytes\n",
1504 len));
1505 if(!stream->upload_len) {
1506 stream->upload_mem = mem;
1507 stream->upload_len = len;
1508 (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
1509 sent = len;
1510 }
1511 else {
1512 *curlcode = CURLE_AGAIN;
1513 return -1;
1514 }
1515 }
1516
1517 if(ng_flush_egress(conn, sockfd, qs)) {
1518 *curlcode = CURLE_SEND_ERROR;
1519 return -1;
1520 }
1521
1522 *curlcode = CURLE_OK;
1523 return sent;
1524}
1525
1526static void ng_has_connected(struct connectdata *conn, int tempindex)
1527{
1528 conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
1529 conn->send[FIRSTSOCKET] = ngh3_stream_send;
1530 conn->handler = &Curl_handler_http3;
1531 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1532 conn->httpversion = 30;
1533 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1534 conn->quic = &conn->hequic[tempindex];
1535 DEBUGF(infof(conn->data, "ngtcp2 established connection!\n"));
1536}
1537
1538/*
1539 * There can be multiple connection attempts going on in parallel.
1540 */
1541CURLcode Curl_quic_is_connected(struct connectdata *conn,
1542 int sockindex,
1543 bool *done)
1544{
1545 CURLcode result;
1546 struct quicsocket *qs = &conn->hequic[sockindex];
1547 curl_socket_t sockfd = conn->tempsock[sockindex];
1548
1549 result = ng_process_ingress(conn, sockfd, qs);
1550 if(result)
1551 return result;
1552
1553 result = ng_flush_egress(conn, sockfd, qs);
1554 if(result)
1555 return result;
1556
1557 if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
1558 *done = TRUE;
1559 ng_has_connected(conn, sockindex);
1560 }
1561
1562 return result;
1563}
1564
1565static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
1566 struct quicsocket *qs)
1567{
1568 ssize_t recvd;
1569 int rv;
1570 uint8_t buf[65536];
1571 size_t bufsize = sizeof(buf);
1572 struct sockaddr_storage remote_addr;
1573 socklen_t remote_addrlen;
1574 ngtcp2_path path;
1575 ngtcp2_tstamp ts = timestamp();
1576
1577 for(;;) {
1578 remote_addrlen = sizeof(remote_addr);
1579 while((recvd = recvfrom(sockfd, buf, bufsize, 0,
1580 (struct sockaddr *)&remote_addr,
1581 &remote_addrlen)) == -1 &&
1582 SOCKERRNO == EINTR)
1583 ;
1584 if(recvd == -1) {
1585 if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
1586 break;
1587
1588 failf(conn->data, "ngtcp2: recvfrom() unexpectedly returned %d", recvd);
1589 return CURLE_RECV_ERROR;
1590 }
1591
1592 ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr,
1593 qs->local_addrlen, NULL);
1594 ngtcp2_addr_init(&path.remote, (uint8_t *)&remote_addr, remote_addrlen,
1595 NULL);
1596
1597 rv = ngtcp2_conn_read_pkt(qs->qconn, &path, buf, recvd, ts);
1598 if(rv != 0) {
1599 /* TODO Send CONNECTION_CLOSE if possible */
1600 return CURLE_RECV_ERROR;
1601 }
1602 }
1603
1604 return CURLE_OK;
1605}
1606
1607static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
1608 struct quicsocket *qs)
1609{
1610 int rv;
1611 ssize_t sent;
1612 ssize_t outlen;
1613 uint8_t out[NGTCP2_MAX_PKTLEN_IPV4];
1614 size_t pktlen;
1615 ngtcp2_path_storage ps;
1616 ngtcp2_tstamp ts = timestamp();
1617 struct sockaddr_storage remote_addr;
1618 ngtcp2_tstamp expiry;
1619 ngtcp2_duration timeout;
1620 int64_t stream_id;
1621 ssize_t veccnt;
1622 int fin;
1623 nghttp3_vec vec[16];
1624 ssize_t ndatalen;
1625
1626 switch(qs->local_addr.ss_family) {
1627 case AF_INET:
1628 pktlen = NGTCP2_MAX_PKTLEN_IPV4;
1629 break;
1630 case AF_INET6:
1631 pktlen = NGTCP2_MAX_PKTLEN_IPV6;
1632 break;
1633 default:
1634 assert(0);
1635 }
1636
1637 rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
1638 if(rv != 0) {
1639 failf(conn->data, "ngtcp2_conn_handle_expiry returned error: %s\n",
1640 ngtcp2_strerror(rv));
1641 return CURLE_SEND_ERROR;
1642 }
1643
1644 ngtcp2_path_storage_zero(&ps);
1645
1646 for(;;) {
1647 outlen = -1;
1648 if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) {
1649 veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec,
1650 sizeof(vec) / sizeof(vec[0]));
1651 if(veccnt < 0) {
1652 failf(conn->data, "nghttp3_conn_writev_stream returned error: %s\n",
1653 nghttp3_strerror((int)veccnt));
1654 return CURLE_SEND_ERROR;
1655 }
1656 else if(veccnt > 0) {
1657 outlen =
1658 ngtcp2_conn_writev_stream(qs->qconn, &ps.path,
1659 out, pktlen, &ndatalen,
1660 NGTCP2_WRITE_STREAM_FLAG_MORE,
1661 stream_id, fin,
1662 (const ngtcp2_vec *)vec, veccnt, ts);
1663 if(outlen == 0) {
1664 break;
1665 }
1666 if(outlen < 0) {
1667 if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
1668 outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
1669 rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
1670 if(rv != 0) {
1671 failf(conn->data,
1672 "nghttp3_conn_block_stream returned error: %s\n",
1673 nghttp3_strerror(rv));
1674 return CURLE_SEND_ERROR;
1675 }
1676 continue;
1677 }
1678 else if(outlen == NGTCP2_ERR_WRITE_STREAM_MORE) {
1679 assert(ndatalen > 0);
1680 rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id,
1681 ndatalen);
1682 if(rv != 0) {
1683 failf(conn->data,
1684 "nghttp3_conn_add_write_offset returned error: %s\n",
1685 nghttp3_strerror(rv));
1686 return CURLE_SEND_ERROR;
1687 }
1688 continue;
1689 }
1690 else {
1691 failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n",
1692 ngtcp2_strerror((int)outlen));
1693 return CURLE_SEND_ERROR;
1694 }
1695 }
1696 else if(ndatalen >= 0) {
1697 rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
1698 if(rv != 0) {
1699 failf(conn->data,
1700 "nghttp3_conn_add_write_offset returned error: %s\n",
1701 nghttp3_strerror(rv));
1702 return CURLE_SEND_ERROR;
1703 }
1704 }
1705 }
1706 }
1707 if(outlen < 0) {
1708 outlen = ngtcp2_conn_write_pkt(qs->qconn, &ps.path, out, pktlen, ts);
1709 if(outlen < 0) {
1710 failf(conn->data, "ngtcp2_conn_write_pkt returned error: %s\n",
1711 ngtcp2_strerror((int)outlen));
1712 return CURLE_SEND_ERROR;
1713 }
1714 if(outlen == 0)
1715 break;
1716 }
1717
1718 memcpy(&remote_addr, ps.path.remote.addr, ps.path.remote.addrlen);
1719 while((sent = send(sockfd, out, outlen, 0)) == -1 &&
1720 SOCKERRNO == EINTR)
1721 ;
1722
1723 if(sent == -1) {
1724 if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
1725 /* TODO Cache packet */
1726 break;
1727 }
1728 else {
1729 failf(conn->data, "send() returned %zd (errno %d)\n", sent,
1730 SOCKERRNO);
1731 return CURLE_SEND_ERROR;
1732 }
1733 }
1734 }
1735
1736 expiry = ngtcp2_conn_get_expiry(qs->qconn);
1737 if(expiry != UINT64_MAX) {
1738 if(expiry <= ts) {
1739 timeout = NGTCP2_MILLISECONDS;
1740 }
1741 else {
1742 timeout = expiry - ts;
1743 }
1744 Curl_expire(conn->data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
1745 }
1746
1747 return CURLE_OK;
1748}
1749
1750/*
1751 * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
1752 */
1753CURLcode Curl_quic_done_sending(struct connectdata *conn)
1754{
1755 if(conn->handler == &Curl_handler_http3) {
1756 /* only for HTTP/3 transfers */
1757 struct HTTP *stream = conn->data->req.protop;
1758 struct quicsocket *qs = conn->quic;
1759 stream->upload_done = TRUE;
1760 (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
1761 }
1762
1763 return CURLE_OK;
1764}
1765
1766/*
1767 * Called from http.c:Curl_http_done when a request completes.
1768 */
1769void Curl_quic_done(struct Curl_easy *data, bool premature)
1770{
1771 (void)premature;
1772 if(data->conn->handler == &Curl_handler_http3) {
1773 /* only for HTTP/3 transfers */
1774 struct HTTP *stream = data->req.protop;
1775 Curl_safefree(stream->overflow_buf);
1776 }
1777}
1778
1779/*
1780 * Called from transfer.c:data_pending to know if we should keep looping
1781 * to receive more data from the connection.
1782 */
1783bool Curl_quic_data_pending(const struct Curl_easy *data)
1784{
1785 /* We may have received more data than we're able to hold in the receive
1786 buffer and allocated an overflow buffer. Since it's possible that
1787 there's no more data coming on the socket, we need to keep reading
1788 until the overflow buffer is empty. */
1789 const struct HTTP *stream = data->req.protop;
1790 return stream->overflow_buflen > 0;
1791}
1792
1793#endif
1794