mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-27 05:41:10 +01:00
MEDIUM: http-rules: Make early-hint custom actions
Now, the early-hint action uses its own dedicated action and is no longer handled "in place" during the HTTP rules evaluation. Thus the action name ACT_HTTP_EARLY_HINT is removed. In additionn, http_add_early_hint_header() and http_reply_103_early_hints() are also removed. This part is now handled in the new action_ptr callback function.
This commit is contained in:
parent
5275aa7540
commit
91b3ec13c6
@ -84,7 +84,6 @@ enum act_name {
|
|||||||
ACT_HTTP_SET_LOGL,
|
ACT_HTTP_SET_LOGL,
|
||||||
ACT_HTTP_SET_TOS,
|
ACT_HTTP_SET_TOS,
|
||||||
ACT_HTTP_SET_MARK,
|
ACT_HTTP_SET_MARK,
|
||||||
ACT_HTTP_EARLY_HINT,
|
|
||||||
|
|
||||||
/* http request actions. */
|
/* http request actions. */
|
||||||
ACT_HTTP_REQ_TARPIT,
|
ACT_HTTP_REQ_TARPIT,
|
||||||
|
|||||||
@ -944,6 +944,86 @@ static enum act_parse_ret parse_http_set_log_level(const char **args, int *orig_
|
|||||||
return ACT_RET_PRS_OK;
|
return ACT_RET_PRS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function executes a early-hint action. It adds an HTTP Early Hint HTTP
|
||||||
|
* 103 response header with <.arg.http.str> name and with a value built
|
||||||
|
* according to <.arg.http.fmt> log line format. If it is the first early-hint
|
||||||
|
* rule of a serie, the 103 response start-line is added first. At the end, if
|
||||||
|
* the next rule is not an early-hint rule or if it is the last rule, the EOH
|
||||||
|
* block is added to terminate the response. On success, it returns
|
||||||
|
* ACT_RET_CONT. If an error occurs while soft rewrites are enabled, the action
|
||||||
|
* is canceled, but the rule processing continue. Otherwsize ACT_RET_ERR is
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
static enum act_return http_action_early_hint(struct act_rule *rule, struct proxy *px,
|
||||||
|
struct session *sess, struct stream *s, int flags)
|
||||||
|
{
|
||||||
|
struct act_rule *prev_rule, *next_rule;
|
||||||
|
struct channel *res = &s->res;
|
||||||
|
struct htx *htx = htx_from_buf(&res->buf);
|
||||||
|
struct buffer *value = alloc_trash_chunk();
|
||||||
|
enum act_return ret = ACT_RET_CONT;
|
||||||
|
|
||||||
|
if (!(s->txn->req.flags & HTTP_MSGF_VER_11))
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
if (!(s->flags & SF_ERR_MASK))
|
||||||
|
s->flags |= SF_ERR_RESOURCE;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get previous and next rules */
|
||||||
|
prev_rule = LIST_PREV(&rule->list, typeof(rule), list);
|
||||||
|
next_rule = LIST_NEXT(&rule->list, typeof(rule), list);
|
||||||
|
|
||||||
|
/* if no previous rule or previous rule is not early-hint, start a new response. Otherwise,
|
||||||
|
* continue to add link to a previously started response */
|
||||||
|
if (&prev_rule->list == s->current_rule_list || prev_rule->action_ptr != http_action_early_hint) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the HTTP Early Hint HTTP 103 response heade */
|
||||||
|
value->data = build_logline(s, b_tail(value), b_room(value), &rule->arg.http.fmt);
|
||||||
|
if (!htx_add_header(htx, rule->arg.http.str, ist2(b_head(value), b_data(value))))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* if it is the last rule or the next one is not an early-hint, terminate the current
|
||||||
|
* response. */
|
||||||
|
if (&next_rule->list == s->current_rule_list || next_rule->action_ptr != http_action_early_hint) {
|
||||||
|
size_t data;
|
||||||
|
|
||||||
|
if (!htx_add_endof(htx, HTX_BLK_EOH)) {
|
||||||
|
/* If an error occurred during an Early-hint rule,
|
||||||
|
* remove the incomplete HTTP 103 response from the
|
||||||
|
* buffer */
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = htx->data - co_data(res);
|
||||||
|
c_adv(res, data);
|
||||||
|
res->total += data;
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
free_trash_chunk(value);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* If an error occurred during an Early-hint rule, remove the incomplete
|
||||||
|
* HTTP 103 response from the buffer */
|
||||||
|
channel_htx_truncate(res, htx);
|
||||||
|
ret = ACT_RET_ERR;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function executes a set-header or add-header actions. It builds a string
|
/* This function executes a set-header or add-header actions. It builds a string
|
||||||
* in the trash from the specified format string. It finds the action to be
|
* in the trash from the specified format string. It finds the action to be
|
||||||
* performed in <.action>, previously filled by function parse_set_header(). The
|
* performed in <.action>, previously filled by function parse_set_header(). The
|
||||||
@ -1016,8 +1096,10 @@ static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg
|
|||||||
{
|
{
|
||||||
int cap, cur_arg;
|
int cap, cur_arg;
|
||||||
|
|
||||||
if (args[*orig_arg-1][0] == 'e')
|
if (args[*orig_arg-1][0] == 'e') {
|
||||||
rule->action = ACT_HTTP_EARLY_HINT;
|
rule->action = ACT_CUSTOM;
|
||||||
|
rule->action_ptr = http_action_early_hint;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (args[*orig_arg-1][0] == 's')
|
if (args[*orig_arg-1][0] == 's')
|
||||||
rule->action = 0; // set-header
|
rule->action = 0; // set-header
|
||||||
|
|||||||
@ -2728,75 +2728,6 @@ int http_replace_hdrs(struct stream* s, struct htx *htx, struct ist name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminate a 103-Erly-hints response and send it to the client. It returns 0
|
|
||||||
* on success and -1 on error. The response channel is updated accordingly.
|
|
||||||
*/
|
|
||||||
static int http_reply_103_early_hints(struct channel *res)
|
|
||||||
{
|
|
||||||
struct htx *htx = htx_from_buf(&res->buf);
|
|
||||||
size_t data;
|
|
||||||
|
|
||||||
if (!htx_add_endof(htx, HTX_BLK_EOH)) {
|
|
||||||
/* If an error occurred during an Early-hint rule,
|
|
||||||
* remove the incomplete HTTP 103 response from the
|
|
||||||
* buffer */
|
|
||||||
channel_htx_truncate(res, htx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = htx->data - co_data(res);
|
|
||||||
c_adv(res, data);
|
|
||||||
res->total += data;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build an HTTP Early Hint HTTP 103 response header with <name> as name and with a value
|
|
||||||
* built according to <fmt> log line format.
|
|
||||||
* If <early_hints> is 0, it is starts a new response by adding the start
|
|
||||||
* line. If an error occurred -1 is returned. On success 0 is returned. The
|
|
||||||
* channel is not updated here. It must be done calling the function
|
|
||||||
* http_reply_103_early_hints().
|
|
||||||
*/
|
|
||||||
static int http_add_early_hint_header(struct stream *s, int early_hints, const struct ist name, struct list *fmt)
|
|
||||||
{
|
|
||||||
struct channel *res = &s->res;
|
|
||||||
struct htx *htx = htx_from_buf(&res->buf);
|
|
||||||
struct buffer *value = alloc_trash_chunk();
|
|
||||||
|
|
||||||
if (!value) {
|
|
||||||
if (!(s->flags & SF_ERR_MASK))
|
|
||||||
s->flags |= SF_ERR_RESOURCE;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!early_hints) {
|
|
||||||
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 fail;
|
|
||||||
sl->info.res.status = 103;
|
|
||||||
}
|
|
||||||
|
|
||||||
value->data = build_logline(s, b_tail(value), b_room(value), fmt);
|
|
||||||
if (!htx_add_header(htx, name, ist2(b_head(value), b_data(value))))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
free_trash_chunk(value);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
/* If an error occurred during an Early-hint rule, remove the incomplete
|
|
||||||
* HTTP 103 response from the buffer */
|
|
||||||
channel_htx_truncate(res, htx);
|
|
||||||
free_trash_chunk(value);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function executes one of the set-{method,path,query,uri} actions. It
|
/* This function executes one of the set-{method,path,query,uri} actions. It
|
||||||
* takes the string from the variable 'replace' with length 'len', then modifies
|
* takes the string from the variable 'replace' with length 'len', then modifies
|
||||||
* the relevant part of the request line accordingly. Then it updates various
|
* the relevant part of the request line accordingly. Then it updates various
|
||||||
@ -3028,36 +2959,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
|
|||||||
http_remove_header(htx, &ctx);
|
http_remove_header(htx, &ctx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_HTTP_EARLY_HINT: {
|
|
||||||
struct act_rule *prev_rule, *next_rule;
|
|
||||||
int early_hints;
|
|
||||||
|
|
||||||
if (!(txn->req.flags & HTTP_MSGF_VER_11))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* get previous and next rules */
|
|
||||||
prev_rule = LIST_PREV(&rule->list, typeof(rule), list);
|
|
||||||
next_rule = LIST_NEXT(&rule->list, typeof(rule), list);
|
|
||||||
|
|
||||||
/* if no previous rule or previous rule is not early-hint, start a new response. Otherwise,
|
|
||||||
* continue to add link to a previously started response */
|
|
||||||
early_hints = (&prev_rule->list != rules && prev_rule->action == ACT_HTTP_EARLY_HINT);
|
|
||||||
|
|
||||||
if (http_add_early_hint_header(s, early_hints, rule->arg.http.str, &rule->arg.http.fmt) == -1) {
|
|
||||||
rule_ret = HTTP_RULE_RES_ERROR;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
/* if it is the last rule or the next one is not an early-hint, terminate the current
|
|
||||||
* response. */
|
|
||||||
if (&next_rule->list == rules || next_rule->action != ACT_HTTP_EARLY_HINT) {
|
|
||||||
if (http_reply_103_early_hints(&s->res) == -1) {
|
|
||||||
rule_ret = HTTP_RULE_RES_ERROR;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ACT_ACTION_TRK_SC0 ... ACT_ACTION_TRK_SCMAX:
|
case ACT_ACTION_TRK_SC0 ... ACT_ACTION_TRK_SCMAX:
|
||||||
/* Note: only the first valid tracking parameter of each
|
/* Note: only the first valid tracking parameter of each
|
||||||
* applies.
|
* applies.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user