MEDIUM: proxy: remove long-broken 'option http_proxy'

This option had always been broken in HTX, which means that the first
breakage appeared in 1.9, that it was broken by default in 2.0 and that
no workaround existed starting with 2.1. The way this option works is
praticularly unfit to the rest of the configuration and to the internal
architecture. It had some uses when it was introduced 14 years ago but
nowadays it's possible to do much better and more reliable using a
set of "http-request set-dst" and "http-request set-uri" rules, which
additionally are compatible with DNS resolution (via do-resolve) and
are not exclusive to normal load balancing. The "option-http_proxy"
example config file was updated to reflect this.

The option is still parsed so that an error message gives hints about
what to look for.
This commit is contained in:
Willy Tarreau 2021-07-18 19:18:56 +02:00
parent f1db20c473
commit 252412316e
8 changed files with 22 additions and 100 deletions

View File

@ -3607,7 +3607,6 @@ option http-use-proxy-header (*) X X X -
option httpchk X - X X option httpchk X - X X
option httpclose (*) X X X X option httpclose (*) X X X X
option httplog X X X - option httplog X X X -
option http_proxy (*) X X X X
option independent-streams (*) X X X X option independent-streams (*) X X X X
option ldap-check X - X X option ldap-check X - X X
option external-check X - X X option external-check X - X X
@ -4002,7 +4001,7 @@ balance url_param <param> [check_post]
might be a URL parameter list. This is probably not a concern with SGML might be a URL parameter list. This is probably not a concern with SGML
type message bodies. type message bodies.
See also : "dispatch", "cookie", "transparent", "hash-type" and "http_proxy". See also : "dispatch", "cookie", "transparent", "hash-type".
bind [<address>]:<port_range> [, ...] [param*] bind [<address>]:<port_range> [, ...] [param*]
@ -8857,36 +8856,6 @@ option httplog [ clf ]
See also : section 8 about logging. See also : section 8 about logging.
option http_proxy
no option http_proxy
Enable or disable plain HTTP proxy mode
May be used in sections : defaults | frontend | listen | backend
yes | yes | yes | yes
Arguments : none
It sometimes happens that people need a pure HTTP proxy which understands
basic proxy requests without caching nor any fancy feature. In this case,
it may be worth setting up an HAProxy instance with the "option http_proxy"
set. In this mode, no server is declared, and the connection is forwarded to
the IP address and port found in the URL after the "http://" scheme.
No host address resolution is performed, so this only works when pure IP
addresses are passed. Since this option's usage perimeter is rather limited,
it will probably be used only by experts who know they need exactly it. This
is incompatible with the HTTP tunnel mode.
If this option has been enabled in a "defaults" section, it can be disabled
in a specific instance by prepending the "no" keyword before it.
Example :
# this backend understands HTTP proxy requests and forwards them directly.
backend direct_forward
option httpclose
option http_proxy
See also : "option httpclose"
option independent-streams option independent-streams
no option independent-streams no option independent-streams
Enable or disable independent timeout processing for both directions Enable or disable independent timeout processing for both directions
@ -19941,15 +19910,12 @@ url_ip : ip
presented as an IP address. Its use is very limited. For instance, a presented as an IP address. Its use is very limited. For instance, a
monitoring system might use this field as an alternative for the source IP in monitoring system might use this field as an alternative for the source IP in
order to test what path a given source address would follow, or to force an order to test what path a given source address would follow, or to force an
entry in a table for a given source address. With ACLs it can be used to entry in a table for a given source address. It may be used in combination
restrict access to certain systems through a proxy, for example when combined with 'http-request set-dst' to emulate the older 'option http_proxy'.
with option "http_proxy".
url_port : integer url_port : integer
This extracts the port part from the request's URL. Note that if the port is This extracts the port part from the request's URL. Note that if the port is
not specified in the request, port 80 is assumed. With ACLs it can be used to not specified in the request, port 80 is assumed..
restrict access to certain systems through a proxy, for example when combined
with option "http_proxy".
urlp([<name>[,<delim>]]) : string urlp([<name>[,<delim>]]) : string
url_param([<name>[,<delim>]]) : string url_param([<name>[,<delim>]]) : string

View File

@ -17,8 +17,6 @@ frontend test-proxy
log global log global
option httplog option httplog
option dontlognull option dontlognull
option nolinger
option http_proxy
maxconn 8000 maxconn 8000
timeout client 30s timeout client 30s
@ -40,12 +38,17 @@ backend test-proxy-srv
timeout connect 5s timeout connect 5s
timeout server 5s timeout server 5s
retries 2 retries 2
option nolinger
option http_proxy
# layer7: Only GET method is valid # layer7: Only GET method is valid
acl valid_method method GET acl valid_method method GET
http-request deny if !valid_method http-request deny if !valid_method
# take IP address from URL's authority
# and drop scheme+authority from URI
http-request set-dst url_ip
http-request set-dst-port url_port
http-request set-uri %[pathq]
server next-hop 0.0.0.0
# layer7: protect bad reply # layer7: protect bad reply
http-response deny if { res.hdr(content-type) audio/mp3 } http-response deny if { res.hdr(content-type) audio/mp3 }

View File

@ -112,7 +112,7 @@ enum PR_SRV_STATE_FILE {
#define PR_O_TCPCHK_SSL 0x08000000 /* at least one TCPCHECK connect rule requires SSL */ #define PR_O_TCPCHK_SSL 0x08000000 /* at least one TCPCHECK connect rule requires SSL */
#define PR_O_CONTSTATS 0x10000000 /* continuous counters */ #define PR_O_CONTSTATS 0x10000000 /* continuous counters */
#define PR_O_HTTP_PROXY 0x20000000 /* Enable stream to use HTTP proxy operations */ /* unused: 0x20000000 */
#define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */ #define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */
#define PR_O_ORGTO 0x80000000 /* insert x-original-to with destination address */ #define PR_O_ORGTO 0x80000000 /* insert x-original-to with destination address */

View File

@ -792,17 +792,6 @@ int assign_server(struct stream *s)
else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) { else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) {
s->target = &s->be->obj_type; s->target = &s->be->obj_type;
} }
else if ((s->be->options & PR_O_HTTP_PROXY)) {
conn = cs_conn(objt_cs(s->si[1].end));
if (conn && conn->dst && is_addr(conn->dst)) {
/* in proxy mode, we need a valid destination address */
s->target = &s->be->obj_type;
} else {
err = SRV_STATUS_NOSRV;
goto out;
}
}
else { else {
err = SRV_STATUS_NOSRV; err = SRV_STATUS_NOSRV;
goto out; goto out;
@ -904,10 +893,6 @@ static int alloc_dst_address(struct sockaddr_storage **ss,
(cli_conn->dst->ss_family == AF_INET || cli_conn->dst->ss_family == AF_INET6)) (cli_conn->dst->ss_family == AF_INET || cli_conn->dst->ss_family == AF_INET6))
**ss = *cli_conn->dst; **ss = *cli_conn->dst;
} }
else if (s->be->options & PR_O_HTTP_PROXY) {
/* If HTTP PROXY option is set, then server is already assigned
* during incoming client request parsing. */
}
else { else {
/* no server and no LB algorithm ! */ /* no server and no LB algorithm ! */
return SRV_STATUS_INTERNAL; return SRV_STATUS_INTERNAL;

View File

@ -2024,6 +2024,13 @@ stats_error_parsing:
goto out; goto out;
} }
if (strcmp(args[1], "http_proxy") == 0) {
ha_alert("parsing [%s:%d]: option '%s' is not supported any more since HAProxy 2.5. This option stopped working in HAProxy 1.9 and usually had nasty side effects. It can be more reliably implemented with combinations of 'http-request set-dst' and 'http-request set-uri', and even 'http-request do-resolve' if DNS resolution is desired.\n",
file, linenum, args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (kwm != KWM_STD) { if (kwm != KWM_STD) {
ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n", ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
file, linenum, args[1]); file, linenum, args[1]);

View File

@ -2579,7 +2579,7 @@ int check_config_validity()
err_code |= ERR_WARN; err_code |= ERR_WARN;
} }
} }
else if (!(curproxy->options & (PR_O_TRANSP | PR_O_DISPATCH | PR_O_HTTP_PROXY))) { else if (!(curproxy->options & (PR_O_TRANSP | PR_O_DISPATCH))) {
/* If no LB algo is set in a backend, and we're not in /* If no LB algo is set in a backend, and we're not in
* transparent mode, dispatch mode nor proxy mode, we * transparent mode, dispatch mode nor proxy mode, we
* want to use balance roundrobin by default. * want to use balance roundrobin by default.
@ -2590,11 +2590,9 @@ int check_config_validity()
} }
if (curproxy->options & PR_O_DISPATCH) if (curproxy->options & PR_O_DISPATCH)
curproxy->options &= ~(PR_O_TRANSP | PR_O_HTTP_PROXY); curproxy->options &= ~PR_O_TRANSP;
else if (curproxy->options & PR_O_HTTP_PROXY)
curproxy->options &= ~(PR_O_DISPATCH | PR_O_TRANSP);
else if (curproxy->options & PR_O_TRANSP) else if (curproxy->options & PR_O_TRANSP)
curproxy->options &= ~(PR_O_DISPATCH | PR_O_HTTP_PROXY); curproxy->options &= ~PR_O_DISPATCH;
if ((curproxy->tcpcheck_rules.flags & TCPCHK_RULES_UNUSED_HTTP_RS)) { if ((curproxy->tcpcheck_rules.flags & TCPCHK_RULES_UNUSED_HTTP_RS)) {
ha_warning("%s '%s' uses http-check rules without 'option httpchk', so the rules are ignored.\n", ha_warning("%s '%s' uses http-check rules without 'option httpchk', so the rules are ignored.\n",

View File

@ -616,42 +616,6 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit)
*/ */
htx = htxbuf(&req->buf); htx = htxbuf(&req->buf);
/*
* If HTTP PROXY is set we simply get remote server address parsing
* incoming request.
*/
if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SF_ADDR_SET)) {
struct htx_sl *sl;
struct ist uri, path;
struct http_uri_parser parser;
if (!sockaddr_alloc(&s->target_addr, NULL, 0)) {
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
goto return_int_err;
}
sl = http_get_stline(htx);
uri = htx_sl_req_uri(sl);
parser = http_uri_parser_init(uri);
path = http_parse_path(&parser);
if (url2sa(uri.ptr, uri.len - path.len, s->target_addr, NULL) == -1)
goto return_bad_req;
s->target = &s->be->obj_type;
s->flags |= SF_ADDR_SET | SF_ASSIGNED;
/* if the path was found, we have to remove everything between
* uri.ptr and path.ptr (excluded). If it was not found, we need
* to replace from all the uri by a single "/".
*
* Instead of rewriting the whole start line, we just update
* the star-line URI. Some space will be lost but it should be
* insignificant.
*/
istcpy(&uri, (path.len ? path : ist("/")), uri.len);
}
/* /*
* 7: Now we can work with the cookies. * 7: Now we can work with the cookies.
* Note that doing so might move headers in the request, but * Note that doing so might move headers in the request, but

View File

@ -68,7 +68,6 @@ const struct cfg_opt cfg_opts[] =
{ "clitcpka", PR_O_TCP_CLI_KA, PR_CAP_FE, 0, 0 }, { "clitcpka", PR_O_TCP_CLI_KA, PR_CAP_FE, 0, 0 },
{ "contstats", PR_O_CONTSTATS, PR_CAP_FE, 0, 0 }, { "contstats", PR_O_CONTSTATS, PR_CAP_FE, 0, 0 },
{ "dontlognull", PR_O_NULLNOLOG, PR_CAP_FE, 0, 0 }, { "dontlognull", PR_O_NULLNOLOG, PR_CAP_FE, 0, 0 },
{ "http_proxy", PR_O_HTTP_PROXY, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
{ "http-buffer-request", PR_O_WREQ_BODY, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP }, { "http-buffer-request", PR_O_WREQ_BODY, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
{ "http-ignore-probes", PR_O_IGNORE_PRB, PR_CAP_FE, 0, PR_MODE_HTTP }, { "http-ignore-probes", PR_O_IGNORE_PRB, PR_CAP_FE, 0, PR_MODE_HTTP },
{ "prefer-last-server", PR_O_PREF_LAST, PR_CAP_BE, 0, PR_MODE_HTTP }, { "prefer-last-server", PR_O_PREF_LAST, PR_CAP_BE, 0, PR_MODE_HTTP },