option httpchk X - X X
[no] option http-server-
close X X X X
+[no] option http-use-proxy-
+ header X X X -
[no] option httpclose X X X X
option httplog X X X X
[no] option http_proxy X X X X
See also : "option forceclose" and "option httpclose"
+option http-use-proxy-header
+[no] option http-use-proxy-header
+ Make use of non-standard Proxy-Connection header instead of Connection
+ May be used in sections : defaults | frontend | listen | backend
+ yes | yes | yes | no
+ Arguments : none
+
+ While RFC2616 explicitly states that HTTP/1.1 agents must use the
+ Connection header to indicate their wish of persistent or non-persistent
+ connections, both browsers and proxies ignore this header for proxied
+ connections and make use of the undocumented, non-standard Proxy-Connection
+ header instead. The issue begins when trying to put a load balancer between
+ browsers and such proxies, because there will be a difference between what
+ haproxy understands and what the client and the proxy agree on.
+
+ By setting this option in a frontend, haproxy can automatically switch to use
+ that non-standard header if it sees proxied requests. A proxied request is
+ defined here as one where the URI begins with neither a '/' nor a '*'. The
+ choice of header only affects requests passing through proxies making use of
+ one of the "httpclose", "forceclose" and "http-server-close" options. Note
+ that this option can only be specified in a frontend and will affect the
+ request along its whole life.
+
+ This option should normally never be used, except in front of a proxy.
+
+ See also : "option httpclose", "option forceclose" and "option
+ http-server-close".
+
+
option httpclose
no option httpclose
Enable or disable passive HTTP connection closing
memcpy(rdr.str + rdr.len, path, len);
rdr.len += len;
- memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
- rdr.len += 23;
+
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ memcpy(rdr.str + rdr.len, "\r\nProxy-Connection: close\r\n\r\n", 29);
+ rdr.len += 29;
+ } else {
+ memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
+ rdr.len += 23;
+ }
/* prepare to return without error. */
si->shutr(si);
void http_parse_connection_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, int to_del)
{
struct hdr_ctx ctx;
+ const char *hdr_val = "Connection";
+ int hdr_len = 10;
if (txn->flags & TX_HDR_CONN_PRS)
return;
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ hdr_val = "Proxy-Connection";
+ hdr_len = 16;
+ }
+
ctx.idx = 0;
txn->flags &= ~(TX_CON_KAL_SET|TX_CON_CLO_SET);
- while (http_find_header2("Connection", 10, msg->sol, &txn->hdr_idx, &ctx)) {
+ while (http_find_header2(hdr_val, hdr_len, msg->sol, &txn->hdr_idx, &ctx)) {
if (ctx.vlen >= 10 && word_match(ctx.line + ctx.val, ctx.vlen, "keep-alive", 10)) {
txn->flags |= TX_HDR_CONN_KAL;
if ((to_del & 2) && buf)
void http_change_connection_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, int wanted)
{
struct hdr_ctx ctx;
+ const char *hdr_val = "Connection";
+ int hdr_len = 10;
ctx.idx = 0;
+
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ hdr_val = "Proxy-Connection";
+ hdr_len = 16;
+ }
+
txn->flags &= ~(TX_CON_CLO_SET | TX_CON_KAL_SET);
- while (http_find_header2("Connection", 10, msg->sol, &txn->hdr_idx, &ctx)) {
+ while (http_find_header2(hdr_val, hdr_len, msg->sol, &txn->hdr_idx, &ctx)) {
if (ctx.vlen >= 10 && word_match(ctx.line + ctx.val, ctx.vlen, "keep-alive", 10)) {
if (wanted & TX_CON_KAL_SET)
txn->flags |= TX_CON_KAL_SET;
if ((wanted & TX_CON_CLO_SET) && !(txn->flags & TX_CON_CLO_SET)) {
txn->flags |= TX_CON_CLO_SET;
- http_header_add_tail2(buf, msg, &txn->hdr_idx, "Connection: close", 17);
+ hdr_val = "Connection: close";
+ hdr_len = 17;
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ hdr_val = "Proxy-Connection: close";
+ hdr_len = 23;
+ }
+ http_header_add_tail2(buf, msg, &txn->hdr_idx, hdr_val, hdr_len);
}
if ((wanted & TX_CON_KAL_SET) && !(txn->flags & TX_CON_KAL_SET)) {
txn->flags |= TX_CON_KAL_SET;
- http_header_add_tail2(buf, msg, &txn->hdr_idx, "Connection: keep-alive", 22);
+ hdr_val = "Connection: keep-alive";
+ hdr_len = 22;
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ hdr_val = "Proxy-Connection: keep-alive";
+ hdr_len = 28;
+ }
+ http_header_add_tail2(buf, msg, &txn->hdr_idx, hdr_val, hdr_len);
}
return;
}
/* "connection" has not been parsed yet */
txn->flags &= ~(TX_HDR_CONN_PRS | TX_HDR_CONN_CLO | TX_HDR_CONN_KAL);
+ /* if the frontend has "option http-use-proxy-header", we'll check if
+ * we have what looks like a proxied connection instead of a connection,
+ * and in this case set the TX_USE_PX_CONN flag to use Proxy-connection.
+ * Note that this is *not* RFC-compliant, however browsers and proxies
+ * happen to do that despite being non-standard :-(
+ * We consider that a request not beginning with either '/' or '*' is
+ * a proxied connection, which covers both "scheme://location" and
+ * CONNECT ip:port.
+ */
+ if ((s->fe->options2 & PR_O2_USE_PXHDR) &&
+ msg->sol[msg->sl.rq.u] != '/' && msg->sol[msg->sl.rq.u] != '*')
+ txn->flags |= TX_USE_PX_CONN;
+
/* transfer length unknown*/
txn->flags &= ~TX_REQ_XFER_LEN;
(txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
/* keep-alive possible */
if (!(txn->flags & TX_REQ_VER_11)) {
- memcpy(rdr.str + rdr.len, "\r\nConnection: keep-alive", 24);
- rdr.len += 24;
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ memcpy(rdr.str + rdr.len, "\r\nProxy-Connection: keep-alive", 30);
+ rdr.len += 30;
+ } else {
+ memcpy(rdr.str + rdr.len, "\r\nConnection: keep-alive", 24);
+ rdr.len += 24;
+ }
}
memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
rdr.len += 4;
break;
} else {
/* keep-alive not possible */
- memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
- rdr.len += 23;
+ if (unlikely(txn->flags & TX_USE_PX_CONN)) {
+ memcpy(rdr.str + rdr.len, "\r\nProxy-Connection: close\r\n\r\n", 29);
+ rdr.len += 29;
+ } else {
+ memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
+ rdr.len += 23;
+ }
stream_int_retnclose(req->prod, &rdr);
goto return_prx_cond;
}