diff --git a/deps.edn b/deps.edn index e47e3d5..04c7890 100644 --- a/deps.edn +++ b/deps.edn @@ -14,7 +14,6 @@ :paths ["src" "resources"] :deps {org.clojure/clojure {:mvn/version "1.12.0-alpha1"} - com.github.strojure/zmap {:mvn/version "1.3.26"} io.helidon.http/helidon-http {:mvn/version "4.0.1"} io.helidon.webserver/helidon-webserver {:mvn/version "4.0.2"} io.helidon.webserver/helidon-webserver-websocket {:mvn/version "4.0.2"} diff --git a/src/s_exp/hirundo/http/header.clj b/src/s_exp/hirundo/http/header.clj deleted file mode 100644 index fbc9c24..0000000 --- a/src/s_exp/hirundo/http/header.clj +++ /dev/null @@ -1,146 +0,0 @@ -(ns s-exp.hirundo.http.header - (:import (clojure.lang - IEditableCollection - IFn - IKVReduce - IPersistentMap - MapEntry - MapEquivalence - Util) - (io.helidon.http - Headers - Header - HeaderName - HeaderNames - HeaderValues) - (java.util Map))) - -(defn header-name ^HeaderName - [s] - (HeaderNames/createFromLowercase s)) - -(defn header->value* - ([^Headers header header-name] - (header->value* header header-name nil)) - ([^Headers header - ^HeaderName header-name not-found] - (-> header - (.value header-name) - (.orElse not-found)))) - -(defn header->value - ([^Headers h k] - (header->value h k nil)) - ([^Headers h k not-found] - (header->value* h - (header-name k) - not-found))) - -(defn kv->header [^HeaderName header-name ^String v] - (HeaderValues/create header-name v)) - -(defn ring-headers* - [^Headers headers] - (-> (reduce (fn [m ^Header h] - (assoc! m - (.lowerCase (.headerName h)) - (.value h))) - (transient {}) - headers) - persistent!)) - -(defprotocol RingHeaders - (^clojure.lang.APersistentMap ring-headers [_])) - -;; inspired by ring-undertow -(deftype HeaderMapProxy [^Headers headers - ^:volatile-mutable persistent-copy] - Map - (size [_] - (.size headers)) - - (get [_ k] - (header->value headers k)) - - MapEquivalence - - IFn - (invoke [_ k] - (header->value headers k)) - - (invoke [_this k not-found] - (header->value headers k not-found)) - - IPersistentMap - (valAt [_ k] - (header->value headers k)) - - (valAt [_ k not-found] - (header->value headers k not-found)) - - (entryAt [_ k] - (let [hn (header-name k)] - (when-let [v (header->value* headers hn)] - (MapEntry. (.lowerCase hn) v)))) - - (containsKey [_ k] - (.contains headers (header-name k))) - - (assoc [this k v] - (-> (ring-headers this) - (.assoc k v))) - - (assocEx [this k v] - (if (.containsKey this k) - (throw (Util/runtimeException "Key already present")) - (.assoc this k v))) - - (cons [this o] - (-> (ring-headers this) - (.cons o))) - - (without [this k] - (-> (ring-headers this) - (.without k))) - - (empty [_] - {}) - - (count [_] - (.size headers)) - - (seq [this] - (.seq (ring-headers this))) - - (equiv [this o] - (= o (ring-headers this))) - - (iterator [_] - (->> headers - (eduction (map (fn [^Header header] - (MapEntry. (.lowerCase (.headerName header)) - (.value header))))) - .iterator)) - - IKVReduce - (kvreduce [this f init] - (.kvreduce ^IKVReduce - (ring-headers this) - f - init)) - - IEditableCollection - (asTransient [this] - (transient (ring-headers this))) - - RingHeaders - (ring-headers - [_] - (or persistent-copy - (set! persistent-copy (ring-headers* headers)))) - - Object - (toString [_] - (.toString headers))) - - diff --git a/src/s_exp/hirundo/http/request.clj b/src/s_exp/hirundo/http/request.clj index 25ad37b..a583118 100644 --- a/src/s_exp/hirundo/http/request.clj +++ b/src/s_exp/hirundo/http/request.clj @@ -1,15 +1,19 @@ (ns s-exp.hirundo.http.request - (:require [clojure.string :as str] - [s-exp.hirundo.http.header :as h] - [strojure.zmap.core :as zmap]) + (:require [clojure.string :as str]) (:import (clojure.lang PersistentHashMap) (io.helidon.common.uri UriQuery UriPath) - (io.helidon.http HttpPrologue Headers) + (io.helidon.http HttpPrologue Headers Header) (io.helidon.webserver.http ServerRequest ServerResponse))) (defn ring-headers [^Headers headers] - (h/->HeaderMapProxy headers nil)) + (-> (reduce (fn [m ^Header h] + (assoc! m + (.lowerCase (.headerName h)) + (.value h))) + (transient {}) + headers) + persistent!)) (defn ring-method [^HttpPrologue prologue] (let [method (-> prologue .method .text)] @@ -46,14 +50,11 @@ body (let [content (.content server-request)] (when-not (.consumed content) (.inputStream content))) ring-request (-> (.asTransient PersistentHashMap/EMPTY) - ;; delayed - (.assoc :server-port (zmap/delay (.port (.localPeer server-request)))) - (.assoc :server-name (zmap/delay (.host (.localPeer server-request)))) - (.assoc :remote-addr (zmap/delay - (let [address ^java.net.InetSocketAddress (.address (.remotePeer server-request))] - (-> address .getAddress .getHostAddress)))) - (.assoc :ssl-client-cert (zmap/delay (some-> server-request .remotePeer .tlsCertificates (.orElse nil) first))) - ;; realized + (.assoc :server-port (.port (.localPeer server-request))) + (.assoc :server-name (.host (.localPeer server-request))) + (.assoc :remote-addr (let [address ^java.net.InetSocketAddress (.address (.remotePeer server-request))] + (-> address .getAddress .getHostAddress))) + (.assoc :ssl-client-cert (some-> server-request .remotePeer .tlsCertificates (.orElse nil) first)) (.assoc :uri (ring-path (.path server-request))) (.assoc :scheme (if (.isSecure server-request) :https :http)) (.assoc :protocol (ring-protocol (.prologue server-request))) @@ -65,4 +66,4 @@ ring-request (cond-> ring-request qs (.assoc :query-string (ring-query (.query server-request))) body (.assoc :body body))] - (zmap/wrap (.persistent ring-request)))) + (.persistent ring-request))) diff --git a/test/s_exp/hirundo_test.clj b/test/s_exp/hirundo_test.clj index e3560a9..abd6abf 100644 --- a/test/s_exp/hirundo_test.clj +++ b/test/s_exp/hirundo_test.clj @@ -34,6 +34,14 @@ (with-server {:http-handler (fn [req] {:status 201})} (is (-> (client/get *endpoint*) :status (= 201))))) +(deftest test-headers + (with-server {:http-handler (fn [req] + {:body (str (count (:headers req)))})} + (is (-> (client/get *endpoint*) :body (= "4")))) + (with-server {:http-handler (fn [req] + {:body (str (:headers req))})} + (is (-> (client/get *endpoint*) :status (= 200))))) + (deftest test-query-string (with-server {:http-handler (fn [req] {:body (:query-string req)})} (is (-> (client/get (str *endpoint* "?foo=bar")) :body (= "foo=bar")))) @@ -78,6 +86,11 @@ (with-server {:http-handler (fn [req] {:body (java.io.ByteArrayInputStream. (.getBytes "yes"))})} (is (-> (client/get *endpoint*) :body (= "yes"))))) +(deftest resp-map-decoding + (with-server {:http-handler (fn [req] + {:body (str (select-keys req [:something]))})} + (is (status-ok? (client/get (str *endpoint* "")))))) + (defn tls [] (let [b (doto (TlsConfig/builder) (.sslContext (ls/ssl-context "test/server.key" @@ -119,7 +132,7 @@ (defmacro with-ws-client [options & body] `(binding [*client* (wsc/connect (str (str/replace *endpoint* "http" "ws") "/ws") - ~@(into [] cat options))] + ~@(into [] cat options))] (try ~@body @@ -163,4 +176,3 @@ #"Not Found" (with-ws-client {:subprotocols ["foo"]})) "Incorrect subprotocols")))) -