mirror of
https://github.com/curl/curl.git
synced 2026-08-25 13:13:31 +03:00
lib: connect/h2/h3 refactor
Refactoring of connection setup and happy eyeballing. Move
nghttp2. ngtcp2, quiche and msh3 into connection filters.
- eyeballing cfilter that uses sub-filters for performing parallel connects
- socket cfilter for all transport types, including QUIC
- QUIC implementations in cfilter, can now participate in eyeballing
- connection setup is more dynamic in order to adapt to what filter did
really connect. Relevant to see if a SSL filter needs to be added or
if SSL has already been provided
- HTTP/3 test cases similar to HTTP/2
- multiuse of parallel transfers for HTTP/3, tested for ngtcp2 and quiche
- Fix for data attach/detach in VTLS filters that could lead to crashes
during parallel transfers.
- Eliminating setup() methods in cfilters, no longer needed.
- Improving Curl_conn_is_alive() to replace Curl_connalive() and
integrated ssl alive checks into cfilter.
- Adding CF_CNTRL_CONN_INFO_UPDATE to tell filters to update
connection into and persist it at the easy handle.
- Several more cfilter related cleanups and moves:
- stream_weigth and dependency info is now wrapped in struct
Curl_data_priority
- Curl_data_priority members depend is available in HTTP2|HTTP3
- Curl_data_priority members depend on NGHTTP2 support
- handling init/reset/cleanup of priority part of url.c
- data->state.priority same struct, but shallow copy for compares only
- PROTOPT_STREAM has been removed
- Curl_conn_is_mulitplex() now available to check on capability
- Adding query method to connection filters.
- ngtcp2+quiche: implementing query for max concurrent transfers.
- Adding is_alive and keep_alive cfilter methods. Adding DATA_SETUP event.
- setting keepalive timestamp on connect
- DATA_SETUP is called after the connection has been completely
setup (but may not connected yet) to allow filters to initialize
data members they use.
- there is no socket to be had with msh3, it is unclear how select
shall work
- manual test via "curl --http3 https://curl.se" fail with "empty
reply from server".
- Various socket/conn related cleanups:
- Curl_socket is now Curl_socket_open and in cf-socket.c
- Curl_closesocket is now Curl_socket_close and in cf-socket.c
- Curl_ssl_use has been replaced with Cur_conn_is_ssl
- Curl_conn_tcp_accepted_set has been split into
Curl_conn_tcp_listen_set and Curl_conn_tcp_accepted_set
with a clearer purpose
Closes #10141
This commit is contained in:
parent
1c18f8da51
commit
71b7e01610
48 changed files with 6908 additions and 4675 deletions
|
|
@ -73,6 +73,7 @@
|
|||
#include "url.h"
|
||||
#include "getinfo.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "vquic/vquic.h"
|
||||
#include "select.h"
|
||||
#include "multiif.h"
|
||||
#include "connect.h"
|
||||
|
|
@ -367,27 +368,12 @@ static int data_pending(struct Curl_easy *data)
|
|||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
|
||||
#ifdef ENABLE_QUIC
|
||||
if(conn->transport == TRNSPRT_QUIC)
|
||||
return Curl_quic_data_pending(data);
|
||||
#endif
|
||||
|
||||
if(conn->handler->protocol&PROTO_FAMILY_FTP)
|
||||
return Curl_conn_data_pending(data, SECONDARYSOCKET);
|
||||
|
||||
/* in the case of libssh2, we can never be really sure that we have emptied
|
||||
its internal buffers so we MUST always try until we get EAGAIN back */
|
||||
return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
|
||||
#ifdef USE_NGHTTP2
|
||||
/* For HTTP/2, we may read up everything including response body
|
||||
with header fields in Curl_http_readwrite_headers. If no
|
||||
content-length is provided, curl waits for the connection
|
||||
close, which we emulate it using conn->proto.httpc.closed =
|
||||
TRUE. The thing is if we read everything, then http2_recv won't
|
||||
be called and we cannot signal the HTTP/2 stream has closed. As
|
||||
a workaround, we return nonzero here to call http2_recv. */
|
||||
((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20) ||
|
||||
#endif
|
||||
Curl_conn_data_pending(data, FIRSTSOCKET);
|
||||
}
|
||||
|
||||
|
|
@ -454,29 +440,16 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
bool is_empty_data = FALSE;
|
||||
size_t buffersize = data->set.buffer_size;
|
||||
size_t bytestoread = buffersize;
|
||||
#ifdef USE_NGHTTP2
|
||||
bool is_http2 = ((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
|
||||
(conn->httpversion == 20));
|
||||
#endif
|
||||
bool is_http3 =
|
||||
#ifdef ENABLE_QUIC
|
||||
((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
|
||||
(conn->httpversion == 30));
|
||||
#else
|
||||
FALSE;
|
||||
#endif
|
||||
/* For HTTP/2 and HTTP/3, read data without caring about the content
|
||||
length. This is safe because body in HTTP/2 is always segmented
|
||||
thanks to its framing layer. Meanwhile, we have to call Curl_read
|
||||
to ensure that http2_handle_stream_close is called when we read all
|
||||
incoming bytes for a particular stream. */
|
||||
bool is_http3 = Curl_conn_is_http3(data, conn, FIRSTSOCKET);
|
||||
bool data_eof_handled = is_http3
|
||||
|| Curl_conn_is_http2(data, conn, FIRSTSOCKET);
|
||||
|
||||
if(
|
||||
#ifdef USE_NGHTTP2
|
||||
/* For HTTP/2, read data without caring about the content length. This
|
||||
is safe because body in HTTP/2 is always segmented thanks to its
|
||||
framing layer. Meanwhile, we have to call Curl_read to ensure that
|
||||
http2_handle_stream_close is called when we read all incoming bytes
|
||||
for a particular stream. */
|
||||
!is_http2 &&
|
||||
#endif
|
||||
!is_http3 && /* Same reason mentioned above. */
|
||||
k->size != -1 && !k->header) {
|
||||
if(!data_eof_handled && k->size != -1 && !k->header) {
|
||||
/* make sure we don't read too much */
|
||||
curl_off_t totalleft = k->size - k->bytecount;
|
||||
if(totalleft < (curl_off_t)bytestoread)
|
||||
|
|
@ -499,7 +472,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
else {
|
||||
/* read nothing but since we wanted nothing we consider this an OK
|
||||
situation to proceed from */
|
||||
DEBUGF(infof(data, "readwrite_data: we're done"));
|
||||
DEBUGF(infof(data, DMSG(data, "readwrite_data: we're done")));
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
|
|
@ -518,14 +491,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
buf[nread] = 0;
|
||||
}
|
||||
else {
|
||||
/* if we receive 0 or less here, either the http2 stream is closed or the
|
||||
/* if we receive 0 or less here, either the data transfer is done or the
|
||||
server closed the connection and we bail out from this! */
|
||||
#ifdef USE_NGHTTP2
|
||||
if(is_http2 && !nread)
|
||||
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
|
||||
else
|
||||
#endif
|
||||
if(is_http3 && !nread)
|
||||
if(data_eof_handled)
|
||||
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
|
||||
else
|
||||
DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
|
||||
|
|
@ -799,19 +767,18 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
out:
|
||||
DEBUGF(infof(data, "readwrite_data(handle=%p) -> %d", data, result));
|
||||
if(result)
|
||||
DEBUGF(infof(data, DMSG(data, "readwrite_data() -> %d"), result));
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_done_sending(struct Curl_easy *data,
|
||||
struct SingleRequest *k)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
k->keepon &= ~KEEP_SEND; /* we're done writing */
|
||||
|
||||
/* These functions should be moved into the handler struct! */
|
||||
Curl_http2_done_sending(data, conn);
|
||||
Curl_quic_done_sending(data);
|
||||
Curl_conn_ev_data_done_send(data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
@ -1182,13 +1149,9 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_QUIC
|
||||
if(conn->transport == TRNSPRT_QUIC) {
|
||||
result = Curl_quic_idle(data);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
result = Curl_conn_ev_data_idle(data);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(Curl_pgrsUpdate(data))
|
||||
|
|
@ -1264,7 +1227,8 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||
KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
|
||||
result = CURLE_OK;
|
||||
out:
|
||||
DEBUGF(infof(data, "Curl_readwrite(handle=%p) -> %d", data, result));
|
||||
if(result)
|
||||
DEBUGF(infof(data, DMSG(data, "Curl_readwrite() -> %d"), result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1377,6 +1341,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
|
|||
data->state.authhost.want = data->set.httpauth;
|
||||
data->state.authproxy.want = data->set.proxyauth;
|
||||
Curl_safefree(data->info.wouldredirect);
|
||||
Curl_data_priority_clear_state(data);
|
||||
|
||||
if(data->state.httpreq == HTTPREQ_PUT)
|
||||
data->state.infilesize = data->set.filesize;
|
||||
|
|
@ -1434,7 +1399,6 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
Curl_http2_init_state(&data->state);
|
||||
result = Curl_hsts_loadcb(data, data->hsts);
|
||||
}
|
||||
|
||||
|
|
@ -1872,7 +1836,7 @@ Curl_setup_transfer(
|
|||
httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
|
||||
(http->sending == HTTPSEND_REQUEST));
|
||||
|
||||
if(conn->bits.multiplex || conn->httpversion == 20 || httpsending) {
|
||||
if(conn->bits.multiplex || conn->httpversion >= 20 || httpsending) {
|
||||
/* when multiplexing, the read/write sockets need to be the same! */
|
||||
conn->sockfd = sockindex == -1 ?
|
||||
((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue