]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http: Implement "early-hint" http request rules.
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 12 Nov 2018 09:06:54 +0000 (10:06 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 12 Nov 2018 20:08:55 +0000 (21:08 +0100)
This patch implements http_apply_early_hint_rule() function is responsible of
building HTTP 103 Early Hint responses each time a "early-hint" rule is matched.

include/common/http.h
src/http.c
src/proto_http.c

index f876891158a65031df59619ff3793875fcaf2451..3b1620df94d2caa6ddb0e38cae98b19a30ae4e97 100644 (file)
@@ -124,6 +124,7 @@ const struct ist http_known_methods[HTTP_METH_OTHER];
 extern const uint8_t http_char_classes[256];
 
 const struct ist HTTP_100;
+const struct ist HTTP_103;
 extern const char *HTTP_301;
 extern const char *HTTP_302;
 extern const char *HTTP_303;
index 932f3cf70a618477fe2e1af2641fff6530a6ce42..30d349a4b16dada539c92d83db48433fd0269677 100644 (file)
@@ -162,6 +162,8 @@ struct buffer http_err_chunks[HTTP_ERR_SIZE];
 
 const struct ist HTTP_100 = IST("HTTP/1.1 100 Continue\r\n\r\n");
 
+const struct ist HTTP_103 = IST("HTTP/1.1 103 Early Hints\r\n");
+
 /* Warning: no "connection" header is provided with the 3xx messages below */
 const char *HTTP_301 =
        "HTTP/1.1 301 Moved Permanently\r\n"
index a8a1728a8d4ef486ab2d1de802148c3456b81dce..c5d35437f2bd03780d5d2bd18c9898679d991f9d 100644 (file)
@@ -1719,6 +1719,48 @@ static int http_transform_header(struct stream* s, struct http_msg *msg,
        return ret;
 }
 
+/*
+ * 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_hint> is false the HTTP 103 response first line is inserted before
+ * the header.
+ */
+static int http_apply_early_hint_rule(struct stream* s, struct channel *resp, int early_hint,
+                                      const char* name, unsigned int name_len, struct list *fmt)
+{
+       int ret;
+       size_t data;
+       struct buffer *chunk;
+       char *cur_ptr = ci_head(resp);
+
+       ret = 0;
+       data = co_data(resp);
+
+       chunk = alloc_trash_chunk();
+       if (!chunk)
+               goto leave;
+
+       if (!early_hint && !chunk_memcat(chunk, HTTP_103.ptr, HTTP_103.len))
+           goto leave;
+
+       if (!chunk_memcat(chunk, name, name_len) || !chunk_memcat(chunk, ": ", 2))
+               goto leave;
+
+       chunk->data += build_logline(s, chunk->area + chunk->data, chunk->size - chunk->data, fmt);
+       if (!chunk_memcat(chunk, "\r\n", 2))
+           goto leave;
+
+       ret = b_rep_blk(&resp->buf, cur_ptr, cur_ptr, chunk->area, chunk->data);
+       c_adv(resp, ret);
+
+ leave:
+       if (!ret)
+               co_set_data(resp, data);
+       free_trash_chunk(chunk);
+
+       return ret;
+}
+
 /* Executes the http-request rules <rules> for stream <s>, proxy <px> and
  * transaction <txn>. Returns the verdict of the first rule that prevents
  * further processing of the request (auth, deny, ...), and defaults to
@@ -1739,6 +1781,7 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream
        const char *auth_realm;
        int act_flags = 0;
        int len;
+       int early_hint = 0;
 
        /* If "the current_rule_list" match the executed rule list, we are in
         * resume condition. If a resume is needed it is always in the action
@@ -2006,6 +2049,17 @@ resume_execution:
                        break;
                        }
 
+               case ACT_HTTP_EARLY_HINT:
+                       if (!(txn->req.flags & HTTP_MSGF_VER_11))
+                               break;
+
+                       if (!http_apply_early_hint_rule(s, txn->rsp.chn, early_hint,
+                                                       rule->arg.early_hint.name,
+                                                       rule->arg.early_hint.name_len,
+                                                       &rule->arg.early_hint.fmt))
+                               return HTTP_RULE_RES_DONE;
+                       early_hint = 1;
+                       break;
                case ACT_CUSTOM:
                        if ((s->req.flags & CF_READ_ERROR) ||
                            ((s->req.flags & (CF_SHUTR|CF_READ_NULL)) &&
@@ -2074,6 +2128,15 @@ resume_execution:
                }
        }
 
+       if (early_hint) {
+               struct channel *chn = s->txn->rsp.chn;
+               char *cur_ptr = ci_head(chn);
+
+               /* Add an empty line after Early Hint informational response headers */
+               b_rep_blk(&chn->buf, cur_ptr, cur_ptr, "\r\n", 2);
+               c_adv(chn, 2);
+       }
+
        /* we reached the end of the rules, nothing to report */
        return HTTP_RULE_RES_CONT;
 }