]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
quic: remove conn->data use
authorDaniel Stenberg <daniel@haxx.se>
Tue, 19 Jan 2021 08:48:40 +0000 (09:48 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 19 Jan 2021 15:56:35 +0000 (16:56 +0100)
Closes #6485

lib/connect.c
lib/quic.h
lib/transfer.c
lib/vquic/ngtcp2.c
lib/vquic/quiche.c

index 712fc8a0d26818d9c7e7291b59bd12b6c43da120..81ae006e86cdfb63514b66f8caa55a8c0eb7e403 100644 (file)
@@ -887,7 +887,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
     error = 0;
 #ifdef ENABLE_QUIC
     if(conn->transport == TRNSPRT_QUIC) {
-      result = Curl_quic_is_connected(conn, i, connected);
+      result = Curl_quic_is_connected(data, conn, i, connected);
       if(!result && *connected) {
         /* use this socket from now on */
         conn->sock[sockindex] = conn->tempsock[i];
@@ -1024,8 +1024,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
           hostname, conn->port,
           Curl_strerror(error, buffer, sizeof(buffer)));
 
-    Curl_quic_disconnect(conn, 0);
-    Curl_quic_disconnect(conn, 1);
+    Curl_quic_disconnect(data, conn, 0);
+    Curl_quic_disconnect(data, conn, 1);
 
 #ifdef WSAETIMEDOUT
     if(WSAETIMEDOUT == data->state.os_errno)
@@ -1280,7 +1280,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
     else if(conn->transport == TRNSPRT_QUIC) {
       /* pass in 'sockfd' separately since it hasn't been put into the
          tempsock array at this point */
-      result = Curl_quic_connect(conn, sockfd, tempindex,
+      result = Curl_quic_connect(data, conn, sockfd, tempindex,
                                  &addr.sa_addr, addr.addrlen);
       if(result)
         error = SOCKERRNO;
index f04662e8206a4a9671f31af7382630a3c1fb75b8..947f13edcf7a46743a1cf71f0ad8fcfde569a55f 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
 #include "urldata.h"
 
 /* functions provided by the specific backends */
-CURLcode Curl_quic_connect(struct connectdata *conn,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr,
                            socklen_t addrlen);
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 int sockindex,
                                 bool *connected);
 int Curl_quic_ver(char *p, size_t len);
-CURLcode Curl_quic_done_sending(struct connectdata *conn);
+CURLcode Curl_quic_done_sending(struct Curl_easy *data);
 void Curl_quic_done(struct Curl_easy *data, bool premature);
 bool Curl_quic_data_pending(const struct Curl_easy *data);
-void Curl_quic_disconnect(struct connectdata *conn, int tempindex);
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn, int tempindex);
 
 #else /* ENABLE_QUIC */
 #define Curl_quic_done_sending(x)
 #define Curl_quic_done(x,y)
 #define Curl_quic_data_pending(x)
-#define Curl_quic_disconnect(x,y)
+#define Curl_quic_disconnect(x,y,z)
 #endif /* !ENABLE_QUIC */
 
 #endif /* HEADER_CURL_QUIC_H */
index 59b351519bedb296d14897e533c15b329b3e9fc4..ce5acfbc934b0c1672f4de41acbfd87c14dc638f 100644 (file)
@@ -911,7 +911,7 @@ CURLcode Curl_done_sending(struct Curl_easy *data,
 
   /* These functions should be moved into the handler struct! */
   Curl_http2_done_sending(data, conn);
-  Curl_quic_done_sending(conn);
+  Curl_quic_done_sending(data);
 
   if(conn->bits.rewindaftersend) {
     CURLcode result = Curl_readrewind(conn);
index e1882dafc548e1691e64235132527cd82e6a189e..e87f8f4ba4f2ff7974e4aa275ba2d1f6c70b8de5 100644 (file)
@@ -87,7 +87,7 @@ struct h3out {
   "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1"
 #endif
 
-static CURLcode ng_process_ingress(struct connectdata *conn,
+static CURLcode ng_process_ingress(struct Curl_easy *data,
                                    curl_socket_t sockfd,
                                    struct quicsocket *qs);
 static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd,
@@ -556,10 +556,8 @@ cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
 
 static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
 {
-  struct quicsocket *qs = (struct quicsocket *)user_data;
+  (void)user_data;
   (void)tconn;
-  infof(qs->conn->data, "QUIC handshake is completed\n");
-
   return 0;
 }
 
@@ -587,8 +585,6 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
   nconsumed =
     nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
   if(nconsumed < 0) {
-    failf(qs->conn->data, "nghttp3_conn_read_stream returned error: %s",
-          nghttp3_strerror((int)nconsumed));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -616,8 +612,6 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
 
   rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_add_ack_offset returned error: %s",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -637,8 +631,6 @@ static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
   rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
                                  app_error_code);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_close_stream returned error: %s",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -658,8 +650,6 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
 
   rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -689,8 +679,6 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
 
   rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -701,16 +689,16 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
                                     uint8_t *token, size_t cidlen,
                                     void *user_data)
 {
-  struct quicsocket *qs = (struct quicsocket *)user_data;
   CURLcode result;
   (void)tconn;
+  (void)user_data;
 
-  result = Curl_rand(qs->conn->data, cid->data, cidlen);
+  result = Curl_rand(NULL, cid->data, cidlen);
   if(result)
     return NGTCP2_ERR_CALLBACK_FAILURE;
   cid->datalen = cidlen;
 
-  result = Curl_rand(qs->conn->data, token, NGTCP2_STATELESS_RESET_TOKENLEN);
+  result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
   if(result)
     return NGTCP2_ERR_CALLBACK_FAILURE;
 
@@ -755,7 +743,8 @@ static ngtcp2_callbacks ng_callbacks = {
 /*
  * Might be called twice for happy eyeballs.
  */
-CURLcode Curl_quic_connect(struct connectdata *conn,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr,
@@ -765,14 +754,13 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
   int rv;
   CURLcode result;
   ngtcp2_path path; /* TODO: this must be initialized properly */
-  struct Curl_easy *data = conn->data;
   struct quicsocket *qs = &conn->hequic[sockindex];
   char ipbuf[40];
   long port;
   int qfd;
 
   if(qs->conn)
-    Curl_quic_disconnect(conn, sockindex);
+    Curl_quic_disconnect(data, conn, sockindex);
   qs->conn = conn;
 
   /* extract the used address as a string */
@@ -892,9 +880,11 @@ static void qs_disconnect(struct quicsocket *qs)
 #endif
 }
 
-void Curl_quic_disconnect(struct connectdata *conn,
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int tempindex)
 {
+  (void)data;
   if(conn->transport == TRNSPRT_QUIC)
     qs_disconnect(&conn->hequic[tempindex]);
 }
@@ -904,9 +894,8 @@ static CURLcode ng_disconnect(struct Curl_easy *data,
                               bool dead_connection)
 {
   (void)dead_connection;
-  (void)data;
-  Curl_quic_disconnect(conn, 0);
-  Curl_quic_disconnect(conn, 1);
+  Curl_quic_disconnect(data, conn, 0);
+  Curl_quic_disconnect(data, conn, 1);
   return CURLE_OK;
 }
 
@@ -1161,7 +1150,6 @@ static int init_ngh3_conn(struct quicsocket *qs)
   int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
 
   if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
-    failf(qs->conn->data, "too few available QUIC streams");
     return CURLE_QUIC_CONNECT_ERROR;
   }
 
@@ -1257,7 +1245,7 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data,
      as possible to the receive buffer before receiving more */
   drain_overflow_buffer(stream);
 
-  if(ng_process_ingress(conn, sockfd, qs)) {
+  if(ng_process_ingress(data, sockfd, qs)) {
     *curlcode = CURLE_RECV_ERROR;
     return -1;
   }
@@ -1669,13 +1657,13 @@ static void ng_has_connected(struct connectdata *conn, int tempindex)
   conn->httpversion = 30;
   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
   conn->quic = &conn->hequic[tempindex];
-  DEBUGF(infof(conn->data, "ngtcp2 established connection!\n"));
 }
 
 /*
  * There can be multiple connection attempts going on in parallel.
  */
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 int sockindex,
                                 bool *done)
 {
@@ -1683,11 +1671,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn,
   struct quicsocket *qs = &conn->hequic[sockindex];
   curl_socket_t sockfd = conn->tempsock[sockindex];
 
-  result = ng_process_ingress(conn, sockfd, qs);
+  result = ng_process_ingress(data, sockfd, qs);
   if(result)
     goto error;
 
-  result = ng_flush_egress(conn->data, sockfd, qs);
+  result = ng_flush_egress(data, sockfd, qs);
   if(result)
     goto error;
 
@@ -1703,7 +1691,7 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn,
 
 }
 
-static CURLcode ng_process_ingress(struct connectdata *conn,
+static CURLcode ng_process_ingress(struct Curl_easy *data,
                                    curl_socket_t sockfd,
                                    struct quicsocket *qs)
 {
@@ -1728,7 +1716,7 @@ static CURLcode ng_process_ingress(struct connectdata *conn,
       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
         break;
 
-      failf(conn->data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd);
+      failf(data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd);
       return CURLE_RECV_ERROR;
     }
 
@@ -1894,11 +1882,13 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
 /*
  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
  */
-CURLcode Curl_quic_done_sending(struct connectdata *conn)
+CURLcode Curl_quic_done_sending(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
+  DEBUGASSERT(conn);
   if(conn->handler == &Curl_handler_http3) {
     /* only for HTTP/3 transfers */
-    struct HTTP *stream = conn->data->req.p.http;
+    struct HTTP *stream = data->req.p.http;
     struct quicsocket *qs = conn->quic;
     stream->upload_done = TRUE;
     (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
index 5601428e9f7d865830810964cf1469b13ee9d6d1..d9d50bb53ce492465646d86be48c83861f9a83aa 100644 (file)
 #define QUIC_MAX_DATA (1*1024*1024)
 #define QUIC_IDLE_TIMEOUT (60 * 1000) /* milliseconds */
 
-static CURLcode process_ingress(struct connectdata *conn,
+static CURLcode process_ingress(struct Curl_easy *data,
                                 curl_socket_t sockfd,
                                 struct quicsocket *qs);
 
-static CURLcode flush_egress(struct connectdata *conn, curl_socket_t sockfd,
+static CURLcode flush_egress(struct Curl_easy *data, curl_socket_t sockfd,
                              struct quicsocket *qs);
 
-static CURLcode http_request(struct connectdata *conn, const void *mem,
+static CURLcode http_request(struct Curl_easy *data, const void *mem,
                              size_t len);
 static Curl_recv h3_stream_recv;
 static Curl_send h3_stream_send;
@@ -84,14 +84,17 @@ static int quiche_getsock(struct Curl_easy *data,
   return bitmap;
 }
 
-static CURLcode qs_disconnect(struct connectdata *conn,
+static CURLcode qs_disconnect(struct Curl_easy *data,
+                              struct connectdata *conn,
                               struct quicsocket *qs)
 {
+  DEBUGASSERT(conn);
+  DEBUGASSERT(qs);
   if(qs->conn) {
     (void)quiche_conn_close(qs->conn, TRUE, 0, NULL, 0);
     /* flushing the egress is not a failsafe way to deliver all the
        outstanding packets, but we also don't want to get stuck here... */
-    (void)flush_egress(conn, qs->sockfd, qs);
+    (void)flush_egress(data, qs->sockfd, qs);
     quiche_conn_free(qs->conn);
     qs->conn = NULL;
   }
@@ -111,16 +114,16 @@ static CURLcode quiche_disconnect(struct Curl_easy *data,
                                   bool dead_connection)
 {
   struct quicsocket *qs = conn->quic;
-  (void)data;
   (void)dead_connection;
-  return qs_disconnect(conn, qs);
+  return qs_disconnect(data, conn, qs);
 }
 
-void Curl_quic_disconnect(struct connectdata *conn,
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int tempindex)
 {
   if(conn->transport == TRNSPRT_QUIC)
-    qs_disconnect(conn, &conn->hequic[tempindex]);
+    qs_disconnect(data, conn, &conn->hequic[tempindex]);
 }
 
 static unsigned int quiche_conncheck(struct Curl_easy *data,
@@ -170,13 +173,13 @@ static void quiche_debug_log(const char *line, void *argp)
 }
 #endif
 
-CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn, curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr, socklen_t addrlen)
 {
   CURLcode result;
   struct quicsocket *qs = &conn->hequic[sockindex];
-  struct Curl_easy *data = conn->data;
   char *keylog_file = NULL;
 
 #ifdef DEBUG_QUICHE
@@ -242,7 +245,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
   }
 #endif
 
-  result = flush_egress(conn, sockfd, qs);
+  result = flush_egress(data, sockfd, qs);
   if(result)
     return result;
 
@@ -319,38 +322,39 @@ static CURLcode quiche_has_connected(struct connectdata *conn,
 /*
  * This function gets polled to check if this QUIC connection has connected.
  */
-CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                int sockindex,
                                 bool *done)
 {
   CURLcode result;
   struct quicsocket *qs = &conn->hequic[sockindex];
   curl_socket_t sockfd = conn->tempsock[sockindex];
 
-  result = process_ingress(conn, sockfd, qs);
+  result = process_ingress(data, sockfd, qs);
   if(result)
     goto error;
 
-  result = flush_egress(conn, sockfd, qs);
+  result = flush_egress(data, sockfd, qs);
   if(result)
     goto error;
 
   if(quiche_conn_is_established(qs->conn)) {
     *done = TRUE;
     result = quiche_has_connected(conn, 0, sockindex);
-    DEBUGF(infof(conn->data, "quiche established connection!\n"));
+    DEBUGF(infof(data, "quiche established connection!\n"));
   }
 
   return result;
   error:
-  qs_disconnect(conn, qs);
+  qs_disconnect(data, conn, qs);
   return result;
 }
 
-static CURLcode process_ingress(struct connectdata *conn, int sockfd,
+static CURLcode process_ingress(struct Curl_easy *data, int sockfd,
                                 struct quicsocket *qs)
 {
   ssize_t recvd;
-  struct Curl_easy *data = conn->data;
   uint8_t *buf = (uint8_t *)data->state.buffer;
   size_t bufsize = data->set.buffer_size;
 
@@ -363,7 +367,7 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd,
       break;
 
     if(recvd < 0) {
-      failf(conn->data, "quiche: recv() unexpectedly returned %zd "
+      failf(data, "quiche: recv() unexpectedly returned %zd "
             "(errno: %d, socket %d)", recvd, SOCKERRNO, sockfd);
       return CURLE_RECV_ERROR;
     }
@@ -373,7 +377,7 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd,
       break;
 
     if(recvd < 0) {
-      failf(conn->data, "quiche_conn_recv() == %zd", recvd);
+      failf(data, "quiche_conn_recv() == %zd", recvd);
       return CURLE_RECV_ERROR;
     }
   } while(1);
@@ -385,7 +389,7 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd,
  * flush_egress drains the buffers and sends off data.
  * Calls failf() on errors.
  */
-static CURLcode flush_egress(struct connectdata *conn, int sockfd,
+static CURLcode flush_egress(struct Curl_easy *data, int sockfd,
                              struct quicsocket *qs)
 {
   ssize_t sent;
@@ -398,14 +402,13 @@ static CURLcode flush_egress(struct connectdata *conn, int sockfd,
       break;
 
     if(sent < 0) {
-      failf(conn->data, "quiche_conn_send returned %zd",
-            sent);
+      failf(data, "quiche_conn_send returned %zd", sent);
       return CURLE_SEND_ERROR;
     }
 
     sent = send(sockfd, out, sent, 0);
     if(sent < 0) {
-      failf(conn->data, "send() returned %zd", sent);
+      failf(data, "send() returned %zd", sent);
       return CURLE_SEND_ERROR;
     }
   } while(1);
@@ -414,7 +417,7 @@ static CURLcode flush_egress(struct connectdata *conn, int sockfd,
   timeout_ns = quiche_conn_timeout_as_nanos(qs->conn);
   if(timeout_ns)
     /* expire uses milliseconds */
-    Curl_expire(conn->data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC);
+    Curl_expire(data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC);
 
   return CURLE_OK;
 }
@@ -471,7 +474,7 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
   headers.destlen = buffersize;
   headers.nlen = 0;
 
-  if(process_ingress(conn, sockfd, qs)) {
+  if(process_ingress(data, sockfd, qs)) {
     infof(data, "h3_stream_recv returns on ingress\n");
     *curlcode = CURLE_RECV_ERROR;
     return -1;
@@ -531,7 +534,7 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
 
     quiche_h3_event_free(ev);
   }
-  if(flush_egress(conn, sockfd, qs)) {
+  if(flush_egress(data, sockfd, qs)) {
     *curlcode = CURLE_SEND_ERROR;
     return -1;
   }
@@ -558,7 +561,7 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
   struct HTTP *stream = data->req.p.http;
 
   if(!stream->h3req) {
-    CURLcode result = http_request(conn, mem, len);
+    CURLcode result = http_request(data, mem, len);
     if(result) {
       *curlcode = CURLE_SEND_ERROR;
       return -1;
@@ -566,8 +569,7 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
     sent = len;
   }
   else {
-    H3BUGF(infof(conn->data, "Pass on %zd body bytes to quiche\n",
-                 len));
+    H3BUGF(infof(data, "Pass on %zd body bytes to quiche\n", len));
     sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,
                                (uint8_t *)mem, len, FALSE);
     if(sent < 0) {
@@ -576,7 +578,7 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
     }
   }
 
-  if(flush_egress(conn, sockfd, qs)) {
+  if(flush_egress(data, sockfd, qs)) {
     *curlcode = CURLE_SEND_ERROR;
     return -1;
   }
@@ -598,12 +600,13 @@ int Curl_quic_ver(char *p, size_t len)
    field list. */
 #define AUTHORITY_DST_IDX 3
 
-static CURLcode http_request(struct connectdata *conn, const void *mem,
+static CURLcode http_request(struct Curl_easy *data, const void *mem,
                              size_t len)
 {
   /*
    */
-  struct HTTP *stream = conn->data->req.p.http;
+  struct connectdata *conn = data->conn;
+  struct HTTP *stream = data->req.p.http;
   size_t nheader;
   size_t i;
   size_t authority_idx;
@@ -613,7 +616,6 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
   quiche_h3_header *nva = NULL;
   struct quicsocket *qs = conn->quic;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   stream->h3req = TRUE; /* senf off! */
 
@@ -826,12 +828,14 @@ fail:
 /*
  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
  */
-CURLcode Curl_quic_done_sending(struct connectdata *conn)
+CURLcode Curl_quic_done_sending(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
+  DEBUGASSERT(conn);
   if(conn->handler == &Curl_handler_http3) {
     /* only for HTTP/3 transfers */
     ssize_t sent;
-    struct HTTP *stream = conn->data->req.p.http;
+    struct HTTP *stream = data->req.p.http;
     struct quicsocket *qs = conn->quic;
     stream->upload_done = TRUE;
     sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,