From 71236dedb959e4b707411e0e9be2248452f4d927 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Fri, 13 Jan 2023 09:06:38 +0100 Subject: [PATCH] MINOR: http-ana: Add a function to set HTTP termination flags There is already a function to set termination flags but it is not well suited for HTTP streams. So a function, dedicated to the HTTP analysis, was added. This way, this new function will be called for HTTP analysers on error. And if the error is not caugth at this stage, the generic function will still be called from process_stream(). Here, by default a PRXCOND error is reported and depending on the stream state, the reson will be set accordingly: * If the backend SC is in INI state, SF_FINST_T is reported on tarpit and SF_FINST_R otherwise. * SF_FINST_Q is the server connection is queued * SF_FINST_C in any connection attempt state (REQ/TAR/ASS/CONN/CER/RDY). Except for applets, a SF_FINST_R is reported. * Once the server connection is established, SF_FINST_H is reported while HTTP_MSG_DATA state on the response side. * SF_FINST_L is reported if the response is in HTTP_MSG_DONE state or higher and a client error/timeout was reported. * Otherwise SF_FINST_D is reported. --- include/haproxy/http_ana.h | 2 ++ src/http_ana.c | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/haproxy/http_ana.h b/include/haproxy/http_ana.h index 7a1b94489..cbff545b1 100644 --- a/include/haproxy/http_ana.h +++ b/include/haproxy/http_ana.h @@ -62,6 +62,8 @@ int http_forward_proxy_resp(struct stream *s, int final); struct http_txn *http_create_txn(struct stream *s); void http_destroy_txn(struct stream *s); +void http_set_term_flags(struct stream *s); + /* for debugging, reports the HTTP/1 message state name (legacy version) */ static inline const char *h1_msg_state_str(enum h1_state msg_state) { diff --git a/src/http_ana.c b/src/http_ana.c index 44c295346..873064d55 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -5249,6 +5249,53 @@ void http_destroy_txn(struct stream *s) } +void http_set_term_flags(struct stream *s) +{ + if (!(s->flags & SF_ERR_MASK)) + s->flags |= SF_ERR_PRXCOND; + + if (!(s->flags & SF_FINST_MASK)) { + if (s->scb->state == SC_ST_INI) { + /* Before any connection attempt on the server side, we + * are still in the request analysis. Just take case to + * detect tarpit error + */ + if (s->req.analysers & AN_REQ_HTTP_TARPIT) + s->flags |= SF_FINST_T; + else + s->flags |= SF_FINST_R; + } + else if (s->scb->state == SC_ST_QUE) + s->flags |= SF_FINST_Q; + else if (sc_state_in(s->scb->state, SC_SB_REQ|SC_SB_TAR|SC_SB_ASS|SC_SB_CON|SC_SB_CER|SC_SB_RDY)) { + if (unlikely(objt_applet(s->target))) { + s->flags |= SF_FINST_R; + } + else + s->flags |= SF_FINST_C; + } + else { + if (s->txn->rsp.msg_state < HTTP_MSG_DATA) { + /* We are still processing the response headers */ + s->flags |= SF_FINST_H; + } + // (res >= done) & (res->flags & shutw) + else if (s->txn->rsp.msg_state >= HTTP_MSG_DONE && + (s->flags & (SF_ERR_CLITO|SF_ERR_CLICL))) { + /* A client error was reported and we are + * transmitting the last block of data + */ + s->flags |= SF_FINST_L; + } + else { + /* Otherwise we are in DATA phase on both sides */ + s->flags |= SF_FINST_D; + } + } + } +} + + DECLARE_POOL(pool_head_http_txn, "http_txn", sizeof(struct http_txn)); /*