proxy: refactor haproxy protocol handling as connection filter

Closes #9893
This commit is contained in:
Stefan Eissing 2022-11-14 16:44:12 +01:00 committed by Daniel Stenberg
parent 6967571bf2
commit a8e6351e12
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 105 additions and 62 deletions

View File

@ -328,6 +328,15 @@ CURLcode Curl_cfilter_setup(struct Curl_easy *data,
#else #else
(void)ssl_mode; (void)ssl_mode;
#endif /* USE_SSL */ #endif /* USE_SSL */
#ifndef CURL_DISABLE_PROXY
if(data->set.haproxyprotocol) {
result = Curl_cfilter_haproxy_add(data, conn, sockindex);
if(result)
goto out;
}
#endif /* !CURL_DISABLE_PROXY */
} }
DEBUGASSERT(conn->cfilter[sockindex]); DEBUGASSERT(conn->cfilter[sockindex]);
cf = data->conn->cfilter[sockindex]; cf = data->conn->cfilter[sockindex];

View File

@ -102,10 +102,6 @@ static int http_getsock_do(struct Curl_easy *data,
curl_socket_t *socks); curl_socket_t *socks);
static bool http_should_fail(struct Curl_easy *data); static bool http_should_fail(struct Curl_easy *data);
#ifndef CURL_DISABLE_PROXY
static CURLcode add_haproxy_protocol_header(struct Curl_easy *data);
#endif
static CURLcode http_setup_conn(struct Curl_easy *data, static CURLcode http_setup_conn(struct Curl_easy *data,
struct connectdata *conn); struct connectdata *conn);
#ifdef USE_WEBSOCKETS #ifdef USE_WEBSOCKETS
@ -1532,30 +1528,13 @@ Curl_compareheader(const char *headerline, /* line to check */
*/ */
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done) CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
{ {
CURLcode result;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
/* We default to persistent connections. We set this already in this connect /* We default to persistent connections. We set this already in this connect
function to make the re-use checks properly be able to check this bit. */ function to make the re-use checks properly be able to check this bit. */
connkeep(conn, "HTTP default"); connkeep(conn, "HTTP default");
result = Curl_cfilter_connect(data, conn, FIRSTSOCKET, FALSE, done); return Curl_cfilter_connect(data, conn, FIRSTSOCKET, FALSE, done);
if(result || !*done)
return result;
#ifndef CURL_DISABLE_PROXY
if(data->set.haproxyprotocol && !data->state.is_haproxy_hdr_sent) {
/* add HAProxy PROXY protocol header */
result = add_haproxy_protocol_header(data);
if(result)
return result;
/* do not send the header again after successful try */
data->state.is_haproxy_hdr_sent = TRUE;
}
#endif
return CURLE_OK;
} }
/* this returns the socket to wait for in the DO and DOING state for the multi /* this returns the socket to wait for in the DO and DOING state for the multi
@ -1571,42 +1550,6 @@ static int http_getsock_do(struct Curl_easy *data,
return GETSOCK_WRITESOCK(0); return GETSOCK_WRITESOCK(0);
} }
#ifndef CURL_DISABLE_PROXY
static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
{
struct dynbuf req;
CURLcode result;
const char *tcp_version;
DEBUGASSERT(data->conn);
Curl_dyn_init(&req, DYN_HAXPROXY);
#ifdef USE_UNIX_SOCKETS
if(data->conn->unix_domain_socket)
/* the buffer is large enough to hold this! */
result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
else {
#endif
/* Emit the correct prefix for IPv6 */
tcp_version = data->conn->bits.ipv6 ? "TCP6" : "TCP4";
result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
tcp_version,
data->info.conn_local_ip,
data->info.conn_primary_ip,
data->info.conn_local_port,
data->info.conn_primary_port);
#ifdef USE_UNIX_SOCKETS
}
#endif
if(!result)
result = Curl_buffer_send(&req, data, &data->info.request_size,
0, FIRSTSOCKET);
return result;
}
#endif
/* /*
* Curl_http_done() gets called after a single HTTP request has been * Curl_http_done() gets called after a single HTTP request has been
* performed. * performed.

View File

@ -1188,4 +1188,91 @@ CURLcode Curl_cfilter_http_proxy_add(struct Curl_easy *data,
return result; return result;
} }
#endif /* !CURL_DISABLE_PROXY && !defined(CURL_DISABLE_HTTP) */
#if !defined(CURL_DISABLE_PROXY)
static CURLcode send_haproxy_header(struct Curl_cfilter*cf,
struct Curl_easy *data)
{
struct dynbuf req;
CURLcode result;
const char *tcp_version;
Curl_dyn_init(&req, DYN_HAXPROXY);
#ifdef USE_UNIX_SOCKETS
if(cf->conn->unix_domain_socket)
/* the buffer is large enough to hold this! */
result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
else {
#endif
/* Emit the correct prefix for IPv6 */
tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
tcp_version,
data->info.conn_local_ip,
data->info.conn_primary_ip,
data->info.conn_local_port,
data->info.conn_primary_port);
#ifdef USE_UNIX_SOCKETS
}
#endif
if(!result)
result = Curl_buffer_send(&req, data, &data->info.request_size,
0, FIRSTSOCKET);
return result;
}
static CURLcode haproxy_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done)
{
CURLcode result;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
}
result = cf->next->cft->connect(cf->next, data, blocking, done);
if(result || !*done)
return result;
result = send_haproxy_header(cf, data);
*done = (!result);
cf->connected = *done;
return result;
}
static const struct Curl_cftype cft_haproxy = {
"HAPROXY",
Curl_cf_def_destroy,
Curl_cf_def_attach_data,
Curl_cf_def_detach_data,
Curl_cf_def_setup,
Curl_cf_def_close,
haproxy_cf_connect,
Curl_cf_def_get_select_socks,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
};
CURLcode Curl_cfilter_haproxy_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
{
struct Curl_cfilter *cf;
CURLcode result;
result = Curl_cfilter_create(&cf, data, conn, sockindex,
&cft_haproxy, NULL);
if(!result)
Curl_cfilter_add(data, conn, sockindex, cf);
return result;
}
#endif /* !CURL_DISABLE_PROXY */ #endif /* !CURL_DISABLE_PROXY */

View File

@ -38,4 +38,12 @@ CURLcode Curl_cfilter_http_proxy_add(struct Curl_easy *data,
#endif #endif
#if !defined(CURL_DISABLE_PROXY)
CURLcode Curl_cfilter_haproxy_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
#endif
#endif /* HEADER_CURL_HTTP_PROXY_H */ #endif /* HEADER_CURL_HTTP_PROXY_H */

View File

@ -1427,10 +1427,6 @@ struct UrlState {
trailers_state trailers_state; /* whether we are sending trailers trailers_state trailers_state; /* whether we are sending trailers
and what stage are we at */ and what stage are we at */
#endif #endif
#ifndef CURL_DISABLE_PROXY
/* to keep track whether we already sent PROXY header or not */
BIT(is_haproxy_hdr_sent);
#endif
#ifdef USE_HYPER #ifdef USE_HYPER
bool hconnect; /* set if a CONNECT request */ bool hconnect; /* set if a CONNECT request */
CURLcode hresult; /* used to pass return codes back from hyper callbacks */ CURLcode hresult; /* used to pass return codes back from hyper callbacks */