From c97b939325221cd8f4b2b1b92443659343469ca8 Mon Sep 17 00:00:00 2001 From: Veit Heller Date: Sat, 3 Oct 2026 23:14:07 +0200 Subject: [PATCH] Compare header names case-insensitively without allocating --- http.carp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/http.carp b/http.carp index c528753..55b9f3e 100644 --- a/http.carp +++ b/http.carp @@ -260,16 +260,35 @@ attribute, whatever order the two appear in.") c (parse-set-prop c (Array.unsafe-last &max-ages)))))) +(private ascii-lower-byte) +(hidden ascii-lower-byte) +; the byte at `i` of `s`, A–Z folded to a–z, as `tolower` does in the C locale +(defn ascii-lower-byte [s i] + (let [c (Char.to-int (String.char-at s i))] + (if (and (>= c 65) (<= c 90)) (+ c 32) c))) + +(private header-name=) +(hidden header-name=) +; whether header names `a` and `b` are equal, ignoring ASCII case; `len` is the +; length of `b`. It allocates nothing, unlike comparing `String.ascii-to-lower`s. +(defn header-name= [a b len] + (and (= (String.length a) len) + (let-do [i 0 + same true] + (while-do (and same (< i len)) + (set! same (= (ascii-lower-byte a i) (ascii-lower-byte b i))) + (set! i (Int.inc i))) + same))) + (private header-lookup) (hidden header-lookup) (defn header-lookup [hdrs name] - (let [lower-name &(String.ascii-to-lower name)] + (let [len (String.length name)] (Map.kv-reduce &(fn [acc k v] (cond (Maybe.just? &acc) acc - (= &(String.ascii-to-lower k) lower-name) - (Maybe.Just @(Array.unsafe-first v)) + (header-name= k name len) (Maybe.Just @(Array.unsafe-first v)) acc)) (the (Maybe String) (Maybe.Nothing)) hdrs))) @@ -277,12 +296,9 @@ attribute, whatever order the two appear in.") (private header-values) (hidden header-values) (defn header-values [hdrs name] - (let [lower-name &(String.ascii-to-lower name)] + (let [len (String.length name)] (Map.kv-reduce - &(fn [acc k v] - (if (= &(String.ascii-to-lower k) lower-name) - (Array.concat &[acc @v]) - acc)) + &(fn [acc k v] (if (header-name= k name len) (Array.concat &[acc @v]) acc)) (the (Array String) []) hdrs)))