• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
28 
29 #include <openssl/ssl.h>
30 #include <openssl/bio.h>
31 #include <openssl/err.h>
32 #include <nghttp3/nghttp3.h>
33 
34 #include "urldata.h"
35 #include "sendf.h"
36 #include "strdup.h"
37 #include "rand.h"
38 #include "multiif.h"
39 #include "strcase.h"
40 #include "cfilters.h"
41 #include "cf-socket.h"
42 #include "connect.h"
43 #include "progress.h"
44 #include "strerror.h"
45 #include "dynbuf.h"
46 #include "http1.h"
47 #include "select.h"
48 #include "inet_pton.h"
49 #include "vquic.h"
50 #include "vquic_int.h"
51 #include "vquic-tls.h"
52 #include "vtls/keylog.h"
53 #include "vtls/vtls.h"
54 #include "vtls/openssl.h"
55 #include "curl_osslq.h"
56 
57 #include "warnless.h"
58 
59 /* The last 3 #include files should be in this order */
60 #include "curl_printf.h"
61 #include "curl_memory.h"
62 #include "memdebug.h"
63 
64 /* A stream window is the maximum amount we need to buffer for
65  * each active transfer. We use HTTP/3 flow control and only ACK
66  * when we take things out of the buffer.
67  * Chunk size is large enough to take a full DATA frame */
68 #define H3_STREAM_WINDOW_SIZE (128 * 1024)
69 #define H3_STREAM_CHUNK_SIZE   (16 * 1024)
70 /* The pool keeps spares around and half of a full stream windows
71  * seems good. More does not seem to improve performance.
72  * The benefit of the pool is that stream buffer to not keep
73  * spares. So memory consumption goes down when streams run empty,
74  * have a large upload done, etc. */
75 #define H3_STREAM_POOL_SPARES \
76           (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
77 /* Receive and Send max number of chunks just follows from the
78  * chunk size and window size */
79 #define H3_STREAM_RECV_CHUNKS \
80           (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
81 #define H3_STREAM_SEND_CHUNKS \
82           (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
83 
84 #ifndef ARRAYSIZE
85 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
86 #endif
87 
88 #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
89 typedef uint32_t sslerr_t;
90 #else
91 typedef unsigned long sslerr_t;
92 #endif
93 
94 
95 /* How to access `call_data` from a cf_osslq filter */
96 #undef CF_CTX_CALL_DATA
97 #define CF_CTX_CALL_DATA(cf)  \
98   ((struct cf_osslq_ctx *)(cf)->ctx)->call_data
99 
100 static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
101                                     struct Curl_easy *data);
102 
SSL_ERROR_to_str(int err)103 static const char *SSL_ERROR_to_str(int err)
104 {
105   switch(err) {
106   case SSL_ERROR_NONE:
107     return "SSL_ERROR_NONE";
108   case SSL_ERROR_SSL:
109     return "SSL_ERROR_SSL";
110   case SSL_ERROR_WANT_READ:
111     return "SSL_ERROR_WANT_READ";
112   case SSL_ERROR_WANT_WRITE:
113     return "SSL_ERROR_WANT_WRITE";
114   case SSL_ERROR_WANT_X509_LOOKUP:
115     return "SSL_ERROR_WANT_X509_LOOKUP";
116   case SSL_ERROR_SYSCALL:
117     return "SSL_ERROR_SYSCALL";
118   case SSL_ERROR_ZERO_RETURN:
119     return "SSL_ERROR_ZERO_RETURN";
120   case SSL_ERROR_WANT_CONNECT:
121     return "SSL_ERROR_WANT_CONNECT";
122   case SSL_ERROR_WANT_ACCEPT:
123     return "SSL_ERROR_WANT_ACCEPT";
124 #if defined(SSL_ERROR_WANT_ASYNC)
125   case SSL_ERROR_WANT_ASYNC:
126     return "SSL_ERROR_WANT_ASYNC";
127 #endif
128 #if defined(SSL_ERROR_WANT_ASYNC_JOB)
129   case SSL_ERROR_WANT_ASYNC_JOB:
130     return "SSL_ERROR_WANT_ASYNC_JOB";
131 #endif
132 #if defined(SSL_ERROR_WANT_EARLY)
133   case SSL_ERROR_WANT_EARLY:
134     return "SSL_ERROR_WANT_EARLY";
135 #endif
136   default:
137     return "SSL_ERROR unknown";
138   }
139 }
140 
141 /* Return error string for last OpenSSL error */
ossl_strerror(unsigned long error,char * buf,size_t size)142 static char *ossl_strerror(unsigned long error, char *buf, size_t size)
143 {
144   DEBUGASSERT(size);
145   *buf = '\0';
146 
147 #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
148   ERR_error_string_n((uint32_t)error, buf, size);
149 #else
150   ERR_error_string_n(error, buf, size);
151 #endif
152 
153   if(!*buf) {
154     const char *msg = error ? "Unknown error" : "No error";
155     if(strlen(msg) < size)
156       strcpy(buf, msg);
157   }
158 
159   return buf;
160 }
161 
make_bio_addr(BIO_ADDR ** pbio_addr,const struct Curl_sockaddr_ex * addr)162 static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
163                               const struct Curl_sockaddr_ex *addr)
164 {
165   BIO_ADDR *ba;
166   CURLcode result = CURLE_FAILED_INIT;
167 
168   ba = BIO_ADDR_new();
169   if(!ba) {
170     result = CURLE_OUT_OF_MEMORY;
171     goto out;
172   }
173 
174   switch(addr->family) {
175   case AF_INET: {
176     struct sockaddr_in * const sin =
177       (struct sockaddr_in * const)(void *)&addr->sa_addr;
178     if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr,
179                          sizeof(sin->sin_addr), sin->sin_port)) {
180       goto out;
181     }
182     result = CURLE_OK;
183     break;
184   }
185 #ifdef ENABLE_IPV6
186   case AF_INET6: {
187     struct sockaddr_in6 * const sin =
188       (struct sockaddr_in6 * const)(void *)&addr->sa_addr;
189     if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr,
190                          sizeof(sin->sin6_addr), sin->sin6_port)) {
191     }
192     result = CURLE_OK;
193     break;
194   }
195 #endif /* ENABLE_IPV6 */
196   default:
197     /* sunsupported */
198     DEBUGASSERT(0);
199     break;
200   }
201 
202 out:
203   if(result && ba) {
204     BIO_ADDR_free(ba);
205     ba = NULL;
206   }
207   *pbio_addr = ba;
208   return result;
209 }
210 
211 /* QUIC stream (not necessarily H3) */
212 struct cf_osslq_stream {
213   int64_t id;
214   SSL *ssl;
215   struct bufq recvbuf; /* QUIC war data recv buffer */
216   BIT(recvd_eos);
217   BIT(closed);
218   BIT(reset);
219   BIT(send_blocked);
220 };
221 
cf_osslq_stream_open(struct cf_osslq_stream * s,SSL * conn,uint64_t flags,struct bufc_pool * bufcp,void * user_data)222 static CURLcode cf_osslq_stream_open(struct cf_osslq_stream *s,
223                                      SSL *conn,
224                                      uint64_t flags,
225                                      struct bufc_pool *bufcp,
226                                      void *user_data)
227 {
228   DEBUGASSERT(!s->ssl);
229   Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE);
230   s->ssl = SSL_new_stream(conn, flags);
231   if(!s->ssl) {
232     return CURLE_FAILED_INIT;
233   }
234   s->id = SSL_get_stream_id(s->ssl);
235   SSL_set_app_data(s->ssl, user_data);
236   return CURLE_OK;
237 }
238 
cf_osslq_stream_cleanup(struct cf_osslq_stream * s)239 static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s)
240 {
241   if(s->ssl) {
242     SSL_set_app_data(s->ssl, NULL);
243     SSL_free(s->ssl);
244   }
245   Curl_bufq_free(&s->recvbuf);
246   memset(s, 0, sizeof(*s));
247 }
248 
cf_osslq_stream_close(struct cf_osslq_stream * s)249 static void cf_osslq_stream_close(struct cf_osslq_stream *s)
250 {
251   if(s->ssl) {
252     SSL_free(s->ssl);
253     s->ssl = NULL;
254   }
255 }
256 
257 struct cf_osslq_h3conn {
258   nghttp3_conn *conn;
259   nghttp3_settings settings;
260   struct cf_osslq_stream s_ctrl;
261   struct cf_osslq_stream s_qpack_enc;
262   struct cf_osslq_stream s_qpack_dec;
263   struct cf_osslq_stream remote_ctrl[3]; /* uni streams opened by the peer */
264   size_t remote_ctrl_n; /* number of peer streams opened */
265 };
266 
cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn * h3)267 static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3)
268 {
269   size_t i;
270 
271   if(h3->conn)
272     nghttp3_conn_del(h3->conn);
273   cf_osslq_stream_cleanup(&h3->s_ctrl);
274   cf_osslq_stream_cleanup(&h3->s_qpack_enc);
275   cf_osslq_stream_cleanup(&h3->s_qpack_dec);
276   for(i = 0; i < h3->remote_ctrl_n; ++i) {
277     cf_osslq_stream_cleanup(&h3->remote_ctrl[i]);
278   }
279 }
280 
281 struct cf_osslq_ctx {
282   struct cf_quic_ctx q;
283   struct ssl_peer peer;
284   struct quic_tls_ctx tls;
285   struct cf_call_data call_data;
286   struct cf_osslq_h3conn h3;
287   struct curltime started_at;        /* time the current attempt started */
288   struct curltime handshake_at;      /* time connect handshake finished */
289   struct curltime first_byte_at;     /* when first byte was recvd */
290   struct curltime reconnect_at;      /* time the next attempt should start */
291   struct bufc_pool stream_bufcp;     /* chunk pool for streams */
292   size_t max_stream_window;          /* max flow window for one stream */
293   uint64_t max_idle_ms;              /* max idle time for QUIC connection */
294   BIT(got_first_byte);               /* if first byte was received */
295 #ifdef USE_OPENSSL
296   BIT(x509_store_setup);             /* if x509 store has been set up */
297   BIT(protocol_shutdown);            /* QUIC connection is shut down */
298 #endif
299 };
300 
cf_osslq_ctx_clear(struct cf_osslq_ctx * ctx)301 static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx)
302 {
303   struct cf_call_data save = ctx->call_data;
304 
305   cf_osslq_h3conn_cleanup(&ctx->h3);
306   Curl_vquic_tls_cleanup(&ctx->tls);
307   vquic_ctx_free(&ctx->q);
308   Curl_bufcp_free(&ctx->stream_bufcp);
309   Curl_ssl_peer_cleanup(&ctx->peer);
310 
311   memset(ctx, 0, sizeof(*ctx));
312   ctx->call_data = save;
313 }
314 
cf_osslq_close(struct Curl_cfilter * cf,struct Curl_easy * data)315 static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
316 {
317   struct cf_osslq_ctx *ctx = cf->ctx;
318   struct cf_call_data save;
319 
320   CF_DATA_SAVE(save, cf, data);
321   if(ctx && ctx->tls.ssl) {
322     /* TODO: send connection close */
323     CURL_TRC_CF(data, cf, "cf_osslq_close()");
324     cf_osslq_ctx_clear(ctx);
325   }
326 
327   cf->connected = FALSE;
328   CF_DATA_RESTORE(cf, save);
329 }
330 
cf_osslq_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)331 static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
332 {
333   struct cf_osslq_ctx *ctx = cf->ctx;
334   struct cf_call_data save;
335 
336   CF_DATA_SAVE(save, cf, data);
337   CURL_TRC_CF(data, cf, "destroy");
338   if(ctx) {
339     CURL_TRC_CF(data, cf, "cf_osslq_destroy()");
340     cf_osslq_ctx_clear(ctx);
341     free(ctx);
342   }
343   cf->ctx = NULL;
344   /* No CF_DATA_RESTORE(cf, save) possible */
345   (void)save;
346 }
347 
cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn * h3,SSL * stream_ssl,struct Curl_cfilter * cf,struct Curl_easy * data)348 static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
349                                            SSL *stream_ssl,
350                                            struct Curl_cfilter *cf,
351                                            struct Curl_easy *data)
352 {
353   struct cf_osslq_ctx *ctx = cf->ctx;
354   int64_t stream_id = SSL_get_stream_id(stream_ssl);
355 
356   if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
357     /* rejected, we are full */
358     CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting additional remote stream",
359                 stream_id);
360     SSL_free(stream_ssl);
361     return CURLE_FAILED_INIT;
362   }
363   switch(SSL_get_stream_type(stream_ssl)) {
364     case SSL_STREAM_TYPE_READ: {
365       struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++];
366       nstream->id = stream_id;
367       nstream->ssl = stream_ssl;
368       Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
369       CURL_TRC_CF(data, cf, "[%" PRId64 "] accepted new remote uni stream",
370                   stream_id);
371       break;
372     }
373     default:
374       CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting remote non-uni-read"
375                   " stream", stream_id);
376       SSL_free(stream_ssl);
377       return CURLE_FAILED_INIT;
378   }
379   return CURLE_OK;
380 
381 }
382 
cf_osslq_ssl_err(struct Curl_cfilter * cf,struct Curl_easy * data,int detail,CURLcode def_result)383 static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
384                               struct Curl_easy *data,
385                               int detail, CURLcode def_result)
386 {
387   struct cf_osslq_ctx *ctx = cf->ctx;
388   CURLcode result = def_result;
389   sslerr_t errdetail;
390   char ebuf[256] = "unknown";
391   const char *err_descr = ebuf;
392   long lerr;
393   int lib;
394   int reason;
395   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
396 
397   errdetail = ERR_get_error();
398   lib = ERR_GET_LIB(errdetail);
399   reason = ERR_GET_REASON(errdetail);
400 
401   if((lib == ERR_LIB_SSL) &&
402      ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) ||
403       (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
404     result = CURLE_PEER_FAILED_VERIFICATION;
405 
406     lerr = SSL_get_verify_result(ctx->tls.ssl);
407     if(lerr != X509_V_OK) {
408       ssl_config->certverifyresult = lerr;
409       msnprintf(ebuf, sizeof(ebuf),
410                 "SSL certificate problem: %s",
411                 X509_verify_cert_error_string(lerr));
412     }
413     else
414       err_descr = "SSL certificate verification failed";
415   }
416 #if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
417   /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
418      OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
419   else if((lib == ERR_LIB_SSL) &&
420           (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) {
421     /* If client certificate is required, communicate the
422        error to client */
423     result = CURLE_SSL_CLIENTCERT;
424     ossl_strerror(errdetail, ebuf, sizeof(ebuf));
425   }
426 #endif
427   else if((lib == ERR_LIB_SSL) && (reason == SSL_R_PROTOCOL_IS_SHUTDOWN)) {
428     ctx->protocol_shutdown = TRUE;
429     err_descr = "QUIC connectin has been shut down";
430     result = def_result;
431   }
432   else {
433     result = def_result;
434     ossl_strerror(errdetail, ebuf, sizeof(ebuf));
435   }
436 
437   /* detail is already set to the SSL error above */
438 
439   /* If we e.g. use SSLv2 request-method and the server doesn't like us
440    * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
441    * the SO_ERROR is also lost.
442    */
443   if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
444     char extramsg[80]="";
445     int sockerr = SOCKERRNO;
446     const char *r_ip = NULL;
447     int r_port = 0;
448 
449     Curl_cf_socket_peek(cf->next, data, NULL, NULL,
450                         &r_ip, &r_port, NULL, NULL);
451     if(sockerr && detail == SSL_ERROR_SYSCALL)
452       Curl_strerror(sockerr, extramsg, sizeof(extramsg));
453     failf(data, "QUIC connect: %s in connection to %s:%d (%s)",
454           extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
455           ctx->peer.dispname, r_port, r_ip);
456   }
457   else {
458     /* Could be a CERT problem */
459     failf(data, "%s", err_descr);
460   }
461   return result;
462 }
463 
cf_osslq_verify_peer(struct Curl_cfilter * cf,struct Curl_easy * data)464 static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf,
465                                   struct Curl_easy *data)
466 {
467   struct cf_osslq_ctx *ctx = cf->ctx;
468 
469   cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
470   cf->conn->httpversion = 30;
471   cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
472 
473   return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
474 }
475 
476 /**
477  * All about the H3 internals of a stream
478  */
479 struct h3_stream_ctx {
480   struct cf_osslq_stream s;
481   struct bufq sendbuf;   /* h3 request body */
482   struct bufq recvbuf;   /* h3 response body */
483   struct h1_req_parser h1; /* h1 request parsing */
484   size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
485   size_t upload_blocked_len; /* the amount written last and EGAINed */
486   size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
487   uint64_t error3; /* HTTP/3 stream error code */
488   curl_off_t upload_left; /* number of request bytes left to upload */
489   curl_off_t download_recvd; /* number of response DATA bytes received */
490   int status_code; /* HTTP status code */
491   bool resp_hds_complete; /* we have a complete, final response */
492   bool closed; /* TRUE on stream close */
493   bool reset;  /* TRUE on stream reset */
494   bool send_closed; /* stream is local closed */
495   BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
496 };
497 
498 #define H3_STREAM_CTX(d)  ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
499                            ((struct HTTP *)(d)->req.p.http)->h3_ctx \
500                              : NULL))
501 #define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
502 #define H3_STREAM_ID(d)   (H3_STREAM_CTX(d)? \
503                            H3_STREAM_CTX(d)->s.id : -2)
504 
h3_data_setup(struct Curl_cfilter * cf,struct Curl_easy * data)505 static CURLcode h3_data_setup(struct Curl_cfilter *cf,
506                               struct Curl_easy *data)
507 {
508   struct cf_osslq_ctx *ctx = cf->ctx;
509   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
510 
511   if(!data || !data->req.p.http) {
512     failf(data, "initialization failure, transfer not http initialized");
513     return CURLE_FAILED_INIT;
514   }
515 
516   if(stream)
517     return CURLE_OK;
518 
519   stream = calloc(1, sizeof(*stream));
520   if(!stream)
521     return CURLE_OUT_OF_MEMORY;
522 
523   stream->s.id = -1;
524   /* on send, we control how much we put into the buffer */
525   Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
526                   H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
527   stream->sendbuf_len_in_flight = 0;
528   /* on recv, we need a flexible buffer limit since we also write
529    * headers to it that are not counted against the nghttp3 flow limits. */
530   Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
531                   H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
532   stream->recv_buf_nonflow = 0;
533   Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
534 
535   H3_STREAM_LCTX(data) = stream;
536   return CURLE_OK;
537 }
538 
h3_data_done(struct Curl_cfilter * cf,struct Curl_easy * data)539 static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
540 {
541   struct cf_osslq_ctx *ctx = cf->ctx;
542   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
543 
544   (void)cf;
545   if(stream) {
546     CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->s.id);
547     if(ctx->h3.conn && !stream->closed) {
548       nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id);
549       nghttp3_conn_close_stream(ctx->h3.conn, stream->s.id,
550                                 NGHTTP3_H3_REQUEST_CANCELLED);
551       nghttp3_conn_set_stream_user_data(ctx->h3.conn, stream->s.id, NULL);
552       stream->closed = TRUE;
553     }
554 
555     cf_osslq_stream_cleanup(&stream->s);
556     Curl_bufq_free(&stream->sendbuf);
557     Curl_bufq_free(&stream->recvbuf);
558     Curl_h1_req_parse_free(&stream->h1);
559     free(stream);
560     H3_STREAM_LCTX(data) = NULL;
561   }
562 }
563 
cf_osslq_get_qstream(struct Curl_cfilter * cf,struct Curl_easy * data,int64_t stream_id)564 static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
565                                                     struct Curl_easy *data,
566                                                     int64_t stream_id)
567 {
568   struct cf_osslq_ctx *ctx = cf->ctx;
569   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
570   struct Curl_easy *sdata;
571 
572   if(stream && stream->s.id == stream_id) {
573     return &stream->s;
574   }
575   else if(ctx->h3.s_ctrl.id == stream_id) {
576     return &ctx->h3.s_ctrl;
577   }
578   else if(ctx->h3.s_qpack_enc.id == stream_id) {
579     return &ctx->h3.s_qpack_enc;
580   }
581   else if(ctx->h3.s_qpack_dec.id == stream_id) {
582     return &ctx->h3.s_qpack_dec;
583   }
584   else {
585     DEBUGASSERT(data->multi);
586     for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
587       if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
588         stream = H3_STREAM_CTX(sdata);
589         return stream? &stream->s : NULL;
590       }
591     }
592   }
593   return NULL;
594 }
595 
h3_drain_stream(struct Curl_cfilter * cf,struct Curl_easy * data)596 static void h3_drain_stream(struct Curl_cfilter *cf,
597                             struct Curl_easy *data)
598 {
599   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
600   unsigned char bits;
601 
602   (void)cf;
603   bits = CURL_CSELECT_IN;
604   if(stream && stream->upload_left && !stream->send_closed)
605     bits |= CURL_CSELECT_OUT;
606   if(data->state.select_bits != bits) {
607     data->state.select_bits = bits;
608     Curl_expire(data, 0, EXPIRE_RUN_NOW);
609   }
610 }
611 
h3_data_pause(struct Curl_cfilter * cf,struct Curl_easy * data,bool pause)612 static CURLcode h3_data_pause(struct Curl_cfilter *cf,
613                               struct Curl_easy *data,
614                               bool pause)
615 {
616   if(!pause) {
617     /* unpaused. make it run again right away */
618     h3_drain_stream(cf, data);
619     Curl_expire(data, 0, EXPIRE_RUN_NOW);
620   }
621   return CURLE_OK;
622 }
623 
cb_h3_stream_close(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)624 static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
625                               uint64_t app_error_code, void *user_data,
626                               void *stream_user_data)
627 {
628   struct Curl_cfilter *cf = user_data;
629   struct Curl_easy *data = stream_user_data;
630   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
631   (void)conn;
632   (void)stream_id;
633 
634   /* we might be called by nghttp3 after we already cleaned up */
635   if(!stream)
636     return 0;
637 
638   stream->closed = TRUE;
639   stream->error3 = app_error_code;
640   if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
641     stream->reset = TRUE;
642     stream->send_closed = TRUE;
643     CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64,
644                 stream->s.id, stream->error3);
645   }
646   else {
647     CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->s.id);
648   }
649   h3_drain_stream(cf, data);
650   return 0;
651 }
652 
653 /*
654  * write_resp_raw() copies response data in raw format to the `data`'s
655   * receive buffer. If not enough space is available, it appends to the
656  * `data`'s overflow buffer.
657  */
write_resp_raw(struct Curl_cfilter * cf,struct Curl_easy * data,const void * mem,size_t memlen,bool flow)658 static CURLcode write_resp_raw(struct Curl_cfilter *cf,
659                                struct Curl_easy *data,
660                                const void *mem, size_t memlen,
661                                bool flow)
662 {
663   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
664   CURLcode result = CURLE_OK;
665   ssize_t nwritten;
666 
667   (void)cf;
668   if(!stream) {
669     return CURLE_RECV_ERROR;
670   }
671   nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
672   if(nwritten < 0) {
673     return result;
674   }
675 
676   if(!flow)
677     stream->recv_buf_nonflow += (size_t)nwritten;
678 
679   if((size_t)nwritten < memlen) {
680     /* This MUST not happen. Our recbuf is dimensioned to hold the
681      * full max_stream_window and then some for this very reason. */
682     DEBUGASSERT(0);
683     return CURLE_RECV_ERROR;
684   }
685   return result;
686 }
687 
cb_h3_recv_data(nghttp3_conn * conn,int64_t stream3_id,const uint8_t * buf,size_t buflen,void * user_data,void * stream_user_data)688 static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
689                            const uint8_t *buf, size_t buflen,
690                            void *user_data, void *stream_user_data)
691 {
692   struct Curl_cfilter *cf = user_data;
693   struct Curl_easy *data = stream_user_data;
694   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
695   CURLcode result;
696 
697   (void)conn;
698   (void)stream3_id;
699 
700   if(!stream)
701     return NGHTTP3_ERR_CALLBACK_FAILURE;
702 
703   result = write_resp_raw(cf, data, buf, buflen, TRUE);
704   if(result) {
705     CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
706                 stream->s.id, buflen, result);
707     return NGHTTP3_ERR_CALLBACK_FAILURE;
708   }
709   stream->download_recvd += (curl_off_t)buflen;
710   CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, total=%zd",
711               stream->s.id, buflen, stream->download_recvd);
712   h3_drain_stream(cf, data);
713   return 0;
714 }
715 
cb_h3_deferred_consume(nghttp3_conn * conn,int64_t stream_id,size_t consumed,void * user_data,void * stream_user_data)716 static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
717                                   size_t consumed, void *user_data,
718                                   void *stream_user_data)
719 {
720   struct Curl_cfilter *cf = user_data;
721   struct Curl_easy *data = stream_user_data;
722   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
723 
724   (void)conn;
725   (void)stream_id;
726   if(stream)
727     CURL_TRC_CF(data, cf, "[%" PRId64 "] deferred consume %zu bytes",
728                 stream->s.id, consumed);
729   return 0;
730 }
731 
cb_h3_recv_header(nghttp3_conn * conn,int64_t stream_id,int32_t token,nghttp3_rcbuf * name,nghttp3_rcbuf * value,uint8_t flags,void * user_data,void * stream_user_data)732 static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
733                              int32_t token, nghttp3_rcbuf *name,
734                              nghttp3_rcbuf *value, uint8_t flags,
735                              void *user_data, void *stream_user_data)
736 {
737   struct Curl_cfilter *cf = user_data;
738   nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
739   nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
740   struct Curl_easy *data = stream_user_data;
741   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
742   CURLcode result = CURLE_OK;
743   (void)conn;
744   (void)stream_id;
745   (void)token;
746   (void)flags;
747   (void)cf;
748 
749   /* we might have cleaned up this transfer already */
750   if(!stream)
751     return 0;
752 
753   if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
754     char line[14]; /* status line is always 13 characters long */
755     size_t ncopy;
756 
757     result = Curl_http_decode_status(&stream->status_code,
758                                      (const char *)h3val.base, h3val.len);
759     if(result)
760       return -1;
761     ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
762                       stream->status_code);
763     CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
764     result = write_resp_raw(cf, data, line, ncopy, FALSE);
765     if(result) {
766       return -1;
767     }
768   }
769   else {
770     /* store as an HTTP1-style header */
771     CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
772                 stream_id, (int)h3name.len, h3name.base,
773                 (int)h3val.len, h3val.base);
774     result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
775     if(result) {
776       return -1;
777     }
778     result = write_resp_raw(cf, data, ": ", 2, FALSE);
779     if(result) {
780       return -1;
781     }
782     result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE);
783     if(result) {
784       return -1;
785     }
786     result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
787     if(result) {
788       return -1;
789     }
790   }
791   return 0;
792 }
793 
cb_h3_end_headers(nghttp3_conn * conn,int64_t stream_id,int fin,void * user_data,void * stream_user_data)794 static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
795                              int fin, void *user_data, void *stream_user_data)
796 {
797   struct Curl_cfilter *cf = user_data;
798   struct Curl_easy *data = stream_user_data;
799   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
800   CURLcode result = CURLE_OK;
801   (void)conn;
802   (void)stream_id;
803   (void)fin;
804   (void)cf;
805 
806   if(!stream)
807     return 0;
808   /* add a CRLF only if we've received some headers */
809   result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
810   if(result) {
811     return -1;
812   }
813 
814   CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d",
815               stream_id, stream->status_code);
816   if(stream->status_code / 100 != 1) {
817     stream->resp_hds_complete = TRUE;
818   }
819   h3_drain_stream(cf, data);
820   return 0;
821 }
822 
cb_h3_stop_sending(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)823 static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
824                               uint64_t app_error_code, void *user_data,
825                               void *stream_user_data)
826 {
827   struct Curl_cfilter *cf = user_data;
828   struct Curl_easy *data = stream_user_data;
829   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
830   (void)conn;
831   (void)app_error_code;
832 
833   if(!stream || !stream->s.ssl)
834     return 0;
835 
836   CURL_TRC_CF(data, cf, "[%" PRId64 "] stop_sending", stream_id);
837   cf_osslq_stream_close(&stream->s);
838   return 0;
839 }
840 
cb_h3_reset_stream(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)841 static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
842                               uint64_t app_error_code, void *user_data,
843                               void *stream_user_data) {
844   struct Curl_cfilter *cf = user_data;
845   struct Curl_easy *data = stream_user_data;
846   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
847   int rv;
848   (void)conn;
849 
850   if(stream && stream->s.ssl) {
851     SSL_STREAM_RESET_ARGS args = {0};
852     args.quic_error_code = app_error_code;
853     rv = !SSL_stream_reset(stream->s.ssl, &args, sizeof(args));
854     CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
855     if(!rv) {
856       return NGHTTP3_ERR_CALLBACK_FAILURE;
857     }
858   }
859   return 0;
860 }
861 
862 static nghttp3_ssize
cb_h3_read_req_body(nghttp3_conn * conn,int64_t stream_id,nghttp3_vec * vec,size_t veccnt,uint32_t * pflags,void * user_data,void * stream_user_data)863 cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
864                     nghttp3_vec *vec, size_t veccnt,
865                     uint32_t *pflags, void *user_data,
866                     void *stream_user_data)
867 {
868   struct Curl_cfilter *cf = user_data;
869   struct Curl_easy *data = stream_user_data;
870   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
871   ssize_t nwritten = 0;
872   size_t nvecs = 0;
873   (void)cf;
874   (void)conn;
875   (void)stream_id;
876   (void)user_data;
877   (void)veccnt;
878 
879   if(!stream)
880     return NGHTTP3_ERR_CALLBACK_FAILURE;
881   /* nghttp3 keeps references to the sendbuf data until it is ACKed
882    * by the server (see `cb_h3_acked_req_body()` for updates).
883    * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
884    * that we have already passed to nghttp3, but which have not been
885    * ACKed yet.
886    * Any amount beyond `sendbuf_len_in_flight` we need still to pass
887    * to nghttp3. Do that now, if we can. */
888   if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
889     nvecs = 0;
890     while(nvecs < veccnt &&
891           Curl_bufq_peek_at(&stream->sendbuf,
892                             stream->sendbuf_len_in_flight,
893                             (const unsigned char **)&vec[nvecs].base,
894                             &vec[nvecs].len)) {
895       stream->sendbuf_len_in_flight += vec[nvecs].len;
896       nwritten += vec[nvecs].len;
897       ++nvecs;
898     }
899     DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
900   }
901 
902   if(nwritten > 0 && stream->upload_left != -1)
903     stream->upload_left -= nwritten;
904 
905   /* When we stopped sending and everything in `sendbuf` is "in flight",
906    * we are at the end of the request body. */
907   if(stream->upload_left == 0) {
908     *pflags = NGHTTP3_DATA_FLAG_EOF;
909     stream->send_closed = TRUE;
910   }
911   else if(!nwritten) {
912     /* Not EOF, and nothing to give, we signal WOULDBLOCK. */
913     CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN",
914                 stream->s.id);
915     return NGHTTP3_ERR_WOULDBLOCK;
916   }
917 
918   CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> "
919               "%d vecs%s with %zu (buffered=%zu, left=%"
920               CURL_FORMAT_CURL_OFF_T ")",
921               stream->s.id, (int)nvecs,
922               *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
923               nwritten, Curl_bufq_len(&stream->sendbuf),
924               stream->upload_left);
925   return (nghttp3_ssize)nvecs;
926 }
927 
cb_h3_acked_stream_data(nghttp3_conn * conn,int64_t stream_id,uint64_t datalen,void * user_data,void * stream_user_data)928 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
929                                    uint64_t datalen, void *user_data,
930                                    void *stream_user_data)
931 {
932   struct Curl_cfilter *cf = user_data;
933   struct Curl_easy *data = stream_user_data;
934   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
935   size_t skiplen;
936 
937   (void)cf;
938   if(!stream)
939     return 0;
940   /* The server acknowledged `datalen` of bytes from our request body.
941    * This is a delta. We have kept this data in `sendbuf` for
942    * re-transmissions and can free it now. */
943   if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
944     skiplen = stream->sendbuf_len_in_flight;
945   else
946     skiplen = (size_t)datalen;
947   Curl_bufq_skip(&stream->sendbuf, skiplen);
948   stream->sendbuf_len_in_flight -= skiplen;
949 
950   /* Everything ACKed, we resume upload processing */
951   if(!stream->sendbuf_len_in_flight) {
952     int rv = nghttp3_conn_resume_stream(conn, stream_id);
953     if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
954       return NGHTTP3_ERR_CALLBACK_FAILURE;
955     }
956   }
957   return 0;
958 }
959 
960 static nghttp3_callbacks ngh3_callbacks = {
961   cb_h3_acked_stream_data,
962   cb_h3_stream_close,
963   cb_h3_recv_data,
964   cb_h3_deferred_consume,
965   NULL, /* begin_headers */
966   cb_h3_recv_header,
967   cb_h3_end_headers,
968   NULL, /* begin_trailers */
969   cb_h3_recv_header,
970   NULL, /* end_trailers */
971   cb_h3_stop_sending,
972   NULL, /* end_stream */
973   cb_h3_reset_stream,
974   NULL, /* shutdown */
975   NULL /* recv_settings */
976 };
977 
cf_osslq_h3conn_init(struct cf_osslq_ctx * ctx,SSL * conn,void * user_data)978 static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn,
979                                   void *user_data)
980 {
981   struct cf_osslq_h3conn *h3 = &ctx->h3;
982   CURLcode result;
983   int rc;
984 
985   nghttp3_settings_default(&h3->settings);
986   rc = nghttp3_conn_client_new(&h3->conn,
987                                &ngh3_callbacks,
988                                &h3->settings,
989                                nghttp3_mem_default(),
990                                user_data);
991   if(rc) {
992     result = CURLE_OUT_OF_MEMORY;
993     goto out;
994   }
995 
996   result = cf_osslq_stream_open(&h3->s_ctrl, conn,
997                                 SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
998                                 &ctx->stream_bufcp, NULL);
999   if(result) {
1000     result = CURLE_QUIC_CONNECT_ERROR;
1001     goto out;
1002   }
1003   result = cf_osslq_stream_open(&h3->s_qpack_enc, conn,
1004                                 SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
1005                                 &ctx->stream_bufcp, NULL);
1006   if(result) {
1007     result = CURLE_QUIC_CONNECT_ERROR;
1008     goto out;
1009   }
1010   result = cf_osslq_stream_open(&h3->s_qpack_dec, conn,
1011                                 SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
1012                                 &ctx->stream_bufcp, NULL);
1013   if(result) {
1014     result = CURLE_QUIC_CONNECT_ERROR;
1015     goto out;
1016   }
1017 
1018   rc = nghttp3_conn_bind_control_stream(h3->conn, h3->s_ctrl.id);
1019   if(rc) {
1020     result = CURLE_QUIC_CONNECT_ERROR;
1021     goto out;
1022   }
1023   rc = nghttp3_conn_bind_qpack_streams(h3->conn, h3->s_qpack_enc.id,
1024                                        h3->s_qpack_dec.id);
1025   if(rc) {
1026     result = CURLE_QUIC_CONNECT_ERROR;
1027     goto out;
1028   }
1029 
1030   result = CURLE_OK;
1031 out:
1032   return result;
1033 }
1034 
cf_osslq_ctx_start(struct Curl_cfilter * cf,struct Curl_easy * data)1035 static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
1036                                    struct Curl_easy *data)
1037 {
1038   struct cf_osslq_ctx *ctx = cf->ctx;
1039   CURLcode result;
1040   int rv;
1041   const struct Curl_sockaddr_ex *peer_addr = NULL;
1042   int peer_port;
1043   BIO *bio = NULL;
1044   BIO_ADDR *baddr = NULL;
1045 
1046   Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
1047                   H3_STREAM_POOL_SPARES);
1048   result = Curl_ssl_peer_init(&ctx->peer, cf);
1049   if(result)
1050     goto out;
1051 
1052 #define H3_ALPN "\x2h3"
1053   result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
1054                                H3_ALPN, sizeof(H3_ALPN) - 1,
1055                                NULL, NULL);
1056   if(result)
1057     goto out;
1058 
1059   result = vquic_ctx_init(&ctx->q);
1060   if(result)
1061     goto out;
1062 
1063   result = CURLE_QUIC_CONNECT_ERROR;
1064   Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
1065                       &peer_addr, NULL, &peer_port, NULL, NULL);
1066   if(!peer_addr)
1067     goto out;
1068 
1069   ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
1070   rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
1071                    &ctx->q.local_addrlen);
1072   if(rv == -1)
1073     goto out;
1074 
1075   result = make_bio_addr(&baddr, peer_addr);
1076   if(result) {
1077     failf(data, "error creating BIO_ADDR from sockaddr");
1078     goto out;
1079   }
1080 
1081   bio = BIO_new_dgram(ctx->q.sockfd, BIO_NOCLOSE);
1082   if(!bio) {
1083     result = CURLE_OUT_OF_MEMORY;
1084     goto out;
1085   }
1086 
1087   if(!SSL_set1_initial_peer_addr(ctx->tls.ssl, baddr)) {
1088     failf(data, "failed to set the initial peer address");
1089     result = CURLE_FAILED_INIT;
1090     goto out;
1091   }
1092   if(!SSL_set_blocking_mode(ctx->tls.ssl, 0)) {
1093     failf(data, "failed to turn off blocking mode");
1094     result = CURLE_FAILED_INIT;
1095     goto out;
1096   }
1097 
1098   SSL_set_bio(ctx->tls.ssl, bio, bio);
1099   bio = NULL;
1100   SSL_set_connect_state(ctx->tls.ssl);
1101   SSL_set_incoming_stream_policy(ctx->tls.ssl,
1102                                  SSL_INCOMING_STREAM_POLICY_ACCEPT, 0);
1103   /* setup the H3 things on top of the QUIC connection */
1104   result = cf_osslq_h3conn_init(ctx, ctx->tls.ssl, cf);
1105 
1106 out:
1107   if(bio)
1108     BIO_free(bio);
1109   if(baddr)
1110     BIO_ADDR_free(baddr);
1111   CURL_TRC_CF(data, cf, "QUIC tls init -> %d", result);
1112   return result;
1113 }
1114 
1115 struct h3_quic_recv_ctx {
1116   struct Curl_cfilter *cf;
1117   struct Curl_easy *data;
1118   struct cf_osslq_stream *s;
1119 };
1120 
h3_quic_recv(void * reader_ctx,unsigned char * buf,size_t len,CURLcode * err)1121 static ssize_t h3_quic_recv(void *reader_ctx,
1122                             unsigned char *buf, size_t len,
1123                             CURLcode *err)
1124 {
1125   struct h3_quic_recv_ctx *x = reader_ctx;
1126   size_t nread;
1127   int rv;
1128 
1129   *err = CURLE_OK;
1130   rv = SSL_read_ex(x->s->ssl, buf, len, &nread);
1131   if(rv <= 0) {
1132     int detail = SSL_get_error(x->s->ssl, rv);
1133     if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) {
1134       *err = CURLE_AGAIN;
1135       return -1;
1136     }
1137     else if(detail == SSL_ERROR_ZERO_RETURN) {
1138       CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> EOS",
1139                   x->s->id);
1140       x->s->recvd_eos = TRUE;
1141       return 0;
1142     }
1143     else if(SSL_get_stream_read_state(x->s->ssl) ==
1144             SSL_STREAM_STATE_RESET_REMOTE) {
1145       uint64_t app_error_code = NGHTTP3_H3_NO_ERROR;
1146       SSL_get_stream_read_error_code(x->s->ssl, &app_error_code);
1147       CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> RESET, "
1148                   "rv=%d, app_err=%" PRIu64,
1149                    x->s->id, rv, app_error_code);
1150       if(app_error_code != NGHTTP3_H3_NO_ERROR) {
1151         x->s->reset = TRUE;
1152       }
1153       x->s->recvd_eos = TRUE;
1154       return 0;
1155     }
1156     else {
1157       *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
1158       return -1;
1159     }
1160   }
1161   else {
1162     /* CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> %zu bytes",
1163                 x->s->id, nread); */
1164   }
1165   return (ssize_t)nread;
1166 }
1167 
cf_osslq_stream_recv(struct cf_osslq_stream * s,struct Curl_cfilter * cf,struct Curl_easy * data)1168 static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
1169                                      struct Curl_cfilter *cf,
1170                                      struct Curl_easy *data)
1171 {
1172   struct cf_osslq_ctx *ctx = cf->ctx;
1173   CURLcode result = CURLE_OK;
1174   ssize_t nread;
1175   struct h3_quic_recv_ctx x;
1176   int rv, eagain = FALSE;
1177   size_t total_recv_len = 0;
1178 
1179   DEBUGASSERT(s);
1180   if(s->closed)
1181     return CURLE_OK;
1182 
1183   x.cf = cf;
1184   x.data = data;
1185   x.s = s;
1186   while(s->ssl && !s->closed && !eagain &&
1187         (total_recv_len < H3_STREAM_CHUNK_SIZE)) {
1188     if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) {
1189       while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) {
1190         nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result);
1191         if(nread < 0) {
1192           if(result != CURLE_AGAIN)
1193             goto out;
1194           result = CURLE_OK;
1195           eagain = TRUE;
1196         }
1197       }
1198     }
1199 
1200     /* Forward what we have to nghttp3 */
1201     if(!Curl_bufq_is_empty(&s->recvbuf)) {
1202       const unsigned char *buf;
1203       size_t blen;
1204 
1205       while(Curl_bufq_peek(&s->recvbuf, &buf, &blen)) {
1206         nread = nghttp3_conn_read_stream(ctx->h3.conn, s->id,
1207                                          buf, blen, 0);
1208         CURL_TRC_CF(data, cf, "[%" PRId64 "] forward %zu bytes "
1209                     "to nghttp3 -> %zd", s->id, blen, nread);
1210         if(nread < 0) {
1211           failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s",
1212                 blen, nghttp3_strerror((int)nread));
1213           result = CURLE_RECV_ERROR;
1214           goto out;
1215         }
1216         /* success, `nread` is the flow for QUIC to count as "consumed",
1217          * not sure how that will work with OpenSSL. Anyways, without error,
1218          * all data that we passed is not owned by nghttp3. */
1219         Curl_bufq_skip(&s->recvbuf, blen);
1220         total_recv_len += blen;
1221       }
1222     }
1223 
1224     /* When we forwarded everything, handle RESET/EOS */
1225     if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) {
1226       result = CURLE_OK;
1227       if(s->reset) {
1228         uint64_t app_error;
1229         if(!SSL_get_stream_read_error_code(s->ssl, &app_error)) {
1230           failf(data, "SSL_get_stream_read_error_code returned error");
1231           result = CURLE_RECV_ERROR;
1232           goto out;
1233         }
1234         rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id, app_error);
1235         s->closed = TRUE;
1236         if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1237           failf(data, "nghttp3_conn_close_stream returned error: %s",
1238                 nghttp3_strerror(rv));
1239           result = CURLE_RECV_ERROR;
1240           goto out;
1241         }
1242       }
1243       else if(s->recvd_eos) {
1244         rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id,
1245                                        NGHTTP3_H3_NO_ERROR);
1246         s->closed = TRUE;
1247         CURL_TRC_CF(data, cf, "[%" PRId64 "] close nghttp3 stream -> %d",
1248                     s->id, rv);
1249         if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1250           failf(data, "nghttp3_conn_close_stream returned error: %s",
1251                 nghttp3_strerror(rv));
1252           result = CURLE_RECV_ERROR;
1253           goto out;
1254         }
1255       }
1256     }
1257   }
1258 out:
1259   if(result)
1260     CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_osslq_stream_recv -> %d",
1261                 s->id, result);
1262   return result;
1263 }
1264 
cf_progress_ingress(struct Curl_cfilter * cf,struct Curl_easy * data)1265 static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
1266                                     struct Curl_easy *data)
1267 {
1268   struct cf_osslq_ctx *ctx = cf->ctx;
1269   CURLcode result = CURLE_OK;
1270 
1271   if(!ctx->tls.ssl)
1272     goto out;
1273 
1274   ERR_clear_error();
1275 
1276   /* 1. Check for new incoming streams */
1277   while(1) {
1278     SSL *snew = SSL_accept_stream(ctx->tls.ssl, SSL_ACCEPT_STREAM_NO_BLOCK);
1279     if(!snew)
1280       break;
1281 
1282     (void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data);
1283   }
1284 
1285   if(!SSL_handle_events(ctx->tls.ssl)) {
1286     int detail = SSL_get_error(ctx->tls.ssl, 0);
1287     result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR);
1288   }
1289 
1290   if(ctx->h3.conn) {
1291     size_t i;
1292     for(i = 0; i < ctx->h3.remote_ctrl_n; ++i) {
1293       result = cf_osslq_stream_recv(&ctx->h3.remote_ctrl[i], cf, data);
1294       if(result)
1295         goto out;
1296     }
1297   }
1298 
1299   if(ctx->h3.conn) {
1300     struct Curl_easy *sdata;
1301     struct h3_stream_ctx *stream;
1302     /* PULL all open streams */
1303     DEBUGASSERT(data->multi);
1304     for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
1305       if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
1306         stream = H3_STREAM_CTX(sdata);
1307         if(stream && !stream->closed &&
1308            !Curl_bufq_is_full(&stream->recvbuf)) {
1309           result = cf_osslq_stream_recv(&stream->s, cf, sdata);
1310           if(result)
1311             goto out;
1312         }
1313       }
1314     }
1315   }
1316 
1317 out:
1318   CURL_TRC_CF(data, cf, "progress_ingress -> %d", result);
1319   return result;
1320 }
1321 
1322 /* Iterate over all streams and check if blocked can be unblocked */
cf_osslq_check_and_unblock(struct Curl_cfilter * cf,struct Curl_easy * data)1323 static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
1324                                            struct Curl_easy *data)
1325 {
1326   struct cf_osslq_ctx *ctx = cf->ctx;
1327   struct Curl_easy *sdata;
1328   struct h3_stream_ctx *stream;
1329 
1330   if(ctx->h3.conn) {
1331     for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
1332       if(sdata->conn == data->conn) {
1333         stream = H3_STREAM_CTX(sdata);
1334         if(stream && stream->s.ssl && stream->s.send_blocked &&
1335            !SSL_want_write(stream->s.ssl)) {
1336           nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
1337           stream->s.send_blocked = FALSE;
1338           h3_drain_stream(cf, sdata);
1339           CURL_TRC_CF(sdata, cf, "unblocked");
1340         }
1341       }
1342     }
1343   }
1344   return CURLE_OK;
1345 }
1346 
h3_send_streams(struct Curl_cfilter * cf,struct Curl_easy * data)1347 static CURLcode h3_send_streams(struct Curl_cfilter *cf,
1348                                 struct Curl_easy *data)
1349 {
1350   struct cf_osslq_ctx *ctx = cf->ctx;
1351   CURLcode result = CURLE_OK;
1352 
1353   if(!ctx->tls.ssl || !ctx->h3.conn)
1354     goto out;
1355 
1356   for(;;) {
1357     struct cf_osslq_stream *s = NULL;
1358     nghttp3_vec vec[16];
1359     nghttp3_ssize n, i;
1360     int64_t stream_id;
1361     size_t written;
1362     int eos, ok, rv;
1363     size_t total_len, acked_len = 0;
1364     bool blocked = FALSE;
1365 
1366     n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos,
1367                                    vec, ARRAYSIZE(vec));
1368     if(n < 0) {
1369       failf(data, "nghttp3_conn_writev_stream returned error: %s",
1370             nghttp3_strerror((int)n));
1371       result = CURLE_SEND_ERROR;
1372       goto out;
1373     }
1374     if(stream_id < 0) {
1375       result = CURLE_OK;
1376       goto out;
1377     }
1378 
1379     /* Get the stream for this data */
1380     s = cf_osslq_get_qstream(cf, data, stream_id);
1381     if(!s) {
1382       failf(data, "nghttp3_conn_writev_stream gave unknown stream %" PRId64,
1383             stream_id);
1384       result = CURLE_SEND_ERROR;
1385       goto out;
1386     }
1387     /* Now write the data to the stream's SSL*, it may not all fit! */
1388     DEBUGASSERT(s->id == stream_id);
1389     for(i = 0, total_len = 0; i < n; ++i) {
1390       total_len += vec[i].len;
1391     }
1392     for(i = 0; (i < n) && !blocked; ++i) {
1393       /* Without stream->s.ssl, we closed that already, so
1394        * pretend the write did succeed. */
1395       written = vec[i].len;
1396       ok = !s->ssl || SSL_write_ex(s->ssl, vec[i].base, vec[i].len,
1397                                    &written);
1398       if(ok) {
1399         /* As OpenSSL buffers the data, we count this as acknowledged
1400          * from nghttp3's point of view */
1401         CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC ok",
1402               s->id, vec[i].len);
1403         acked_len += vec[i].len;
1404       }
1405       else {
1406         int detail = SSL_get_error(s->ssl, 0);
1407         switch(detail) {
1408         case SSL_ERROR_WANT_WRITE:
1409         case SSL_ERROR_WANT_READ:
1410           /* QUIC blocked us from writing more */
1411           CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC blocked",
1412                 s->id, vec[i].len);
1413           written = 0;
1414           nghttp3_conn_block_stream(ctx->h3.conn, s->id);
1415           s->send_blocked = blocked = TRUE;
1416           break;
1417         default:
1418           failf(data, "[%"PRId64"] send %zu bytes to QUIC, SSL error %d",
1419                 s->id, vec[i].len, detail);
1420           result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
1421           goto out;
1422         }
1423       }
1424     }
1425 
1426     if(acked_len > 0 || (eos && !s->send_blocked)) {
1427       /* Since QUIC buffers the data written internally, we can tell
1428        * nghttp3 that it can move forward on it */
1429       rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len);
1430       if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1431         failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
1432               nghttp3_strerror(rv));
1433         result = CURLE_SEND_ERROR;
1434         goto out;
1435       }
1436       rv = nghttp3_conn_add_ack_offset(ctx->h3.conn, s->id, acked_len);
1437       if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1438         failf(data, "nghttp3_conn_add_ack_offset returned error: %s\n",
1439               nghttp3_strerror(rv));
1440         result = CURLE_SEND_ERROR;
1441         goto out;
1442       }
1443       CURL_TRC_CF(data, cf, "[%" PRId64 "] forwarded %zu/%zu h3 bytes "
1444                   "to QUIC, eos=%d", s->id, acked_len, total_len, eos);
1445     }
1446 
1447     if(eos && !s->send_blocked) {
1448       /* wrote everything and H3 indicates end of stream */
1449       CURL_TRC_CF(data, cf, "[%" PRId64 "] closing QUIC stream", s->id);
1450       SSL_stream_conclude(s->ssl, 0);
1451     }
1452   }
1453 
1454 out:
1455   CURL_TRC_CF(data, cf, "h3_send_streams -> %d", result);
1456   return result;
1457 }
1458 
cf_progress_egress(struct Curl_cfilter * cf,struct Curl_easy * data)1459 static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
1460                                    struct Curl_easy *data)
1461 {
1462   struct cf_osslq_ctx *ctx = cf->ctx;
1463   CURLcode result = CURLE_OK;
1464 
1465   if(!ctx->tls.ssl)
1466     goto out;
1467 
1468   ERR_clear_error();
1469   result = h3_send_streams(cf, data);
1470   if(result)
1471     goto out;
1472 
1473   if(!SSL_handle_events(ctx->tls.ssl)) {
1474     int detail = SSL_get_error(ctx->tls.ssl, 0);
1475     result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
1476   }
1477 
1478   result = cf_osslq_check_and_unblock(cf, data);
1479 
1480 out:
1481   CURL_TRC_CF(data, cf, "progress_egress -> %d", result);
1482   return result;
1483 }
1484 
check_and_set_expiry(struct Curl_cfilter * cf,struct Curl_easy * data)1485 static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
1486                                      struct Curl_easy *data)
1487 {
1488   struct cf_osslq_ctx *ctx = cf->ctx;
1489   CURLcode result = CURLE_OK;
1490   struct timeval tv;
1491   timediff_t timeoutms;
1492   int is_infinite = TRUE;
1493 
1494   if(ctx->tls.ssl &&
1495     SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite) &&
1496     !is_infinite) {
1497     timeoutms = curlx_tvtoms(&tv);
1498     /* QUIC want to be called again latest at the returned timeout */
1499     if(timeoutms <= 0) {
1500       result = cf_progress_ingress(cf, data);
1501       if(result)
1502         goto out;
1503       result = cf_progress_egress(cf, data);
1504       if(result)
1505         goto out;
1506       if(SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite)) {
1507         timeoutms = curlx_tvtoms(&tv);
1508       }
1509     }
1510     if(!is_infinite) {
1511       Curl_expire(data, timeoutms, EXPIRE_QUIC);
1512       CURL_TRC_CF(data, cf, "QUIC expiry in %ldms", (long)timeoutms);
1513     }
1514   }
1515 out:
1516   return result;
1517 }
1518 
cf_osslq_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1519 static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
1520                                  struct Curl_easy *data,
1521                                  bool blocking, bool *done)
1522 {
1523   struct cf_osslq_ctx *ctx = cf->ctx;
1524   CURLcode result = CURLE_OK;
1525   struct cf_call_data save;
1526   struct curltime now;
1527   int err;
1528 
1529   if(cf->connected) {
1530     *done = TRUE;
1531     return CURLE_OK;
1532   }
1533 
1534   /* Connect the UDP filter first */
1535   if(!cf->next->connected) {
1536     result = Curl_conn_cf_connect(cf->next, data, blocking, done);
1537     if(result || !*done)
1538       return result;
1539   }
1540 
1541   *done = FALSE;
1542   now = Curl_now();
1543   CF_DATA_SAVE(save, cf, data);
1544 
1545   if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) {
1546     /* Not time yet to attempt the next connect */
1547     CURL_TRC_CF(data, cf, "waiting for reconnect time");
1548     goto out;
1549   }
1550 
1551   if(!ctx->tls.ssl) {
1552     ctx->started_at = now;
1553     result = cf_osslq_ctx_start(cf, data);
1554     if(result)
1555       goto out;
1556   }
1557 
1558   if(!ctx->got_first_byte) {
1559     int readable = SOCKET_READABLE(ctx->q.sockfd, 0);
1560     if(readable > 0 && (readable & CURL_CSELECT_IN)) {
1561       ctx->got_first_byte = TRUE;
1562       ctx->first_byte_at = Curl_now();
1563     }
1564   }
1565 
1566   ERR_clear_error();
1567   err = SSL_do_handshake(ctx->tls.ssl);
1568 
1569   if(err == 1) {
1570     /* connected */
1571     ctx->handshake_at = now;
1572     CURL_TRC_CF(data, cf, "handshake complete after %dms",
1573                (int)Curl_timediff(now, ctx->started_at));
1574     result = cf_osslq_verify_peer(cf, data);
1575     if(!result) {
1576       CURL_TRC_CF(data, cf, "peer verified");
1577       cf->connected = TRUE;
1578       cf->conn->alpn = CURL_HTTP_VERSION_3;
1579       *done = TRUE;
1580       connkeep(cf->conn, "HTTP/3 default");
1581     }
1582   }
1583   else {
1584     int detail = SSL_get_error(ctx->tls.ssl, err);
1585     switch(detail) {
1586     case SSL_ERROR_WANT_READ:
1587       CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV");
1588       result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
1589       goto out;
1590     case SSL_ERROR_WANT_WRITE:
1591       CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND");
1592       result = CURLE_OK;
1593       goto out;
1594 #ifdef SSL_ERROR_WANT_ASYNC
1595     case SSL_ERROR_WANT_ASYNC:
1596       CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC");
1597       result = CURLE_OK;
1598       goto out;
1599 #endif
1600 #ifdef SSL_ERROR_WANT_RETRY_VERIFY
1601     case SSL_ERROR_WANT_RETRY_VERIFY:
1602       result = CURLE_OK;
1603       goto out;
1604 #endif
1605     default:
1606       result = cf_osslq_ssl_err(cf, data, detail, CURLE_COULDNT_CONNECT);
1607       goto out;
1608     }
1609   }
1610 
1611 out:
1612   if(result == CURLE_RECV_ERROR && ctx->tls.ssl && ctx->protocol_shutdown) {
1613     /* When a QUIC server instance is shutting down, it may send us a
1614      * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
1615      * state. The CONNECT may work in the near future again. Indicate
1616      * that as a "weird" reply. */
1617     result = CURLE_WEIRD_SERVER_REPLY;
1618   }
1619 
1620 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1621   if(result) {
1622     const char *r_ip = NULL;
1623     int r_port = 0;
1624 
1625     Curl_cf_socket_peek(cf->next, data, NULL, NULL,
1626                         &r_ip, &r_port, NULL, NULL);
1627     infof(data, "QUIC connect to %s port %u failed: %s",
1628           r_ip, r_port, curl_easy_strerror(result));
1629   }
1630 #endif
1631   if(!result)
1632     result = check_and_set_expiry(cf, data);
1633   if(result || *done)
1634     CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
1635   CF_DATA_RESTORE(cf, save);
1636   return result;
1637 }
1638 
h3_stream_open(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1639 static ssize_t h3_stream_open(struct Curl_cfilter *cf,
1640                               struct Curl_easy *data,
1641                               const void *buf, size_t len,
1642                               CURLcode *err)
1643 {
1644   struct cf_osslq_ctx *ctx = cf->ctx;
1645   struct h3_stream_ctx *stream = NULL;
1646   struct dynhds h2_headers;
1647   size_t nheader;
1648   nghttp3_nv *nva = NULL;
1649   int rc = 0;
1650   unsigned int i;
1651   ssize_t nwritten = -1;
1652   nghttp3_data_reader reader;
1653   nghttp3_data_reader *preader = NULL;
1654 
1655   Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
1656 
1657   *err = h3_data_setup(cf, data);
1658   if(*err)
1659     goto out;
1660   stream = H3_STREAM_CTX(data);
1661   DEBUGASSERT(stream);
1662   if(!stream) {
1663     *err = CURLE_FAILED_INIT;
1664     goto out;
1665   }
1666 
1667   nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
1668   if(nwritten < 0)
1669     goto out;
1670   if(!stream->h1.done) {
1671     /* need more data */
1672     goto out;
1673   }
1674   DEBUGASSERT(stream->h1.req);
1675 
1676   *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
1677   if(*err) {
1678     nwritten = -1;
1679     goto out;
1680   }
1681   /* no longer needed */
1682   Curl_h1_req_parse_free(&stream->h1);
1683 
1684   nheader = Curl_dynhds_count(&h2_headers);
1685   nva = malloc(sizeof(nghttp3_nv) * nheader);
1686   if(!nva) {
1687     *err = CURLE_OUT_OF_MEMORY;
1688     nwritten = -1;
1689     goto out;
1690   }
1691 
1692   for(i = 0; i < nheader; ++i) {
1693     struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
1694     nva[i].name = (unsigned char *)e->name;
1695     nva[i].namelen = e->namelen;
1696     nva[i].value = (unsigned char *)e->value;
1697     nva[i].valuelen = e->valuelen;
1698     nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1699   }
1700 
1701   DEBUGASSERT(stream->s.id == -1);
1702   *err = cf_osslq_stream_open(&stream->s, ctx->tls.ssl, 0,
1703                               &ctx->stream_bufcp, data);
1704   if(*err) {
1705     failf(data, "can't get bidi streams");
1706     *err = CURLE_SEND_ERROR;
1707     goto out;
1708   }
1709 
1710   switch(data->state.httpreq) {
1711   case HTTPREQ_POST:
1712   case HTTPREQ_POST_FORM:
1713   case HTTPREQ_POST_MIME:
1714   case HTTPREQ_PUT:
1715     /* known request body size or -1 */
1716     if(data->state.infilesize != -1)
1717       stream->upload_left = data->state.infilesize;
1718     else
1719       /* data sending without specifying the data amount up front */
1720       stream->upload_left = -1; /* unknown */
1721     break;
1722   default:
1723     /* there is not request body */
1724     stream->upload_left = 0; /* no request body */
1725     break;
1726   }
1727 
1728   stream->send_closed = (stream->upload_left == 0);
1729   if(!stream->send_closed) {
1730     reader.read_data = cb_h3_read_req_body;
1731     preader = &reader;
1732   }
1733 
1734   rc = nghttp3_conn_submit_request(ctx->h3.conn, stream->s.id,
1735                                    nva, nheader, preader, data);
1736   if(rc) {
1737     switch(rc) {
1738     case NGHTTP3_ERR_CONN_CLOSING:
1739       CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, "
1740                   "connection is closing", stream->s.id);
1741       break;
1742     default:
1743       CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)",
1744                   stream->s.id, rc, nghttp3_strerror(rc));
1745       break;
1746     }
1747     *err = CURLE_SEND_ERROR;
1748     nwritten = -1;
1749     goto out;
1750   }
1751 
1752   if(Curl_trc_is_verbose(data)) {
1753     infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
1754           stream->s.id, data->state.url);
1755     for(i = 0; i < nheader; ++i) {
1756       infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->s.id,
1757             (int)nva[i].namelen, nva[i].name,
1758             (int)nva[i].valuelen, nva[i].value);
1759     }
1760   }
1761 
1762 out:
1763   free(nva);
1764   Curl_dynhds_free(&h2_headers);
1765   return nwritten;
1766 }
1767 
cf_osslq_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1768 static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1769                              const void *buf, size_t len, CURLcode *err)
1770 {
1771   struct cf_osslq_ctx *ctx = cf->ctx;
1772   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1773   struct cf_call_data save;
1774   ssize_t nwritten;
1775   CURLcode result;
1776 
1777   CF_DATA_SAVE(save, cf, data);
1778   DEBUGASSERT(cf->connected);
1779   DEBUGASSERT(ctx->tls.ssl);
1780   DEBUGASSERT(ctx->h3.conn);
1781   *err = CURLE_OK;
1782 
1783   result = cf_progress_ingress(cf, data);
1784   if(result) {
1785     *err = result;
1786     nwritten = -1;
1787     goto out;
1788   }
1789 
1790   result = cf_progress_egress(cf, data);
1791   if(result) {
1792     *err = result;
1793     nwritten = -1;
1794     goto out;
1795   }
1796 
1797   if(!stream || stream->s.id < 0) {
1798     nwritten = h3_stream_open(cf, data, buf, len, err);
1799     if(nwritten < 0) {
1800       CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
1801       goto out;
1802     }
1803     stream = H3_STREAM_CTX(data);
1804   }
1805   else if(stream->upload_blocked_len) {
1806     /* the data in `buf` has already been submitted or added to the
1807      * buffers, but have been EAGAINed on the last invocation. */
1808     DEBUGASSERT(len >= stream->upload_blocked_len);
1809     if(len < stream->upload_blocked_len) {
1810       /* Did we get called again with a smaller `len`? This should not
1811        * happen. We are not prepared to handle that. */
1812       failf(data, "HTTP/3 send again with decreased length");
1813       *err = CURLE_HTTP3;
1814       nwritten = -1;
1815       goto out;
1816     }
1817     nwritten = (ssize_t)stream->upload_blocked_len;
1818     stream->upload_blocked_len = 0;
1819   }
1820   else if(stream->closed) {
1821     if(stream->resp_hds_complete) {
1822       /* Server decided to close the stream after having sent us a final
1823        * response. This is valid if it is not interested in the request
1824        * body. This happens on 30x or 40x responses.
1825        * We silently discard the data sent, since this is not a transport
1826        * error situation. */
1827       CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
1828                   "on closed stream with response", stream->s.id);
1829       *err = CURLE_OK;
1830       nwritten = (ssize_t)len;
1831       goto out;
1832     }
1833     CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
1834                 "-> stream closed", stream->s.id, len);
1835     *err = CURLE_HTTP3;
1836     nwritten = -1;
1837     goto out;
1838   }
1839   else {
1840     nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
1841     CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
1842                 "sendbuf(len=%zu) -> %zd, %d",
1843                 stream->s.id, len, nwritten, *err);
1844     if(nwritten < 0) {
1845       goto out;
1846     }
1847 
1848     (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
1849   }
1850 
1851   result = cf_progress_egress(cf, data);
1852   if(result) {
1853     *err = result;
1854     nwritten = -1;
1855   }
1856 
1857   if(stream && nwritten > 0 && stream->sendbuf_len_in_flight) {
1858     /* We have unacknowledged DATA and cannot report success to our
1859      * caller. Instead we EAGAIN and remember how much we have already
1860      * "written" into our various internal connection buffers. */
1861     stream->upload_blocked_len = nwritten;
1862     CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), "
1863                 "%zu bytes in flight -> EGAIN", stream->s.id, len,
1864                 stream->sendbuf_len_in_flight);
1865     *err = CURLE_AGAIN;
1866     nwritten = -1;
1867   }
1868 
1869 out:
1870   result = check_and_set_expiry(cf, data);
1871   CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
1872               stream? stream->s.id : -1, len, nwritten, *err);
1873   CF_DATA_RESTORE(cf, save);
1874   return nwritten;
1875 }
1876 
recv_closed_stream(struct Curl_cfilter * cf,struct Curl_easy * data,struct h3_stream_ctx * stream,CURLcode * err)1877 static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
1878                                   struct Curl_easy *data,
1879                                   struct h3_stream_ctx *stream,
1880                                   CURLcode *err)
1881 {
1882   ssize_t nread = -1;
1883 
1884   (void)cf;
1885   if(stream->reset) {
1886     failf(data,
1887           "HTTP/3 stream %" PRId64 " reset by server", stream->s.id);
1888     *err = stream->resp_hds_complete? CURLE_PARTIAL_FILE : CURLE_HTTP3;
1889     goto out;
1890   }
1891   else if(!stream->resp_hds_complete) {
1892     failf(data,
1893           "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
1894           " all response header fields, treated as error",
1895           stream->s.id);
1896     *err = CURLE_HTTP3;
1897     goto out;
1898   }
1899   *err = CURLE_OK;
1900   nread = 0;
1901 
1902 out:
1903   return nread;
1904 }
1905 
cf_osslq_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)1906 static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1907                              char *buf, size_t len, CURLcode *err)
1908 {
1909   struct cf_osslq_ctx *ctx = cf->ctx;
1910   struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1911   ssize_t nread = -1;
1912   struct cf_call_data save;
1913   CURLcode result;
1914 
1915   (void)ctx;
1916   CF_DATA_SAVE(save, cf, data);
1917   DEBUGASSERT(cf->connected);
1918   DEBUGASSERT(ctx);
1919   DEBUGASSERT(ctx->tls.ssl);
1920   DEBUGASSERT(ctx->h3.conn);
1921   *err = CURLE_OK;
1922 
1923   if(!stream) {
1924     *err = CURLE_RECV_ERROR;
1925     goto out;
1926   }
1927 
1928   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
1929     nread = Curl_bufq_read(&stream->recvbuf,
1930                            (unsigned char *)buf, len, err);
1931     if(nread < 0) {
1932       CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
1933                   "-> %zd, %d", stream->s.id, len, nread, *err);
1934       goto out;
1935     }
1936   }
1937 
1938   result = cf_progress_ingress(cf, data);
1939   if(result) {
1940     *err = result;
1941     nread = -1;
1942     goto out;
1943   }
1944 
1945   /* recvbuf had nothing before, maybe after progressing ingress? */
1946   if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
1947     nread = Curl_bufq_read(&stream->recvbuf,
1948                            (unsigned char *)buf, len, err);
1949     if(nread < 0) {
1950       CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
1951                   "-> %zd, %d", stream->s.id, len, nread, *err);
1952       goto out;
1953     }
1954   }
1955 
1956   if(nread > 0) {
1957     h3_drain_stream(cf, data);
1958   }
1959   else {
1960     if(stream->closed) {
1961       nread = recv_closed_stream(cf, data, stream, err);
1962       goto out;
1963     }
1964     *err = CURLE_AGAIN;
1965     nread = -1;
1966   }
1967 
1968 out:
1969   if(cf_progress_egress(cf, data)) {
1970     *err = CURLE_SEND_ERROR;
1971     nread = -1;
1972   }
1973   else {
1974     CURLcode result2 = check_and_set_expiry(cf, data);
1975     if(result2) {
1976       *err = result2;
1977       nread = -1;
1978     }
1979   }
1980   CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d",
1981               stream? stream->s.id : -1, len, nread, *err);
1982   CF_DATA_RESTORE(cf, save);
1983   return nread;
1984 }
1985 
1986 /*
1987  * Called from transfer.c:data_pending to know if we should keep looping
1988  * to receive more data from the connection.
1989  */
cf_osslq_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1990 static bool cf_osslq_data_pending(struct Curl_cfilter *cf,
1991                                   const struct Curl_easy *data)
1992 {
1993   const struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1994   (void)cf;
1995   return stream && !Curl_bufq_is_empty(&stream->recvbuf);
1996 }
1997 
cf_osslq_data_event(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1998 static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
1999                                     struct Curl_easy *data,
2000                                     int event, int arg1, void *arg2)
2001 {
2002   struct cf_osslq_ctx *ctx = cf->ctx;
2003   CURLcode result = CURLE_OK;
2004   struct cf_call_data save;
2005 
2006   CF_DATA_SAVE(save, cf, data);
2007   (void)arg1;
2008   (void)arg2;
2009   switch(event) {
2010   case CF_CTRL_DATA_SETUP:
2011     break;
2012   case CF_CTRL_DATA_PAUSE:
2013     result = h3_data_pause(cf, data, (arg1 != 0));
2014     break;
2015   case CF_CTRL_DATA_DETACH:
2016     h3_data_done(cf, data);
2017     break;
2018   case CF_CTRL_DATA_DONE:
2019     h3_data_done(cf, data);
2020     break;
2021   case CF_CTRL_DATA_DONE_SEND: {
2022     struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
2023     if(stream && !stream->send_closed) {
2024       stream->send_closed = TRUE;
2025       stream->upload_left = Curl_bufq_len(&stream->sendbuf);
2026       (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
2027     }
2028     break;
2029   }
2030   case CF_CTRL_DATA_IDLE: {
2031     struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
2032     CURL_TRC_CF(data, cf, "data idle");
2033     if(stream && !stream->closed) {
2034       result = check_and_set_expiry(cf, data);
2035     }
2036     break;
2037   }
2038   default:
2039     break;
2040   }
2041   CF_DATA_RESTORE(cf, save);
2042   return result;
2043 }
2044 
cf_osslq_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)2045 static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
2046                                    struct Curl_easy *data,
2047                                    bool *input_pending)
2048 {
2049   struct cf_osslq_ctx *ctx = cf->ctx;
2050   bool alive = FALSE;
2051   struct cf_call_data save;
2052 
2053   CF_DATA_SAVE(save, cf, data);
2054   *input_pending = FALSE;
2055   if(!ctx->tls.ssl)
2056     goto out;
2057 
2058   /* TODO: how to check negotiated connection idle time? */
2059 
2060   if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
2061     goto out;
2062 
2063   alive = TRUE;
2064   if(*input_pending) {
2065     CURLcode result;
2066     /* This happens before we've sent off a request and the connection is
2067        not in use by any other transfer, there shouldn't be any data here,
2068        only "protocol frames" */
2069     *input_pending = FALSE;
2070     result = cf_progress_ingress(cf, data);
2071     CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
2072     alive = result? FALSE : TRUE;
2073   }
2074 
2075 out:
2076   CF_DATA_RESTORE(cf, save);
2077   return alive;
2078 }
2079 
cf_osslq_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)2080 static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
2081                                     struct Curl_easy *data,
2082                                     struct easy_pollset *ps)
2083 {
2084   struct cf_osslq_ctx *ctx = cf->ctx;
2085 
2086   if(!ctx->tls.ssl) {
2087     /* NOP */
2088   }
2089   else if(!cf->connected) {
2090     /* during handshake, transfer has not started yet. we always
2091      * add our socket for polling if SSL wants to send/recv */
2092     Curl_pollset_set(data, ps, ctx->q.sockfd,
2093                      SSL_net_read_desired(ctx->tls.ssl),
2094                      SSL_net_write_desired(ctx->tls.ssl));
2095   }
2096   else {
2097     /* once connected, we only modify the socket if it is present.
2098      * this avoids adding it for paused transfers. */
2099     bool want_recv, want_send;
2100     Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
2101     if(want_recv || want_send) {
2102       Curl_pollset_set(data, ps, ctx->q.sockfd,
2103                        SSL_net_read_desired(ctx->tls.ssl),
2104                        SSL_net_write_desired(ctx->tls.ssl));
2105     }
2106   }
2107 }
2108 
cf_osslq_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)2109 static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
2110                                struct Curl_easy *data,
2111                                int query, int *pres1, void *pres2)
2112 {
2113   struct cf_osslq_ctx *ctx = cf->ctx;
2114   struct cf_call_data save;
2115 
2116   switch(query) {
2117   case CF_QUERY_MAX_CONCURRENT: {
2118     /* TODO: how to get this? */
2119     CF_DATA_SAVE(save, cf, data);
2120     *pres1 = 100;
2121     CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
2122     CF_DATA_RESTORE(cf, save);
2123     return CURLE_OK;
2124   }
2125   case CF_QUERY_CONNECT_REPLY_MS:
2126     if(ctx->got_first_byte) {
2127       timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
2128       *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
2129     }
2130     else
2131       *pres1 = -1;
2132     return CURLE_OK;
2133   case CF_QUERY_TIMER_CONNECT: {
2134     struct curltime *when = pres2;
2135     if(ctx->got_first_byte)
2136       *when = ctx->first_byte_at;
2137     return CURLE_OK;
2138   }
2139   case CF_QUERY_TIMER_APPCONNECT: {
2140     struct curltime *when = pres2;
2141     if(cf->connected)
2142       *when = ctx->handshake_at;
2143     return CURLE_OK;
2144   }
2145   default:
2146     break;
2147   }
2148   return cf->next?
2149     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
2150     CURLE_UNKNOWN_OPTION;
2151 }
2152 
2153 struct Curl_cftype Curl_cft_http3 = {
2154   "HTTP/3",
2155   CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
2156   0,
2157   cf_osslq_destroy,
2158   cf_osslq_connect,
2159   cf_osslq_close,
2160   Curl_cf_def_get_host,
2161   cf_osslq_adjust_pollset,
2162   cf_osslq_data_pending,
2163   cf_osslq_send,
2164   cf_osslq_recv,
2165   cf_osslq_data_event,
2166   cf_osslq_conn_is_alive,
2167   Curl_cf_def_conn_keep_alive,
2168   cf_osslq_query,
2169 };
2170 
Curl_cf_osslq_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai)2171 CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
2172                               struct Curl_easy *data,
2173                               struct connectdata *conn,
2174                               const struct Curl_addrinfo *ai)
2175 {
2176   struct cf_osslq_ctx *ctx = NULL;
2177   struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
2178   CURLcode result;
2179 
2180   (void)data;
2181   ctx = calloc(1, sizeof(*ctx));
2182   if(!ctx) {
2183     result = CURLE_OUT_OF_MEMORY;
2184     goto out;
2185   }
2186   cf_osslq_ctx_clear(ctx);
2187 
2188   result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
2189   if(result)
2190     goto out;
2191 
2192   result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
2193   if(result)
2194     goto out;
2195 
2196   cf->conn = conn;
2197   udp_cf->conn = cf->conn;
2198   udp_cf->sockindex = cf->sockindex;
2199   cf->next = udp_cf;
2200 
2201 out:
2202   *pcf = (!result)? cf : NULL;
2203   if(result) {
2204     if(udp_cf)
2205       Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
2206     Curl_safefree(cf);
2207     Curl_safefree(ctx);
2208   }
2209   return result;
2210 }
2211 
Curl_conn_is_osslq(const struct Curl_easy * data,const struct connectdata * conn,int sockindex)2212 bool Curl_conn_is_osslq(const struct Curl_easy *data,
2213                         const struct connectdata *conn,
2214                         int sockindex)
2215 {
2216   struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
2217 
2218   (void)data;
2219   for(; cf; cf = cf->next) {
2220     if(cf->cft == &Curl_cft_http3)
2221       return TRUE;
2222     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
2223       return FALSE;
2224   }
2225   return FALSE;
2226 }
2227 
2228 /*
2229  * Store ngtcp2 version info in this buffer.
2230  */
Curl_osslq_ver(char * p,size_t len)2231 void Curl_osslq_ver(char *p, size_t len)
2232 {
2233   const nghttp3_info *ht3 = nghttp3_version(0);
2234   (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str);
2235 }
2236 
2237 #endif /* USE_OPENSSL_QUIC && USE_NGHTTP3 */
2238