summaryrefslogtreecommitdiff
path: root/lib/url.c
diff options
context:
space:
mode:
authorStefan Eissing <stefan@eissing.org>2022-11-11 11:45:34 +0100
committerDaniel Stenberg <daniel@haxx.se>2022-11-11 15:17:51 +0100
commitdafdb20a26d0c890e83dea61a104b75408481ebd (patch)
tree40824f46de18cb7b7b47fb06a3be624c9c06961b /lib/url.c
parent89ee5cfb38b22f9ff68c34aa55ca2c242be90826 (diff)
downloadcurl-dafdb20a26d0c890e83dea61a104b75408481ebd.tar.gz
lib: connection filters (cfilter) addition to curl:
- general construct/destroy in connectdata - default implementations of callback functions - connect: cfilters for connect and accept - socks: cfilter for socks proxying - http_proxy: cfilter for http proxy tunneling - vtls: cfilters for primary and proxy ssl - change in general handling of data/conn - Curl_cfilter_setup() sets up filter chain based on data settings, if none are installed by the protocol handler setup - Curl_cfilter_connect() boot straps filters into `connected` status, used by handlers and multi to reach further stages - Curl_cfilter_is_connected() to check if a conn is connected, e.g. all filters have done their work - Curl_cfilter_get_select_socks() gets the sockets and READ/WRITE indicators for multi select to work - Curl_cfilter_data_pending() asks filters if the have incoming data pending for recv - Curl_cfilter_recv()/Curl_cfilter_send are the general callbacks installed in conn->recv/conn->send for io handling - Curl_cfilter_attach_data()/Curl_cfilter_detach_data() inform filters and addition/removal of a `data` from their connection - adding vtl functions to prevent use of Curl_ssl globals directly in other parts of the code. Reviewed-by: Daniel Stenberg Closes #9855
Diffstat (limited to 'lib/url.c')
-rw-r--r--lib/url.c200
1 files changed, 90 insertions, 110 deletions
diff --git a/lib/url.c b/lib/url.c
index 6774b6b85..ebaedd5f2 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -107,6 +107,7 @@ bool Curl_win32_idn_to_ascii(const char *in, char **out);
#include "system_win32.h"
#include "hsts.h"
#include "noproxy.h"
+#include "cfilters.h"
/* And now for the protocols */
#include "ftp.h"
@@ -140,7 +141,11 @@ bool Curl_win32_idn_to_ascii(const char *in, char **out);
#include "curl_memory.h"
#include "memdebug.h"
-static void conn_free(struct connectdata *conn);
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+static void conn_free(struct Curl_easy *data, struct connectdata *conn);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
* more than just a few bytes to play with. Don't let it become too small or
@@ -756,28 +761,20 @@ static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
/* possible left-overs from the async name resolvers */
Curl_resolver_cancel(data);
- /* close the SSL stuff before we close any sockets since they will/may
- write to the sockets */
- Curl_ssl_close(data, conn, FIRSTSOCKET);
-#ifndef CURL_DISABLE_FTP
- Curl_ssl_close(data, conn, SECONDARYSOCKET);
-#endif
-
- /* close possibly still open sockets */
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
- if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
- Curl_closesocket(data, conn, conn->sock[FIRSTSOCKET]);
- if(CURL_SOCKET_BAD != conn->tempsock[0])
- Curl_closesocket(data, conn, conn->tempsock[0]);
- if(CURL_SOCKET_BAD != conn->tempsock[1])
- Curl_closesocket(data, conn, conn->tempsock[1]);
+ Curl_cfilter_close(data, conn, SECONDARYSOCKET);
+ Curl_cfilter_close(data, conn, FIRSTSOCKET);
}
-static void conn_free(struct connectdata *conn)
+static void conn_free(struct Curl_easy *data, struct connectdata *conn)
{
+ size_t i;
+
DEBUGASSERT(conn);
+ for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+ Curl_cfilter_destroy(data, conn, (int)i);
+ }
+
Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host);
#ifndef CURL_DISABLE_PROXY
@@ -801,7 +798,6 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
- Curl_safefree(conn->connect_state);
conn_reset_all_postponed_data(conn);
Curl_llist_destroy(&conn->easyq, NULL);
@@ -847,6 +843,8 @@ void Curl_disconnect(struct Curl_easy *data,
/* the transfer must be detached from the connection */
DEBUGASSERT(!data->conn);
+ DEBUGF(infof(data, "Curl_disconnect(conn #%ld, dead=%d)",
+ conn->connection_id, dead_connection));
/*
* If this connection isn't marked to force-close, leave it open if there
* are other users of it
@@ -884,7 +882,7 @@ void Curl_disconnect(struct Curl_easy *data,
/* detach it again */
Curl_detach_connection(data);
- conn_free(conn);
+ conn_free(data, conn);
}
/*
@@ -1687,7 +1685,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
Note that these backend pointers can be swapped by vtls (eg ssl backend
data becomes proxy backend data). */
{
- size_t onesize = Curl_ssl->sizeof_ssl_backend_data;
+ size_t onesize = Curl_ssl_get_backend_data_size(data);
size_t totalsize = onesize;
char *ssl;
@@ -2435,7 +2433,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
}
#ifdef USE_SSL
- if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
+ if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
#endif
if(proxytype == CURLPROXY_HTTPS) {
failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
@@ -3529,13 +3527,13 @@ static CURLcode resolve_server(struct Curl_easy *data,
}
/*
- * Cleanup the connection just allocated before we can move along and use the
- * previously existing one. All relevant data is copied over and old_conn is
- * ready for freeing once this function returns.
+ * Cleanup the connection `temp`, just allocated for `data`, before using the
+ * previously `existing` one for `data`. All relevant info is copied over
+ * and `temp` is freed.
*/
static void reuse_conn(struct Curl_easy *data,
- struct connectdata *old_conn,
- struct connectdata *conn)
+ struct connectdata *temp,
+ struct connectdata *existing)
{
/* 'local_ip' and 'local_port' get filled with local's numerical
ip address and port number whenever an outgoing connection is
@@ -3543,66 +3541,66 @@ static void reuse_conn(struct Curl_easy *data,
char local_ip[MAX_IPADR_LEN] = "";
int local_port = -1;
- /* get the user+password information from the old_conn struct since it may
+ /* get the user+password information from the temp struct since it may
* be new for this request even when we re-use an existing connection */
- if(old_conn->user) {
+ if(temp->user) {
/* use the new user name and password though */
- Curl_safefree(conn->user);
- Curl_safefree(conn->passwd);
- conn->user = old_conn->user;
- conn->passwd = old_conn->passwd;
- old_conn->user = NULL;
- old_conn->passwd = NULL;
+ Curl_safefree(existing->user);
+ Curl_safefree(existing->passwd);
+ existing->user = temp->user;
+ existing->passwd = temp->passwd;
+ temp->user = NULL;
+ temp->passwd = NULL;
}
#ifndef CURL_DISABLE_PROXY
- conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
- if(conn->bits.proxy_user_passwd) {
+ existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
+ if(existing->bits.proxy_user_passwd) {
/* use the new proxy user name and proxy password though */
- Curl_safefree(conn->http_proxy.user);
- Curl_safefree(conn->socks_proxy.user);
- Curl_safefree(conn->http_proxy.passwd);
- Curl_safefree(conn->socks_proxy.passwd);
- conn->http_proxy.user = old_conn->http_proxy.user;
- conn->socks_proxy.user = old_conn->socks_proxy.user;
- conn->http_proxy.passwd = old_conn->http_proxy.passwd;
- conn->socks_proxy.passwd = old_conn->socks_proxy.passwd;
- old_conn->http_proxy.user = NULL;
- old_conn->socks_proxy.user = NULL;
- old_conn->http_proxy.passwd = NULL;
- old_conn->socks_proxy.passwd = NULL;
- }
-#endif
-
- Curl_free_idnconverted_hostname(&conn->host);
- Curl_free_idnconverted_hostname(&conn->conn_to_host);
- Curl_safefree(conn->host.rawalloc);
- Curl_safefree(conn->conn_to_host.rawalloc);
- conn->host = old_conn->host;
- old_conn->host.rawalloc = NULL;
- old_conn->host.encalloc = NULL;
- conn->conn_to_host = old_conn->conn_to_host;
- old_conn->conn_to_host.rawalloc = NULL;
- conn->conn_to_port = old_conn->conn_to_port;
- conn->remote_port = old_conn->remote_port;
- Curl_safefree(conn->hostname_resolve);
-
- conn->hostname_resolve = old_conn->hostname_resolve;
- old_conn->hostname_resolve = NULL;
+ Curl_safefree(existing->http_proxy.user);
+ Curl_safefree(existing->socks_proxy.user);
+ Curl_safefree(existing->http_proxy.passwd);
+ Curl_safefree(existing->socks_proxy.passwd);
+ existing->http_proxy.user = temp->http_proxy.user;
+ existing->socks_proxy.user = temp->socks_proxy.user;
+ existing->http_proxy.passwd = temp->http_proxy.passwd;
+ existing->socks_proxy.passwd = temp->socks_proxy.passwd;
+ temp->http_proxy.user = NULL;
+ temp->socks_proxy.user = NULL;
+ temp->http_proxy.passwd = NULL;
+ temp->socks_proxy.passwd = NULL;
+ }
+#endif
+
+ Curl_free_idnconverted_hostname(&existing->host);
+ Curl_free_idnconverted_hostname(&existing->conn_to_host);
+ Curl_safefree(existing->host.rawalloc);
+ Curl_safefree(existing->conn_to_host.rawalloc);
+ existing->host = temp->host;
+ temp->host.rawalloc = NULL;
+ temp->host.encalloc = NULL;
+ existing->conn_to_host = temp->conn_to_host;
+ temp->conn_to_host.rawalloc = NULL;
+ existing->conn_to_port = temp->conn_to_port;
+ existing->remote_port = temp->remote_port;
+ Curl_safefree(existing->hostname_resolve);
+
+ existing->hostname_resolve = temp->hostname_resolve;
+ temp->hostname_resolve = NULL;
/* persist connection info in session handle */
- if(conn->transport == TRNSPRT_TCP) {
- Curl_conninfo_local(data, conn->sock[FIRSTSOCKET],
+ if(existing->transport == TRNSPRT_TCP) {
+ Curl_conninfo_local(data, existing->sock[FIRSTSOCKET],
local_ip, &local_port);
}
- Curl_persistconninfo(data, conn, local_ip, local_port);
+ Curl_persistconninfo(data, existing, local_ip, local_port);
- conn_reset_all_postponed_data(old_conn); /* free buffers */
+ conn_reset_all_postponed_data(temp); /* free buffers */
/* re-use init */
- conn->bits.reuse = TRUE; /* yes, we're re-using here */
+ existing->bits.reuse = TRUE; /* yes, we're re-using here */
- conn_free(old_conn);
+ conn_free(data, temp);
}
/**
@@ -3626,7 +3624,7 @@ static CURLcode create_conn(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
struct connectdata *conn;
- struct connectdata *conn_temp = NULL;
+ struct connectdata *existing = NULL;
bool reuse;
bool connections_available = TRUE;
bool force_reuse = FALSE;
@@ -3768,13 +3766,6 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
- conn->recv[FIRSTSOCKET] = Curl_recv_plain;
- conn->send[FIRSTSOCKET] = Curl_send_plain;
- conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
- conn->send[SECONDARYSOCKET] = Curl_send_plain;
-
- conn->bits.tcp_fastopen = data->set.tcp_fastopen;
-
/***********************************************************************
* file: is a special case in that it doesn't need a network connection
***********************************************************************/
@@ -3789,8 +3780,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Setup a "faked" transfer that'll do nothing */
if(!result) {
- conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
-
Curl_attach_connection(data, conn);
result = Curl_conncache_add_conn(data);
if(result)
@@ -3816,6 +3805,13 @@ static CURLcode create_conn(struct Curl_easy *data,
}
#endif
+ /* Setup filter for network connections */
+ conn->recv[FIRSTSOCKET] = Curl_cfilter_recv;
+ conn->send[FIRSTSOCKET] = Curl_cfilter_send;
+ conn->recv[SECONDARYSOCKET] = Curl_cfilter_recv;
+ conn->send[SECONDARYSOCKET] = Curl_cfilter_send;
+ conn->bits.tcp_fastopen = data->set.tcp_fastopen;
+
/* Get a cloned copy of the SSL config situation stored in the
connection struct. But to get this going nicely, we must first make
sure that the strings in the master copy are pointing to the correct
@@ -3915,16 +3911,16 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.connect_only)
reuse = FALSE;
else
- reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
+ reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
if(reuse) {
/*
* We already have a connection for this, we got the former connection in
- * the conn_temp variable and thus we need to cleanup the one we just
- * allocated before we can move along and use the previously existing one.
+ * `existing` and thus we need to cleanup the one we just
+ * allocated before we can move along and use `existing`.
*/
- reuse_conn(data, conn, conn_temp);
- conn = conn_temp;
+ reuse_conn(data, conn, existing);
+ conn = existing;
*in_connect = conn;
#ifndef CURL_DISABLE_PROXY
@@ -3999,7 +3995,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(!connections_available) {
infof(data, "No connections available.");
- conn_free(conn);
+ conn_free(data, conn);
*in_connect = NULL;
result = CURLE_NO_CONNECTION_AVAILABLE;
@@ -4082,7 +4078,6 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
*protocol_done = TRUE;
return result;
}
- *protocol_done = FALSE; /* default to not done */
#ifndef CURL_DISABLE_PROXY
/* set proxy_connect_closed to false unconditionally already here since it
@@ -4099,26 +4094,11 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
/* set start time here for timeout purposes in the connect procedure, it
is later set again for the progress meter purpose */
conn->now = Curl_now();
-
- if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
- conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
- result = Curl_connecthost(data, conn, conn->dns_entry);
- if(result)
- return result;
- }
- else {
- Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
- if(conn->ssl[FIRSTSOCKET].use ||
- (conn->handler->protocol & PROTO_FAMILY_SSH))
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
- conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
- *protocol_done = TRUE;
- Curl_updateconninfo(data, conn, conn->sock[FIRSTSOCKET]);
- Curl_verboseconnect(data, conn);
- }
-
- conn->now = Curl_now(); /* time this *after* the connect is done, we set
- this here perhaps a second time */
+ if(!conn->bits.reuse)
+ result = Curl_cfilter_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
+ CURL_CF_SSL_DEFAULT);
+ /* not sure we need this flag to be passed around any more */
+ *protocol_done = FALSE;
return result;
}