]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: http-rules: Make early-hint custom actions
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 17 Jan 2020 21:30:06 +0000 (22:30 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 20 Jan 2020 14:18:45 +0000 (15:18 +0100)
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.

include/types/action.h
src/http_act.c
src/http_ana.c

index 6d77f9cd2e818ddb8acbf00a6482da92566a55f9..0016796b8b41dddad8b29d25a3ed3dbbc07c11d4 100644 (file)
@@ -84,7 +84,6 @@ enum act_name {
        ACT_HTTP_SET_LOGL,
        ACT_HTTP_SET_TOS,
        ACT_HTTP_SET_MARK,
-       ACT_HTTP_EARLY_HINT,
 
        /* http request actions. */
        ACT_HTTP_REQ_TARPIT,
index 537b1d04a5a093f1b6c814984433da32ac14497f..60b65c4f0f2332dff9e872297620599540f4e75c 100644 (file)
@@ -944,6 +944,86 @@ static enum act_parse_ret parse_http_set_log_level(const char **args, int *orig_
        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
  * 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
@@ -1016,8 +1096,10 @@ static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg
 {
        int cap, cur_arg;
 
-       if (args[*orig_arg-1][0] == 'e')
-               rule->action = ACT_HTTP_EARLY_HINT;
+       if (args[*orig_arg-1][0] == 'e') {
+               rule->action = ACT_CUSTOM;
+               rule->action_ptr = http_action_early_hint;
+       }
        else {
                if (args[*orig_arg-1][0] == 's')
                        rule->action = 0; // set-header
index 9f6c90e0b7dbe718b123e44e9e67392f0b3dc47e..d21d19e1fdb23b53ee9b27a59f454a156c68cd9c 100644 (file)
@@ -2728,75 +2728,6 @@ int http_replace_hdrs(struct stream* s, struct htx *htx, struct ist name,
        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
  * takes the string from the variable 'replace' with length 'len', then modifies
  * 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);
                                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:
                                /* Note: only the first valid tracking parameter of each
                                 * applies.