diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h index 5c39749400..f51d7a5a0c 100644 --- a/bin/varnishd/cache/cache.h +++ b/bin/varnishd/cache/cache.h @@ -155,6 +155,12 @@ struct ws { * */ +enum well_known_method { +#define WKM(wk, bit) WKM_##wk = 1U << bit, +#include "tbl/well_known_methods.h" +#undef WKM +}; + struct http { unsigned magic; #define HTTP_MAGIC 0x6428b5c9 @@ -173,6 +179,7 @@ struct http { struct ws *ws; uint16_t status; uint8_t protover; + enum well_known_method wkm; }; /*--------------------------------------------------------------------*/ @@ -670,6 +677,7 @@ int HTTP_IterHdrPack(struct worker *, struct objcore *, const char **); const char *HTTP_GetHdrPack(struct worker *, struct objcore *, hdr_t); stream_close_t http_DoConnection(struct http *hp, stream_close_t sc_close); int http_IsFiltered(const struct http *hp, unsigned u, unsigned how); +void http_SetWellKnownMethod(struct http *hp); #define HTTPH_R_PASS (1 << 0) /* Request (c->b) in pass mode */ #define HTTPH_R_FETCH (1 << 1) /* Request (c->b) for fetch */ @@ -694,9 +702,8 @@ extern hdr_t H__Reason; // rfc7230,l,1144,1144 // rfc7231,l,1156,1158 -#define http_method_eq(str, tok) (!vstrcmp(str, #tok)) -// l = vstrlen(str) -#define http_method_eq_l(str, l, tok) (l == vstrlen(#tok) && ! vstrcmp(str, #tok)) +#define http_method_eq(check, wkm) ((check & wkm) == wkm) +#define http_method_among(check, wkms) ((check & (wkms)) != 0) // rfc7230,l,1222,1222 // rfc7230,l,2848,2848 diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c index d11ac66d70..a216827b65 100644 --- a/bin/varnishd/cache/cache_fetch.c +++ b/bin/varnishd/cache/cache_fetch.c @@ -382,8 +382,6 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) vtim_real now; unsigned handling, skip_vbr = 0; struct objcore *oc; - const char *met; - size_t met_l; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); @@ -407,13 +405,8 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) http_PrintfHeader(bo->bereq, "X-Varnish: %ju", VXID(bo->vsl->wid)); if (bo->bereq_body == NULL && bo->req == NULL) { - met = http_GetMethod(bo->bereq); - met_l = vstrlen(met); - if (http_method_eq_l(met, met_l, GET) || - http_method_eq_l(met, met_l, HEAD) || - http_method_eq_l(met, met_l, DELETE) || - http_method_eq_l(met, met_l, OPTIONS) || - http_method_eq_l(met, met_l, TRACE)) + if (http_method_among(bo->bereq->wkm, (WKM_GET | WKM_HEAD | WKM_DELETE | + WKM_OPTIONS | WKM_TRACE))) http_Unset(bo->bereq, H_Content_Length); else http_ForceHeader(bo->bereq, H_Content_Length, "0"); diff --git a/bin/varnishd/cache/cache_http.c b/bin/varnishd/cache/cache_http.c index f8402458f2..858d19b2af 100644 --- a/bin/varnishd/cache/cache_http.c +++ b/bin/varnishd/cache/cache_http.c @@ -361,6 +361,7 @@ HTTP_Setup(struct http *hp, struct ws *ws, struct vsl_log *vsl, hp->logtag = whence; hp->ws = ws; hp->vsl = vsl; + hp->wkm = WKM_UNKNOWN; } /*-------------------------------------------------------------------- @@ -397,6 +398,7 @@ HTTP_Dup(struct http *to, const struct http * fm) to->logtag = fm->logtag; to->status = fm->status; to->protover = fm->protover; + to->wkm = fm->wkm; } @@ -452,6 +454,8 @@ http_SetH(struct http *to, unsigned n, const char *header) http_VSLH(to, n); if (n == HTTP_HDR_PROTO) http_Proto(to); + if (n == HTTP_HDR_METHOD) + http_SetWellKnownMethod(to); } /*--------------------------------------------------------------------*/ @@ -1456,6 +1460,7 @@ http_FilterReq(struct http *to, const struct http *fm, unsigned how) CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); http_linkh(to, fm, HTTP_HDR_METHOD); + http_SetWellKnownMethod(to); http_linkh(to, fm, HTTP_HDR_URL); http_linkh(to, fm, HTTP_HDR_PROTO); to->protover = fm->protover; @@ -1625,3 +1630,26 @@ http_Unset(struct http *hp, hdr_t hdr) } hp->nhd = v; } + +void +http_SetWellKnownMethod(struct http *hp) +{ + size_t l; + const char *method; + + CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); + + method = http_GetMethod(hp); + AN(method); + hp->wkm = WKM_UNKNOWN; +#define WKM(wk, bit) \ + do { \ + l = vstrlen(method); \ + if (l == vstrlen(#wk) && !vstrcmp(#wk, method)) { \ + hp->wkm = WKM_##wk; \ + return; \ + } \ + } while (0); +#include "tbl/well_known_methods.h" +#undef WKM +} diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c index f4d3810a27..dd1e20c27e 100644 --- a/bin/varnishd/cache/cache_req_fsm.c +++ b/bin/varnishd/cache/cache_req_fsm.c @@ -452,7 +452,7 @@ cnt_transmit(struct worker *wrk, struct req *req) clval = http_GetContentLength(req->resp); /* RFC 7230, 3.3.3 */ status = http_GetStatus(req->resp); - head = http_method_eq(req->http0->hd[HTTP_HDR_METHOD].b, HEAD); + head = http_method_eq(req->http0->wkm, WKM_HEAD); if (req->boc != NULL || (req->objcore->flags & (OC_F_FAILED))) req->resp_len = clval; diff --git a/bin/varnishd/http1/cache_http1.h b/bin/varnishd/http1/cache_http1.h index d9b8f44057..4a3b15ff78 100644 --- a/bin/varnishd/http1/cache_http1.h +++ b/bin/varnishd/http1/cache_http1.h @@ -68,3 +68,4 @@ stream_close_t V1L_Flush(struct v1l *v1l); stream_close_t V1L_Close(struct v1l **v1lp, uint64_t *cnt); size_t V1L_Write(struct v1l *v1l, const void *ptr, ssize_t len); extern const struct vdp * const VDP_v1l; +void http_SetWellKnownMethod(struct http *hp); diff --git a/bin/varnishd/http1/cache_http1_fetch.c b/bin/varnishd/http1/cache_http1_fetch.c index f8bcf43cd4..a016cb79e0 100644 --- a/bin/varnishd/http1/cache_http1_fetch.c +++ b/bin/varnishd/http1/cache_http1_fetch.c @@ -272,7 +272,7 @@ V1F_FetchRespHdr(struct busyobj *bo) * Figure out how the fetch is supposed to happen, before the * headers are adulterated by VCL */ - if (http_method_eq(http_GetMethod(bo->bereq), HEAD)) { + if (http_method_eq(bo->bereq->wkm, WKM_HEAD)) { /* * A HEAD request can never have a body in the reply, * no matter what the headers might say. diff --git a/bin/varnishd/http1/cache_http1_proto.c b/bin/varnishd/http1/cache_http1_proto.c index 54777278ec..294f2bbc42 100644 --- a/bin/varnishd/http1/cache_http1_proto.c +++ b/bin/varnishd/http1/cache_http1_proto.c @@ -355,7 +355,6 @@ HTTP1_DissectRequest(struct http_conn *htc, struct http *hp) uint16_t retval; const char *p; const char *b = NULL, *e; - size_t l; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); @@ -389,18 +388,18 @@ HTTP1_DissectRequest(struct http_conn *htc, struct http *hp) p = http_GetMethod(hp); AN(p); - l = vstrlen(p); + http_SetWellKnownMethod(hp); if (htc->body_status == BS_EOF) { assert(hp->protover == 10); /* RFC1945 8.3 p32 and D.1.1 p58 */ - if (http_method_eq_l(p, l, POST) || http_method_eq_l(p, l, PUT)) + if (http_method_among(hp->wkm, (WKM_POST | WKM_PUT))) return (400); htc->body_status = BS_NONE; } /* HEAD with a body is a hard error */ - if (htc->body_status != BS_NONE && http_method_eq_l(p, l, HEAD)) + if (htc->body_status != BS_NONE && http_method_eq(hp->wkm, WKM_HEAD)) return (400); return (retval); diff --git a/include/Makefile.am b/include/Makefile.am index 347724d70a..ef4328f189 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -48,6 +48,7 @@ nobase_pkginclude_HEADERS = \ tbl/vsl_tags.h \ tbl/vsl_tags_http.h \ tbl/waiters.h \ + tbl/well_known_methods.h \ vapi/vsc.h \ vapi/vsig.h \ vapi/vsl.h \ diff --git a/include/tbl/well_known_methods.h b/include/tbl/well_known_methods.h new file mode 100644 index 0000000000..d255ede36a --- /dev/null +++ b/include/tbl/well_known_methods.h @@ -0,0 +1,40 @@ +/*- + * Copyright 2026 UPLEX - Nils Goroll Systemoptimierung + * All rights reserved. + * + * Author: Thibaut Artis + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Define well-known HTTP methods + */ + +WKM(GET, 0) +WKM(HEAD, 1) +WKM(POST, 2) +WKM(PUT, 3) +WKM(DELETE, 4) +WKM(OPTIONS, 5) +WKM(TRACE, 6) +WKM(PATCH, 7) +WKM(CONNECT, 8) +WKM(UNKNOWN, 31)