diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 3db8e10f6..945d49cf5 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -112,6 +112,7 @@ unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hle void http_init_txn(struct session *s); void http_end_txn(struct session *s); void http_reset_txn(struct session *s); +void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg); struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy); struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy); diff --git a/src/proto_http.c b/src/proto_http.c index 11177cb06..89e91a986 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2393,6 +2393,59 @@ fail: return 0; } +void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg) +{ + int tmp = TX_CON_WANT_KAL; + + if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) { + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN) + tmp = TX_CON_WANT_TUN; + + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) + tmp = TX_CON_WANT_TUN; + } + + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) { + /* option httpclose + server_close => forceclose */ + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) + tmp = TX_CON_WANT_CLO; + else + tmp = TX_CON_WANT_SCL; + } + + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL) + tmp = TX_CON_WANT_CLO; + + if ((txn->flags & TX_CON_WANT_MSK) < tmp) + txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp; + + if (!(txn->flags & TX_HDR_CONN_PRS) && + (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) { + /* parse the Connection header and possibly clean it */ + int to_del = 0; + if ((msg->flags & HTTP_MSGF_VER_11) || + ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL && + !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA))) + to_del |= 2; /* remove "keep-alive" */ + if (!(msg->flags & HTTP_MSGF_VER_11)) + to_del |= 1; /* remove "close" */ + http_parse_connection_header(txn, msg, to_del); + } + + /* check if client or config asks for explicit close in KAL/SCL */ + if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL || + (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) && + ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */ + (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */ + !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */ + s->fe->state == PR_STSTOPPED)) /* frontend is stopping */ + txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO; +} /* This stream analyser waits for a complete HTTP request. It returns 1 if the * processing can continue on next analysers, or zero if it either needs more @@ -2929,58 +2982,8 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit) * time. */ if (!(txn->flags & TX_HDR_CONN_PRS) || - ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE))) { - int tmp = TX_CON_WANT_KAL; - - if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) { - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN) - tmp = TX_CON_WANT_TUN; - - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) - tmp = TX_CON_WANT_TUN; - } - - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) { - /* option httpclose + server_close => forceclose */ - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) - tmp = TX_CON_WANT_CLO; - else - tmp = TX_CON_WANT_SCL; - } - - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL) - tmp = TX_CON_WANT_CLO; - - if ((txn->flags & TX_CON_WANT_MSK) < tmp) - txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp; - - if (!(txn->flags & TX_HDR_CONN_PRS) && - (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) { - /* parse the Connection header and possibly clean it */ - int to_del = 0; - if ((msg->flags & HTTP_MSGF_VER_11) || - ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL && - !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA))) - to_del |= 2; /* remove "keep-alive" */ - if (!(msg->flags & HTTP_MSGF_VER_11)) - to_del |= 1; /* remove "close" */ - http_parse_connection_header(txn, msg, to_del); - } - - /* check if client or config asks for explicit close in KAL/SCL */ - if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL || - (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) && - ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */ - (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */ - !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */ - s->fe->state == PR_STSTOPPED)) /* frontend is stopping */ - txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO; - } + ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE))) + http_adjust_conn_mode(s, txn, msg); /* end of job, return OK */ req->analysers &= ~an_bit; diff --git a/src/proxy.c b/src/proxy.c index 02103ee11..405c4c4ad 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -955,6 +955,14 @@ int session_set_backend(struct session *s, struct proxy *be) http_init_txn(s); } + /* If we chain to an HTTP backend running a different HTTP mode, we + * have to re-adjust the desired keep-alive/close mode to accommodate + * both the frontend's and the backend's modes. + */ + if (s->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP && + ((s->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE))) + http_adjust_conn_mode(s, &s->txn, &s->txn.req); + /* If an LB algorithm needs to access some pre-parsed body contents, * we must not start to forward anything until the connection is * confirmed otherwise we'll lose the pointer to these data and