mirror of
https://github.com/moparisthebest/curl
synced 2024-11-11 03:55:03 -05:00
CURLOPT_HAPROXYPROTOCOL: support the HAProxy PROXY protocol
Add --haproxy-protocol for the command line tool Closes #2162
This commit is contained in:
parent
9572831b04
commit
6baeb6df35
11
docs/cmdline-opts/haproxy-protocol.d
Normal file
11
docs/cmdline-opts/haproxy-protocol.d
Normal file
@ -0,0 +1,11 @@
|
||||
Long: haproxy-protocol
|
||||
Help: Send HAProxy PROXY protocol header
|
||||
Protocols: HTTP
|
||||
Added: 7.60.0
|
||||
---
|
||||
Send a HAProxy PROXY protocol header at the beginning of the connection. This
|
||||
is used by some load balancers and reverse proxies to indicate the client's
|
||||
true IP address and port.
|
||||
|
||||
This option is primarily useful when sending test requests to a service that
|
||||
expects this header.
|
@ -185,6 +185,8 @@ Socks5 GSSAPI service name. \fICURLOPT_SOCKS5_GSSAPI_SERVICE(3)\fP
|
||||
Socks5 GSSAPI NEC mode. See \fICURLOPT_SOCKS5_GSSAPI_NEC(3)\fP
|
||||
.IP CURLOPT_PROXY_SERVICE_NAME
|
||||
Proxy authentication service name. \fICURLOPT_PROXY_SERVICE_NAME(3)\fP
|
||||
.IP CURLOPT_HAPROXYPROTOCOL
|
||||
Send an HAProxy PROXY protocol header. See \fICURLOPT_HAPROXYPROTOCOL(3)\fP
|
||||
.IP CURLOPT_SERVICE_NAME
|
||||
Authentication service name. \fICURLOPT_SERVICE_NAME(3)\fP
|
||||
.IP CURLOPT_INTERFACE
|
||||
|
57
docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.3
Normal file
57
docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.3
Normal file
@ -0,0 +1,57 @@
|
||||
.\" **************************************************************************
|
||||
.\" * _ _ ____ _
|
||||
.\" * Project ___| | | | _ \| |
|
||||
.\" * / __| | | | |_) | |
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2017, 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
|
||||
.\" * are also available at https://curl.haxx.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.
|
||||
.\" *
|
||||
.\" **************************************************************************
|
||||
.\"
|
||||
.TH CURLOPT_HAPROXYPROTOCOL 3 "5 Feb 2018" "libcurl 7.60.0" "curl_easy_setopt options"
|
||||
.SH NAME
|
||||
CURLOPT_HAPROXYPROTOCOL \- send HAProxy PROXY protocol header
|
||||
.SH SYNOPSIS
|
||||
#include <curl/curl.h>
|
||||
|
||||
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HAPROXYPROTOCOL,
|
||||
long haproxy_protocol);
|
||||
.SH DESCRIPTION
|
||||
A long parameter set to 1 tells the library to send an HAProxy PROXY
|
||||
protocol header at beginning of the connection. The default action is not to
|
||||
send this header.
|
||||
|
||||
This option is primarily useful when sending test requests to a service that
|
||||
expects this header.
|
||||
|
||||
Most applications do not need this option.
|
||||
.SH DEFAULT
|
||||
0, do not send HAProxy PROXY protocol header
|
||||
.SH PROTOCOLS
|
||||
HTTP
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
CURL *curl = curl_easy_init();
|
||||
if(curl) {
|
||||
CURLcode ret;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||
curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
|
||||
ret = curl_easy_perform(curl);
|
||||
}
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Along with HTTP. Added in 7.60.0.
|
||||
.SH RETURN VALUE
|
||||
Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.
|
@ -137,6 +137,7 @@ man_MANS = \
|
||||
CURLOPT_FTP_USE_PRET.3 \
|
||||
CURLOPT_GSSAPI_DELEGATION.3 \
|
||||
CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 \
|
||||
CURLOPT_HAPROXYPROTOCOL.3 \
|
||||
CURLOPT_HEADER.3 \
|
||||
CURLOPT_HEADERDATA.3 \
|
||||
CURLOPT_HEADERFUNCTION.3 \
|
||||
|
@ -404,6 +404,7 @@ CURLOPT_FTP_USE_EPSV 7.9.2
|
||||
CURLOPT_FTP_USE_PRET 7.20.0
|
||||
CURLOPT_GSSAPI_DELEGATION 7.22.0
|
||||
CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS 7.59.0
|
||||
CURLOPT_HAPROXYPROTOCOL 7.60.0
|
||||
CURLOPT_HEADER 7.1
|
||||
CURLOPT_HEADERDATA 7.10
|
||||
CURLOPT_HEADERFUNCTION 7.7.2
|
||||
|
@ -1841,6 +1841,9 @@ typedef enum {
|
||||
/* User data to pass to the resolver start callback. */
|
||||
CINIT(RESOLVER_START_DATA, OBJECTPOINT, 273),
|
||||
|
||||
/* send HAProxy PROXY protocol header? */
|
||||
CINIT(HAPROXYPROTOCOL, LONG, 274),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
|
50
lib/http.c
50
lib/http.c
@ -92,6 +92,8 @@ static int http_getsock_do(struct connectdata *conn,
|
||||
int numsocks);
|
||||
static int http_should_fail(struct connectdata *conn);
|
||||
|
||||
static CURLcode add_haproxy_protocol_header(struct connectdata *conn);
|
||||
|
||||
#ifdef USE_SSL
|
||||
static CURLcode https_connecting(struct connectdata *conn, bool *done);
|
||||
static int https_getsock(struct connectdata *conn,
|
||||
@ -1358,6 +1360,13 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
||||
/* nothing else to do except wait right now - we're not done here. */
|
||||
return CURLE_OK;
|
||||
|
||||
if(conn->data->set.haproxyprotocol) {
|
||||
/* add HAProxy PROXY protocol header */
|
||||
result = add_haproxy_protocol_header(conn);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(conn->given->protocol & CURLPROTO_HTTPS) {
|
||||
/* perform SSL initialization */
|
||||
result = https_connecting(conn, done);
|
||||
@ -1383,6 +1392,47 @@ static int http_getsock_do(struct connectdata *conn,
|
||||
return GETSOCK_WRITESOCK(0);
|
||||
}
|
||||
|
||||
static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
|
||||
{
|
||||
char proxy_header[128];
|
||||
Curl_send_buffer *req_buffer;
|
||||
CURLcode result;
|
||||
char tcp_version[5];
|
||||
|
||||
/* Emit the correct prefix for IPv6 */
|
||||
if(conn->bits.ipv6) {
|
||||
strcpy(tcp_version, "TCP6");
|
||||
}
|
||||
else {
|
||||
strcpy(tcp_version, "TCP4");
|
||||
}
|
||||
|
||||
snprintf(proxy_header,
|
||||
sizeof proxy_header,
|
||||
"PROXY %s %s %s %i %i\r\n",
|
||||
tcp_version,
|
||||
conn->data->info.conn_local_ip,
|
||||
conn->data->info.conn_primary_ip,
|
||||
conn->data->info.conn_local_port,
|
||||
conn->data->info.conn_primary_port);
|
||||
|
||||
req_buffer = Curl_add_buffer_init();
|
||||
if(!req_buffer)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
result = Curl_add_bufferf(req_buffer, proxy_header);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_add_buffer_send(req_buffer,
|
||||
conn,
|
||||
&conn->data->info.request_size,
|
||||
0,
|
||||
FIRSTSOCKET);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_SSL
|
||||
static CURLcode https_connecting(struct connectdata *conn, bool *done)
|
||||
{
|
||||
|
@ -1603,6 +1603,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
|
||||
case CURLOPT_HAPROXYPROTOCOL:
|
||||
/*
|
||||
* Set to send the HAProxy Proxy Protocol header
|
||||
*/
|
||||
data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
|
||||
case CURLOPT_INTERFACE:
|
||||
/*
|
||||
* Set what interface or address/hostname to bind the socket to when
|
||||
|
@ -1678,6 +1678,8 @@ struct UserDefined {
|
||||
bool stream_depends_e; /* set or don't set the Exclusive bit */
|
||||
int stream_weight;
|
||||
|
||||
bool haproxyprotocol; /* whether to send HAProxy PROXY protocol header */
|
||||
|
||||
struct Curl_http2_dep *stream_dependents;
|
||||
|
||||
bool abstract_unix_socket;
|
||||
|
@ -252,6 +252,7 @@ struct OperationConfig {
|
||||
bool ssh_compression; /* enable/disable SSH compression */
|
||||
long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds.
|
||||
0 is valid. default: CURL_HET_DEFAULT. */
|
||||
bool haproxy_protocol; /* whether to send HAProxy PROXY protocol */
|
||||
struct GlobalConfig *global;
|
||||
struct OperationConfig *prev;
|
||||
struct OperationConfig *next; /* Always last in the struct */
|
||||
|
@ -112,6 +112,7 @@ static const struct LongShort aliases[]= {
|
||||
{"*x", "krb", ARG_STRING},
|
||||
{"*x", "krb4", ARG_STRING},
|
||||
/* 'krb4' is the previous name */
|
||||
{"*X", "haproxy-protocol", ARG_BOOL},
|
||||
{"*y", "max-filesize", ARG_STRING},
|
||||
{"*z", "disable-eprt", ARG_BOOL},
|
||||
{"*Z", "eprt", ARG_BOOL},
|
||||
@ -779,6 +780,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||
else
|
||||
return PARAM_LIBCURL_DOESNT_SUPPORT;
|
||||
break;
|
||||
case 'X': /* --haproxy-protocol */
|
||||
config->haproxy_protocol = toggle;
|
||||
break;
|
||||
case 'y': /* --max-filesize */
|
||||
{
|
||||
curl_off_t value;
|
||||
|
@ -164,6 +164,8 @@ static const struct helptxt helptext[] = {
|
||||
"How long to wait in milliseconds for IPv6 before trying IPv4"},
|
||||
{"-I, --head",
|
||||
"Show document info only"},
|
||||
{" --haproxy-protocol",
|
||||
"Send HAProxy PROXY protocol header"},
|
||||
{"-H, --header <header/@file>",
|
||||
"Pass custom header(s) to server"},
|
||||
{"-h, --help",
|
||||
|
@ -1445,6 +1445,10 @@ static CURLcode operate_do(struct GlobalConfig *global,
|
||||
my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
|
||||
config->happy_eyeballs_timeout_ms);
|
||||
|
||||
/* new in 7.60.0 */
|
||||
if(config->haproxy_protocol)
|
||||
my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
|
||||
|
||||
/* initialize retry vars for loop below */
|
||||
retry_sleep_default = (config->retry_delay) ?
|
||||
config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
|
||||
|
@ -165,7 +165,7 @@ test1424 test1425 test1426 test1427 \
|
||||
test1428 test1429 test1430 test1431 test1432 test1433 test1434 test1435 \
|
||||
test1436 test1437 test1438 test1439 test1440 test1441 test1442 test1443 \
|
||||
test1444 test1445 test1446 test1447 test1448 test1449 test1450 test1451 \
|
||||
test1452 test1453 test1454 \
|
||||
test1452 test1453 test1454 test1455 test1456 \
|
||||
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
|
||||
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
|
||||
test1516 test1517 \
|
||||
|
56
tests/data/test1455
Normal file
56
tests/data/test1455
Normal file
@ -0,0 +1,56 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply name="1455">
|
||||
<data nocheck=yes>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
ETag: "21025-dc7-39462498"
|
||||
Accept-Ranges: bytes
|
||||
Content-Length: 6
|
||||
Connection: close
|
||||
Content-Type: text/html
|
||||
Funny-head: barkbark
|
||||
|
||||
-foo-
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<name>
|
||||
HTTP GET when PROXY Protocol enabled
|
||||
</name>
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/1455 --haproxy-protocol --local-port 37756
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
</strip>
|
||||
<protocol>
|
||||
PROXY TCP4 %CLIENTIP %HOSTIP 37756 %HTTPPORT
|
||||
GET /1455 HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
59
tests/data/test1456
Normal file
59
tests/data/test1456
Normal file
@ -0,0 +1,59 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
HTTP GET
|
||||
IPv6
|
||||
</keywords>
|
||||
</info>
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data nocheck=yes>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
ETag: "21025-dc7-39462498"
|
||||
Accept-Ranges: bytes
|
||||
Content-Length: 6
|
||||
Connection: close
|
||||
Content-Type: text/html
|
||||
Funny-head: yesyes
|
||||
|
||||
-foo-
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<features>
|
||||
ipv6
|
||||
</features>
|
||||
<server>
|
||||
http-ipv6
|
||||
</server>
|
||||
<name>
|
||||
HTTP-IPv6 GET with PROXY protocol
|
||||
</name>
|
||||
<command>
|
||||
-g "http://%HOST6IP:%HTTP6PORT/1456" --local-port 44444 --haproxy-protocol
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:
|
||||
</strip>
|
||||
<protocol>
|
||||
PROXY TCP6 ::1 ::1 44444 %HTTP6PORT
|
||||
GET /1456 HTTP/1.1
|
||||
Host: %HOST6IP:%HTTP6PORT
|
||||
Accept: */*
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
Loading…
Reference in New Issue
Block a user