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:
Stefan Eissing 2022-12-30 09:14:55 +01:00 committed by Daniel Stenberg
parent 1c18f8da51
commit 71b7e01610
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
48 changed files with 6908 additions and 4675 deletions

View file

@ -246,7 +246,7 @@ test2300 test2301 test2302 test2303 test2304 \
\
test2400 test2401 test2402 \
\
test2500 \
test2500 test2501 test2502 \
\
test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \

70
tests/data/test2501 Normal file
View file

@ -0,0 +1,70 @@
<testcase>
<info>
<keywords>
HTTP
HTTP POST
HTTP/3
HTTPS
</keywords>
</info>
#
# Server-side
<reply>
<data nocheck="yes">
HTTP/1.1 201 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Connection: close
Content-Length: 0
Funny-head: yesyes
</data>
</reply>
#
# Client-side
<client>
<features>
debug
http
http/3
</features>
<server>
http
http/3
</server>
<name>
HTTP/3 POST
</name>
<setenv>
</setenv>
<command>
-k --http3 "https://%HOSTIP:%HTTP3PORT/%TESTNUMBER" -d "moo"
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<stdout>
HTTP/3 201
date: Tue, 09 Nov 2010 14:49:00 GMT
content-length: 0
funny-head: yesyes
via: 1.1 nghttpx
</stdout>
<protocol nonewline="yes">
POST https://%HOSTIP:%HTTP3PORT/2501 HTTP/1.1
Host: %HOSTIP:%HTTP3PORT
User-Agent: curl/%VERSION
Accept: */*
Content-Length: 3
Content-Type: application/x-www-form-urlencoded
Via: 3 nghttpx
moo
</protocol>
</verify>
</testcase>

104
tests/data/test2502 Normal file
View file

@ -0,0 +1,104 @@
<testcase>
<info>
<keywords>
HTTP
HTTP/3
multi
verbose logs
</keywords>
</info>
# Server-side
<reply>
<data1 crlf=yes">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: server.example.com
Content-Length: 47
file contents should appear once for each file
</data1>
<data2>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: server.example.com
Content-Length: 47
file contents should appear once for each file
</data2>
<data3>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: server.example.com
Content-Length: 47
file contents should appear once for each file
</data3>
<data4>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: server.example.com
Content-Length: 47
file contents should appear once for each file
</data4>
</reply>
# Client-side
<client>
<features>
http/3
</features>
<server>
http
http/3
</server>
<tool>
lib%TESTNUMBER
</tool>
<name>
HTTP GET multiple over HTTP/3
</name>
<command>
https://%HOSTIP:%HTTP3PORT/path/%TESTNUMBER %HOSTIP %HTTP3PORT
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
GET https://localhost:%HTTP3PORT/path/%TESTNUMBER0001 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Via: 3 nghttpx
GET https://localhost:%HTTP3PORT/path/%TESTNUMBER0002 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Via: 3 nghttpx
GET https://localhost:%HTTP3PORT/path/%TESTNUMBER0003 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Via: 3 nghttpx
GET https://localhost:%HTTP3PORT/path/%TESTNUMBER0004 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Via: 3 nghttpx
</protocol>
<strip>
^Host:.*
</strip>
<file name="log/stderr%TESTNUMBER" mode="text">
* Connection #0 to host localhost left intact
* Connection #0 to host localhost left intact
* Connection #0 to host localhost left intact
* Connection #0 to host localhost left intact
</file>
<stripfile>
$_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/))
</stripfile>
</verify>
</testcase>

View file

@ -71,6 +71,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib1945 lib1946 lib1947 lib1948 lib1955 lib1956 lib1957 lib1958 lib1959 \
lib2301 lib2302 lib2304 \
lib2402 \
lib2502 \
lib3010 lib3025 lib3026 lib3027 \
lib3100 lib3101
@ -803,6 +804,10 @@ lib2402_SOURCES = lib2402.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib2402_LDADD = $(TESTUTIL_LIBS)
lib2402_CPPFLAGS = $(AM_CPPFLAGS) -DLIB2402
lib2502_SOURCES = lib2502.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib2502_LDADD = $(TESTUTIL_LIBS)
lib2502_CPPFLAGS = $(AM_CPPFLAGS) -DLIB2502
lib3010_SOURCES = lib3010.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib3010_LDADD = $(TESTUTIL_LIBS)
lib3010_CPPFLAGS = $(AM_CPPFLAGS)

141
tests/libtest/lib2502.c Normal file
View file

@ -0,0 +1,141 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2013 - 2022, Linus Nielsen Feltzing <linus@haxx.se>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "test.h"
#include "testutil.h"
#include "warnless.h"
#include "memdebug.h"
#define TEST_HANG_TIMEOUT 60 * 1000
#define NUM_HANDLES 4
int test(char *URL)
{
int res = 0;
CURL *curl[NUM_HANDLES] = {0};
int running;
CURLM *m = NULL;
int i;
char target_url[256];
char dnsentry[256];
struct curl_slist *slist = NULL;
char *port = libtest_arg3;
char *address = libtest_arg2;
(void)URL;
msnprintf(dnsentry, sizeof(dnsentry), "localhost:%s:%s",
port, address);
printf("%s\n", dnsentry);
slist = curl_slist_append(slist, dnsentry);
if(!slist) {
fprintf(stderr, "curl_slist_append() failed\n");
goto test_cleanup;
}
start_test_timing();
global_init(CURL_GLOBAL_ALL);
multi_init(m);
multi_setopt(m, CURLMOPT_MAXCONNECTS, 1L);
/* get NUM_HANDLES easy handles */
for(i = 0; i < NUM_HANDLES; i++) {
/* get an easy handle */
easy_init(curl[i]);
/* specify target */
msnprintf(target_url, sizeof(target_url),
"https://localhost:%s/path/2502%04i",
port, i + 1);
target_url[sizeof(target_url) - 1] = '\0';
easy_setopt(curl[i], CURLOPT_URL, target_url);
/* go http2 */
easy_setopt(curl[i], CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
easy_setopt(curl[i], CURLOPT_CONNECTTIMEOUT_MS, (long)5000);
easy_setopt(curl[i], CURLOPT_CAINFO, "./certs/EdelCurlRoot-ca.cacert");
/* wait for first connection establised to see if we can share it */
easy_setopt(curl[i], CURLOPT_PIPEWAIT, 1L);
/* go verbose */
easy_setopt(curl[i], CURLOPT_VERBOSE, 1L);
/* include headers */
easy_setopt(curl[i], CURLOPT_HEADER, 1L);
easy_setopt(curl[i], CURLOPT_RESOLVE, slist);
}
fprintf(stderr, "Start at URL 0\n");
for(i = 0; i < NUM_HANDLES; i++) {
/* add handle to multi */
multi_add_handle(m, curl[i]);
for(;;) {
struct timeval interval;
fd_set rd, wr, exc;
int maxfd = -99;
interval.tv_sec = 1;
interval.tv_usec = 0;
multi_perform(m, &running);
abort_on_test_timeout();
if(!running)
break; /* done */
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_ZERO(&exc);
multi_fdset(m, &rd, &wr, &exc, &maxfd);
/* At this point, maxfd is guaranteed to be greater or equal than -1. */
select_test(maxfd + 1, &rd, &wr, &exc, &interval);
abort_on_test_timeout();
}
wait_ms(1); /* to ensure different end times */
}
test_cleanup:
/* proper cleanup sequence - type PB */
for(i = 0; i < NUM_HANDLES; i++) {
curl_multi_remove_handle(m, curl[i]);
curl_easy_cleanup(curl[i]);
}
curl_slist_free_all(slist);
curl_multi_cleanup(m);
curl_global_cleanup();
return res;
}