From: Maxime Henrion Date: Tue, 26 May 2026 16:57:36 +0000 (-0400) Subject: MINOR: cache: add helper functions for early hints support X-Git-Url: http://git.kaiwu.me/http/$%7BGITURL%7D/static/gitweb.js?a=commitdiff_plain;h=2a27062f9af8f1b6b94f8804088685a09b9357ae;p=haproxy.git MINOR: cache: add helper functions for early hints support Add the hint_rels array, rel_is_hint(), and link_is_hint() functions for identifying Link header values eligible for early hints emission. --- diff --git a/src/cache.c b/src/cache.c index 8a03a3021..0f70c05a4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1025,6 +1025,86 @@ int http_calc_maxage(struct stream *s, struct cache *cache, int *true_maxage) } +/* The rel values in Link headers for which sending a 103 response makes sense. */ +static const struct ist hint_rels[] = { + IST("preload"), + IST("preconnect"), + IST("dns-prefetch"), + IST("modulepreload"), + IST("prefetch"), +}; + +static int rel_is_hint(const struct ist rel) +{ + int i; + + for (i = 0; i < sizeof(hint_rels) / sizeof(*hint_rels); i++) { + if (isteqi(rel, hint_rels[i])) + return 1; + } + return 0; +} + +/* + * Returns true if the value of the Link header contains at least one rel attribute + * worth sending in a 103 Early Hint response. + */ +static int __maybe_unused link_is_hint(struct ist val) +{ + const char *p = istptr(val), *end = istend(val); + struct ist params, pname, pval; + + /* A link-value must start with a "" part (RFC 8288#3). */ + if (p >= end || *p != '<') + return 0; + + /* Skip past the portion to reach the parameter list. */ + while (p < end && *p != '>') + p++; + if (p < end) + p++; + params = ist2(p, end - p); + + while (http_get_hdr_param(¶ms, &pname, &pval, + HTTP_PARAM_BADWS | HTTP_PARAM_NOVAL) > 0) { + if (!isteqi(pname, ist("rel"))) + continue; + + /* Only the first rel parameter counts: per RFC 8288#3.3, + * parsers must ignore subsequent occurrences. Whatever the + * outcome below, we are done with this link-value. + * + * Per RFC 8288#3.3 the rel value carries only tokens, optionally + * separated by SP. Leading or trailing whitespace inside a quoted + * value is malformed; reject the whole rel parameter rather than + * silently tolerating it (cf. RFC 9110#5.6.3). + */ + if (!pval.len || HTTP_IS_LWS(*istptr(pval)) || + HTTP_IS_LWS(istptr(pval)[pval.len - 1])) + return 0; + + while (pval.len) { + const char *tp = istptr(pval), *tend = istend(pval); + const char *tok; + struct ist token; + + tok = tp; + while (tp < tend && !HTTP_IS_LWS(*tp)) + tp++; + token = ist2(tok, tp - tok); + + if (rel_is_hint(token)) + return 1; + + while (tp < tend && HTTP_IS_LWS(*tp)) + tp++; + pval = ist2(tp, tend - tp); + } + return 0; + } + + return 0; +} static void cache_free_blocks(struct shared_block *first, void *data) {