From 179085ccacb90672d5c383a64e702b1a1135ddc0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 28 Apr 2014 16:48:56 +0200 Subject: [PATCH] MEDIUM: http: move Connection header processing earlier Till now the Connection header was processed in the middle of the http-request rules and some reqadd rules. It used to force some http-request actions to be cut in two parts. Now with keep-alive, not only that doesn't make any sense anymore, but it's becoming a total mess, especially since we need to know the headers contents before proceeding with most actions. The real reason it was not moved earlier is that the "block" or "http-request" rules can see a different version if some fields are changed there. But that is already not reliable anymore since the values observed by the frontend differ from those in the backend. This patch is the equivalent of commit f118d9f ("REORG: http: move HTTP Connection response header parsing earlier") but for the request side. It has been tagged MEDIUM as it could theorically slightly affect some setups relying on corner cases or invalid setups, though this does not make real sense and is highly unlikely. --- src/proto_http.c | 128 +++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 241dc5285a..e797e002c1 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2916,6 +2916,70 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit) if (!use_close_only) msg->flags |= HTTP_MSGF_XFER_LEN; + /* Until set to anything else, the connection mode is set as Keep-Alive. It will + * only change if both the request and the config reference something else. + * Option httpclose by itself sets tunnel mode where headers are mangled. + * However, if another mode is set, it will affect it (eg: server-close/ + * keep-alive + httpclose = close). Note that we avoid to redo the same work + * if FE and BE have the same settings (common). The method consists in + * checking if options changed between the two calls (implying that either + * one is non-null, or one of them is non-null and we are there for the first + * 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; + } + /* end of job, return OK */ req->analysers &= ~an_bit; req->analyse_exp = TICK_ETERNITY; @@ -3829,70 +3893,6 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit, goto tarpit; } - /* Until set to anything else, the connection mode is set as Keep-Alive. It will - * only change if both the request and the config reference something else. - * Option httpclose by itself sets tunnel mode where headers are mangled. - * However, if another mode is set, it will affect it (eg: server-close/ - * keep-alive + httpclose = close). Note that we avoid to redo the same work - * if FE and BE have the same settings (common). The method consists in - * checking if options changed between the two calls (implying that either - * one is non-null, or one of them is non-null and we are there for the first - * 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; - } - /* we can be blocked here because the request needs to be authenticated, * either to pass or to access stats. */ -- 2.39.5