BUG/MEDIUM: http-ana: Don't loop trying to generate a malformed 500 response
When HAProxy generates a 500 response, if the formatting failed, for instance
because the message is larger than a buffer, it retries to format it in loop. To
fix the bug, we must stop trying to send a response if it is a non-rewritable
response (TX_CONST_REPLY flag is set on the HTTP transaction).
Because this part is not trivial, some comments have been added.
No backport is needed.
diff --git a/src/http_ana.c b/src/http_ana.c
index bd63343..7c36293 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -4548,7 +4548,8 @@
* function forwards all pending incoming data. If <final> is set to 0, nothing
* more is performed. It is used for 1xx informational messages. Otherwise, the
* transaction is terminated and the request is emptied. On success 1 is
- * returned. If an error occurred, 0 is returned.
+ * returned. If an error occurred, 0 is returned. If it fails, this function
+ * only exits. It is the caller responsibility to do the cleanup.
*/
int http_forward_proxy_resp(struct stream *s, int final)
{
@@ -4600,10 +4601,14 @@
if (http_reply_message(s, msg) == -1) {
/* On error, return a 500 error message, but don't rewrite it if
- * it is already an internal error.
+ * it is already an internal error. If it was already a "const"
+ * 500 error, just fail.
*/
- if (s->txn->status == 500)
+ if (s->txn->status == 500) {
+ if (s->txn->flags & TX_CONST_REPLY)
+ goto end;
s->txn->flags |= TX_CONST_REPLY;
+ }
s->txn->status = 500;
s->txn->http_reply = NULL;
return http_reply_and_close(s, s->txn->status, http_error_message(s));
@@ -4636,9 +4641,10 @@
return &http_err_replies[msgnum];
}
-/* Produces an HTX message from an http reply. Depending on the http reply type, a,
- * errorfile, an raw file or a log-format string is used. On success, it returns
- * 0. If an error occurs -1 is returned.
+/* Produces an HTX message from an http reply. Depending on the http reply type,
+ * a, errorfile, an raw file or a log-format string is used. On success, it
+ * returns 0. If an error occurs -1 is returned. If it fails, this function only
+ * exits. It is the caller responsibility to do the cleanup.
*/
int http_reply_to_htx(struct stream *s, struct htx *htx, struct http_reply *reply)
{
@@ -4750,7 +4756,11 @@
}
/* Send an http reply to the client. On success, it returns 0. If an error
- * occurs -1 is returned.
+ * occurs -1 is returned and the response channel is truncated, removing this
+ * way the faulty reply. This function may fail when the reply is formatted
+ * (http_reply_to_htx) or when the reply is forwarded
+ * (http_forward_proxy_resp). On the last case, it is because a
+ * http-after-response rule fails.
*/
int http_reply_message(struct stream *s, struct http_reply *reply)
{