diff --git a/include/haproxy/http_ana.h b/include/haproxy/http_ana.h index 6215c50cc..4dd80e647 100644 --- a/include/haproxy/http_ana.h +++ b/include/haproxy/http_ana.h @@ -58,6 +58,8 @@ struct http_reply *http_error_message(struct stream *s); int http_reply_to_htx(struct stream *s, struct htx *htx, struct http_reply *reply); int http_reply_message(struct stream *s, struct http_reply *reply); int http_forward_proxy_resp(struct stream *s, int final); +struct htx *http_early_hint_start(struct stream *s); +int http_early_hint_end(struct stream *s); struct http_txn *http_create_txn(struct stream *s); void http_destroy_txn(struct stream *s); diff --git a/src/http_act.c b/src/http_act.c index 7b6914909..bf0d9a47c 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -1370,21 +1370,8 @@ static enum act_return http_action_early_hint(struct act_rule *rule, struct prox goto error; } - /* if there is no pending 103 response, start a new response. Otherwise, - * continue to add link to a previously started response - */ - if (s->txn.http->status != 103) { - struct htx_sl *sl; - unsigned int flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11| - HTX_SL_F_XFER_LEN|HTX_SL_F_BODYLESS); - - sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, - ist("HTTP/1.1"), ist("103"), ist("Early Hints")); - if (!sl) - goto error; - sl->info.res.status = 103; - s->txn.http->status = 103; - } + if (!http_early_hint_start(s)) + goto error; /* Add the HTTP Early Hint HTTP 103 response header */ value->data = build_logline(s, b_tail(value), b_room(value), &rule->arg.http.fmt); @@ -1396,11 +1383,8 @@ static enum act_return http_action_early_hint(struct act_rule *rule, struct prox */ next_rule = LIST_NEXT(&rule->list, typeof(rule), list); if (&next_rule->list == s->current_rule_list || next_rule->action_ptr != http_action_early_hint || next_rule->cond) { - if (!htx_add_endof(htx, HTX_BLK_EOH)) + if (!http_early_hint_end(s)) goto error; - if (!http_forward_proxy_resp(s, 0)) - goto error; - s->txn.http->status = 0; } leave: diff --git a/src/http_ana.c b/src/http_ana.c index 4806afd65..749f7919e 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -4765,6 +4765,47 @@ int http_forward_proxy_resp(struct stream *s, int final) return 1; } +/* + * Start a 103 Early Hints response in the response buffer if not already in + * progress (txn->status != 103). The caller is responsible for skipping this + * call for HTTP/1.0 clients. Returns the htx to which the caller can add Link + * headers, or NULL on error. + */ +struct htx *http_early_hint_start(struct stream *s) +{ + struct htx *htx = htx_from_buf(&s->res.buf); + + if (s->txn.http->status != 103) { + struct htx_sl *sl; + unsigned int flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11| + HTX_SL_F_XFER_LEN|HTX_SL_F_BODYLESS); + + sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, + ist("HTTP/1.1"), ist("103"), ist("Early Hints")); + if (!sl) + return NULL; + sl->info.res.status = 103; + s->txn.http->status = 103; + } + return htx; +} + +/* + * Finalize a 103 Early Hints response. Returns 1 on success, 0 on error + * (caller is responsible for truncating the response buffer on failure). + */ +int http_early_hint_end(struct stream *s) +{ + struct htx *htx = htxbuf(&s->res.buf); + + if (!htx_add_endof(htx, HTX_BLK_EOH)) + return 0; + if (!http_forward_proxy_resp(s, 0)) + return 0; + s->txn.http->status = 0; + return 1; +} + void http_server_error(struct stream *s, struct stconn *sc, int err, int finst, struct http_reply *msg) {