Repository: ring-clojure/ring
Pull request #483 (2023-08-17 18:35:46)

Replace FileUpload 1.5 with FileUpload 2.0.0-M1
The Apache Commons FileUpload library has released 2.0.0-M1, the first milestone release of 2.0.0. In this version, the core package of the library no longer has a dependency on the Servlet API, which means we can eliminate this problematic dependency from Ring core, once there is a full release of FileUpload 2.0.0.

Milestone 2 should be along in a couple of weeks.


Patch:
diff --git a/ring-core/project.clj b/ring-core/project.clj
index 55e8028..ff0246b 100644
--- a/ring-core/project.clj
+++ b/ring-core/project.clj
@@ -7,14 +7,12 @@
   :dependencies [[org.clojure/clojure "1.7.0"]
                  [ring/ring-codec "1.2.0"]
                  [commons-io "2.13.0"]
-                 [commons-fileupload "1.5"]
+                 [org.apache.commons/commons-fileupload2-core "2.0.0-M1"]
                  [crypto-random "1.2.1"]
                  [crypto-equality "1.0.1"]]
   :aliases {"test-all" ["with-profile" "default:+1.8:+1.9:+1.10:+1.11" "test"]}
   :profiles
-  {:provided {:dependencies [[javax.servlet/servlet-api "2.5"]]}
-   :dev  {:dependencies [[clj-time "0.15.2"]
-                         [javax.servlet/servlet-api "2.5"]]}
+  {:dev  {:dependencies [[clj-time "0.15.2"]]}
    :1.8  {:dependencies [[org.clojure/clojure "1.8.0"]]}
    :1.9  {:dependencies [[org.clojure/clojure "1.9.0"]]}
    :1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]}
diff --git a/ring-core/src/ring/core/protocols.clj b/ring-core/src/ring/core/protocols.clj
index c3a68ff..4c4c30d 100644
--- a/ring-core/src/ring/core/protocols.clj
+++ b/ring-core/src/ring/core/protocols.clj
@@ -9,8 +9,7 @@
   "A protocol for writing data to the response body via an output stream."
   (write-body-to-stream [body response output-stream]
     "Write a value representing a response body to an output stream. The stream
-    will be closed after the value had been written. The stream may be written
-    asynchronously."))
+    will be closed after the value had been written."))
 
 (defn- ^Writer response-writer [response output-stream]
   (if-let [charset (response/get-charset response)]
diff --git a/ring-core/src/ring/middleware/multipart_params.clj b/ring-core/src/ring/middleware/multipart_params.clj
index 3f1fa7f..cb73b7f 100644
--- a/ring-core/src/ring/middleware/multipart_params.clj
+++ b/ring-core/src/ring/middleware/multipart_params.clj
@@ -11,11 +11,11 @@
             [ring.util.codec :refer [assoc-conj]]
             [ring.util.request :as req]
             [ring.util.parsing :as parsing])
-  (:import [org.apache.commons.fileupload
-            UploadContext
-            FileItemStream
-            FileUpload
-            FileUploadBase$FileUploadIOException
+  (:import [org.apache.commons.fileupload2.core
+            AbstractFileUpload
+            RequestContext
+            FileItemInput
+            FileUploadException
             ProgressListener]
            [org.apache.commons.io IOUtils]))
 
@@ -24,27 +24,28 @@
     (update [_ bytes-read content-length item-count]
       (progress-fn request bytes-read content-length item-count))))
 
-(defn- set-progress-listener [^FileUpload upload request progress-fn]
+(defn- set-progress-listener [^AbstractFileUpload upload request progress-fn]
   (when progress-fn
     (.setProgressListener upload (progress-listener request progress-fn))))
 
 (defn- file-upload [request {:keys [progress-fn max-file-size]}]
-  (doto (FileUpload.)
-    (.setFileSizeMax (or max-file-size -1))
+  (doto (proxy [AbstractFileUpload] [])
+    ;; There seems to be an off-by-one bug in FileUpload 2.0.0-M1 that requires
+    ;; us to increment the max-file-size option to get it to work correctly.
+    (.setFileSizeMax (if max-file-size (inc max-file-size) -1))
     (set-progress-listener request progress-fn)))
 
 (defn- multipart-form? [request]
   (= (req/content-type request) "multipart/form-data"))
 
-(defn- request-context ^UploadContext [request encoding]
-  (reify UploadContext
+(defn- request-context ^RequestContext [request encoding]
+  (reify RequestContext
     (getContentType [_]       (get-in request [:headers "content-type"]))
     (getContentLength [_]     (or (req/content-length request) -1))
-    (contentLength [_]        (or (req/content-length request) -1))
     (getCharacterEncoding [_] encoding)
     (getInputStream [_]       (:body request))))
 
-(defn- file-item-iterable [^FileUpload upload context]
+(defn- file-item-iterable [^AbstractFileUpload upload ^RequestContext context]
   (reify Iterable
     (iterator [_]
       (let [it (.getItemIterator upload context)]
@@ -52,18 +53,18 @@
           (hasNext [_] (.hasNext it))
           (next [_] (.next it)))))))
 
-(defn- parse-content-type-charset [^FileItemStream item]
+(defn- parse-content-type-charset [^FileItemInput item]
   (some->> (.getContentType item) parsing/find-content-type-charset))
 
-(defn- parse-file-item [^FileItemStream item store]
+(defn- parse-file-item [^FileItemInput item store]
   {:field? (.isFormField item)
    :name   (.getFieldName item)
    :value  (if (.isFormField item)
-             {:bytes    (IOUtils/toByteArray (.openStream item))
+             {:bytes    (IOUtils/toByteArray (.getInputStream item))
               :encoding (parse-content-type-charset item)}
              (store {:filename     (.getName item)
                      :content-type (.getContentType item)
-                     :stream       (.openStream item)}))})
+                     :stream       (.getInputStream item)}))})
 
 (defn- find-param [params name]
   (first (filter #(= name (:name %)) params)))
@@ -133,7 +134,7 @@
   ((try
      (let [request (requestf)]
        #(handlef request))
-     (catch FileUploadBase$FileUploadIOException _
+     (catch FileUploadException _
        errorf)
      (catch clojure.lang.ExceptionInfo _
        errorf))))
diff --git a/ring-jakarta-servlet/project.clj b/ring-jakarta-servlet/project.clj
deleted file mode 100644
index e468c9a..0000000
--- a/ring-jakarta-servlet/project.clj
+++ /dev/null
@@ -1,16 +0,0 @@
-(defproject ring/ring-jakarta-servlet "1.10.0"
-  :description "Ring Jakarta servlet utilities."
-  :url "https://github.com/ring-clojure/ring"
-  :scm {:dir ".."}
-  :license {:name "The MIT License"
-            :url "http://opensource.org/licenses/MIT"}
-  :dependencies [[org.clojure/clojure "1.7.0"]
-                 [ring/ring-core "1.10.0"]]
-  :aliases {"test-all" ["with-profile" "default:+1.8:+1.9:+1.10:+1.11" "test"]}
-  :profiles
-  {:provided {:dependencies [[jakarta.servlet/jakarta.servlet-api "5.0.0"]]}
-   :dev  {:dependencies [[jakarta.servlet/jakarta.servlet-api "5.0.0"]]}
-   :1.8  {:dependencies [[org.clojure/clojure "1.8.0"]]}
-   :1.9  {:dependencies [[org.clojure/clojure "1.9.0"]]}
-   :1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]}
-   :1.11 {:dependencies [[org.clojure/clojure "1.11.1"]]}})
diff --git a/ring-jakarta-servlet/src/ring/util/jakarta/servlet.clj b/ring-jakarta-servlet/src/ring/util/jakarta/servlet.clj
deleted file mode 100644
index 6888124..0000000
--- a/ring-jakarta-servlet/src/ring/util/jakarta/servlet.clj
+++ /dev/null
@@ -1,161 +0,0 @@
-(ns ring.util.jakarta.servlet
-  "Compatibility functions for turning a ring handler into a Java servlet."
-  (:require [clojure.string :as string]
-            [ring.core.protocols :as protocols])
-  (:import [java.util Locale]
-           [jakarta.servlet AsyncContext]
-           [jakarta.servlet.http
-            HttpServlet
-            HttpServletRequest
-            HttpServletResponse]))
-
-(defn- get-headers [^HttpServletRequest request]
-  (reduce
-   (fn [headers ^String name]
-     (assoc headers
-            (.toLowerCase name Locale/ENGLISH)
-            (->> (.getHeaders request name)
-                 (enumeration-seq)
-                 (string/join ","))))
-   {}
-   (enumeration-seq (.getHeaderNames request))))
-
-(defn- get-content-length [^HttpServletRequest request]
-  (let [length (.getContentLength request)]
-    (when (>= length 0) length)))
-
-(defn- get-client-cert [^HttpServletRequest request]
-  (first (.getAttribute request "jakarta.servlet.request.X509Certificate")))
-
-(defn build-request-map
-  "Create the request map from the HttpServletRequest object."
-  [^HttpServletRequest request]
-  {:server-port        (.getServerPort request)
-   :server-name        (.getServerName request)
-   :remote-addr        (.getRemoteAddr request)
-   :uri                (.getRequestURI request)
-   :query-string       (.getQueryString request)
-   :scheme             (keyword (.getScheme request))
-   :request-method     (keyword (.toLowerCase (.getMethod request) Locale/ENGLISH))
-   :protocol           (.getProtocol request)
-   :headers            (get-headers request)
-   :content-type       (.getContentType request)
-   :content-length     (get-content-length request)
-   :character-encoding (.getCharacterEncoding request)
-   :ssl-client-cert    (get-client-cert request)
-   :body               (.getInputStream request)})
-
-(defn merge-servlet-keys
-  "Associate servlet-specific keys with the request map for use with legacy
-  systems."
-  [request-map
-   ^HttpServlet servlet
-   ^HttpServletRequest request
-   ^HttpServletResponse response]
-  (merge request-map
-         {:servlet              servlet
-          :servlet-request      request
-          :servlet-response     response
-          :servlet-context      (.getServletContext servlet)
-          :servlet-context-path (.getContextPath request)}))
-
-(defn- set-headers [^HttpServletResponse response, headers]
-  (doseq [[key val-or-vals] headers]
-    (if (string? val-or-vals)
-      (.setHeader response key val-or-vals)
-      (doseq [val val-or-vals]
-        (.addHeader response key val))))
-  ; Some headers must be set through specific methods
-  (when-let [content-type (get headers "Content-Type")]
-    (.setContentType response content-type)))
-
-(defn- make-output-stream
-  [^HttpServletResponse response ^AsyncContext context]
-  (let [os (.getOutputStream response)]
-    (if (nil? context)
-      os
-      (proxy [java.io.FilterOutputStream] [os]
-        (write
-          ([b]         (.write os b))
-          ([b off len] (.write os b off len)))
-        (close []
-          (.close os)
-          (.complete context))))))
-
-(defn update-servlet-response
-  "Update the HttpServletResponse using a response map. Takes an optional
-  AsyncContext."
-  ([response response-map]
-   (update-servlet-response response nil response-map))
-  ([^HttpServletResponse response context response-map]
-   (let [{:keys [status headers body]} response-map]
-     (when (nil? response)
-       (throw (NullPointerException. "HttpServletResponse is nil")))
-     (when (nil? response-map)
-       (throw (NullPointerException. "Response map is nil")))
-     (when status
-       (.setStatus response status))
-     (set-headers response headers)
-     (let [output-stream (make-output-stream response context)]
-       (protocols/write-body-to-stream body response-map output-stream)))))
-
-(defn- make-blocking-service-method [handler]
-  (fn [servlet request response]
-    (-> request
-        (build-request-map)
-        (merge-servlet-keys servlet request response)
-        (handler)
-        (->> (update-servlet-response response)))))
-
-(defn- make-async-service-method [handler]
-  (fn [servlet ^HttpServletRequest request ^HttpServletResponse response]
-    (let [^AsyncContext context (.startAsync request)]
-      (handler
-       (-> request
-           (build-request-map)
-           (merge-servlet-keys servlet request response))
-       (fn [response-map]
-         (update-servlet-response response context response-map))
-       (fn [^Throwable exception]
-         (.sendError response 500 (.getMessage exception))
-         (.complete context))))))
-
-(defn make-service-method
-  "Turns a handler into a function that takes the same arguments and has the
-  same return value as the service method in the HttpServlet class."
-  ([handler]
-   (make-service-method handler {}))
-  ([handler options]
-   (if (:async? options)
-     (make-async-service-method handler)
-     (make-blocking-service-method handler))))
-
-(defn servlet
-  "Create a servlet from a Ring handler."
-  ([handler]
-   (servlet handler {}))
-  ([handler options]
-   (let [service-method (make-service-method handler options)]
-     (proxy [HttpServlet] []
-       (service [request response]
-         (service-method this request response))))))
-
-(defmacro defservice
-  "Defines a service method with an optional prefix suitable for being used by
-  genclass to compile a HttpServlet class.
-
-  For example:
-
-    (defservice my-handler)
-    (defservice \"my-prefix-\" my-handler)"
-  ([handler]
-   `(defservice "-" ~handler))
-  ([prefix handler]
-   (if (map? handler)
-     `(defservice "-" ~prefix ~handler)
-     `(defservice ~prefix ~handler {})))
-  ([prefix handler options]
-   `(let [service-method# (make-service-method ~handler ~options)]
-      (defn ~(symbol (str prefix "service"))
-        [servlet# request# response#]
-        (service-method# servlet# request# response#)))))
diff --git a/ring-jetty-adapter/checkouts/ring-jakarta-servlet b/ring-jetty-adapter/checkouts/ring-jakarta-servlet
deleted file mode 120000
index f84bafb..0000000
--- a/ring-jetty-adapter/checkouts/ring-jakarta-servlet
+++ /dev/null
@@ -1,1 +0,0 @@
-../../ring-jakarta-servlet/
\ No newline at end of file
diff --git a/ring-jetty-adapter/checkouts/ring-servlet b/ring-jetty-adapter/checkouts/ring-servlet
new file mode 120000
index 0000000..ea5ef4c
--- /dev/null
+++ b/ring-jetty-adapter/checkouts/ring-servlet
@@ -0,0 +1,1 @@
+../../ring-servlet
\ No newline at end of file
diff --git a/ring-jetty-adapter/project.clj b/ring-jetty-adapter/project.clj
index 2fe29a8..782ae5e 100644
--- a/ring-jetty-adapter/project.clj
+++ b/ring-jetty-adapter/project.clj
@@ -6,8 +6,8 @@
             :url "http://opensource.org/licenses/MIT"}
   :dependencies [[org.clojure/clojure "1.7.0"]
                  [ring/ring-core "1.10.0"]
-                 [ring/ring-jakarta-servlet "1.10.0"]
-                 [org.eclipse.jetty/jetty-server "11.0.15"]]
+                 [ring/ring-servlet "1.10.0"]
+                 [org.eclipse.jetty/jetty-server "9.4.51.v20230217"]]
   :aliases {"test-all" ["with-profile" "default:+1.8:+1.9:+1.10:+1.11" "test"]}
   :profiles
   {:dev  {:dependencies [[clj-http "3.12.3"]
diff --git a/ring-jetty-adapter/src/ring/adapter/jetty.clj b/ring-jetty-adapter/src/ring/adapter/jetty.clj
index 8e3b5f3..24e5f9a 100644
--- a/ring-jetty-adapter/src/ring/adapter/jetty.clj
+++ b/ring-jetty-adapter/src/ring/adapter/jetty.clj
@@ -2,7 +2,7 @@
   "A Ring adapter that uses the Jetty 9 embedded web server.
 
   Adapters are used to convert Ring handlers into running web servers."
-  (:require [ring.util.jakarta.servlet :as servlet])
+  (:require [ring.util.servlet :as servlet])
   (:import [org.eclipse.jetty.server
             Request
             Server
@@ -16,8 +16,8 @@
            [org.eclipse.jetty.util BlockingArrayQueue]
            [org.eclipse.jetty.util.thread ThreadPool QueuedThreadPool]
            [org.eclipse.jetty.util.ssl SslContextFactory$Server KeyStoreScanner]
-           [jakarta.servlet AsyncContext DispatcherType AsyncEvent AsyncListener]
-           [jakarta.servlet.http HttpServletRequest HttpServletResponse]))
+           [javax.servlet AsyncContext DispatcherType AsyncEvent AsyncListener]
+           [javax.servlet.http HttpServletRequest HttpServletResponse]))
 
 (defn- ^AbstractHandler proxy-handler [handler]
   (proxy [AbstractHandler] []
@@ -113,16 +113,13 @@
           (.addExcludeProtocols context-server protocols))))
     context-server))
 
-
 (defn- ^ServerConnector ssl-connector [^Server server options]
   (let [ssl-port     (options :ssl-port 443)
-        customizer   (doto (SecureRequestCustomizer.)
-                       (.setSniHostCheck (options :sni-host-check? true)))
         http-factory (HttpConnectionFactory.
                       (doto (http-config options)
                         (.setSecureScheme "https")
                         (.setSecurePort ssl-port)
-                        (.addCustomizer customizer)))
+                        (.addCustomizer (SecureRequestCustomizer.))))
         ssl-context  (ssl-context-factory options)
         ssl-factory  (SslConnectionFactory. ssl-context "http/1.1")]
     (when-let [scan-interval (options :keystore-scan-interval)]
@@ -178,7 +175,6 @@
   :ssl-port               - the SSL port to listen on (defaults to 443, implies
                             :ssl? is true)
   :ssl-context            - an optional SSLContext to use for SSL connections
-  :sni-host-check?        - use SNI to check the hostname (default true)
   :exclude-ciphers        - when :ssl? is true, additionally exclude these
                             cipher suites
   :exclude-protocols      - when :ssl? is true, additionally exclude these
diff --git a/ring-servlet/src/ring/util/servlet.clj b/ring-servlet/src/ring/util/servlet.clj
index 9579057..c7e6a9b 100644
--- a/ring-servlet/src/ring/util/servlet.clj
+++ b/ring-servlet/src/ring/util/servlet.clj
@@ -1,30 +1,37 @@
 (ns ring.util.servlet
   "Compatibility functions for turning a ring handler into a Java servlet."
-  (:require [clojure.string :as string]
+  (:require [clojure.java.io :as io]
+            [clojure.string :as string]
             [ring.core.protocols :as protocols])
-  (:import [java.util Locale]
+  (:import [java.io File InputStream FileInputStream]
+           [java.util Locale]
            [javax.servlet AsyncContext]
-           [javax.servlet.http
-            HttpServlet
-            HttpServletRequest
-            HttpServletResponse]))
+           [javax.servlet.http HttpServlet
+                               HttpServletRequest
+                               HttpServletResponse]))
 
-(defn- get-headers [^HttpServletRequest request]
+(defn- get-headers
+  "Creates a name/value map of all the request headers."
+  [^HttpServletRequest request]
   (reduce
-   (fn [headers ^String name]
-     (assoc headers
-            (.toLowerCase name Locale/ENGLISH)
-            (->> (.getHeaders request name)
-                 (enumeration-seq)
-                 (string/join ","))))
-   {}
-   (enumeration-seq (.getHeaderNames request))))
+    (fn [headers, ^String name]
+      (assoc headers
+        (.toLowerCase name Locale/ENGLISH)
+        (->> (.getHeaders request name)
+             (enumeration-seq)
+             (string/join ","))))
+    {}
+    (enumeration-seq (.getHeaderNames request))))
 
-(defn- get-content-length [^HttpServletRequest request]
+(defn- get-content-length
+  "Returns the content length, or nil if there is no content."
+  [^HttpServletRequest request]
   (let [length (.getContentLength request)]
-    (when (>= length 0) length)))
+    (if (>= length 0) length)))
 
-(defn- get-client-cert [^HttpServletRequest request]
+(defn- get-client-cert
+  "Returns the SSL client certificate of the request, if one exists."
+  [^HttpServletRequest request]
   (first (.getAttribute request "javax.servlet.request.X509Certificate")))
 
 (defn build-request-map
@@ -59,7 +66,9 @@
           :servlet-context      (.getServletContext servlet)
           :servlet-context-path (.getContextPath request)}))
 
-(defn- set-headers [^HttpServletResponse response, headers]
+(defn- set-headers
+  "Update a HttpServletResponse with a map of headers."
+  [^HttpServletResponse response, headers]
   (doseq [[key val-or-vals] headers]
     (if (string? val-or-vals)
       (.setHeader response key val-or-vals)
@@ -149,13 +158,13 @@
     (defservice my-handler)
     (defservice \"my-prefix-\" my-handler)"
   ([handler]
-   `(defservice "-" ~handler))
+     `(defservice "-" ~handler))
   ([prefix handler]
    (if (map? handler)
      `(defservice "-" ~prefix ~handler)
      `(defservice ~prefix ~handler {})))
   ([prefix handler options]
-   `(let [service-method# (make-service-method ~handler ~options)]
-      (defn ~(symbol (str prefix "service"))
-        [servlet# request# response#]
-        (service-method# servlet# request# response#)))))
+     `(let [service-method# (make-service-method ~handler ~options)]
+        (defn ~(symbol (str prefix "service"))
+          [servlet# request# response#]
+          (service-method# servlet# request# response#)))))


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 47b5fb6..218d245 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
         uses: actions/setup-java@v3
         with:
           distribution: 'zulu'
-          java-version: '11'
+          java-version: '8'
 
       - name: Install clojure tools
         uses: DeLaGuardo/setup-clojure@10.1
@@ -25,9 +25,5 @@ jobs:
           key: cljdeps-${{ hashFiles('project.clj', 'ring-*/project.clj') }}
           restore-keys: cljdeps-
 
-      - name: Install undeployed Jakarta servlet project locally
-        run: lein install
-        working-directory: ./ring-jakarta-servlet
-
       - name: Run tests
         run: lein sub test-all
diff --git a/ring-core/test/ring/middleware/test/multipart_params.clj b/ring-core/test/ring/middleware/test/multipart_params.clj
index fca1989..577e35f 100644
--- a/ring-core/test/ring/middleware/test/multipart_params.clj
+++ b/ring-core/test/ring/middleware/test/multipart_params.clj
@@ -192,7 +192,7 @@
         handler       (constantly {:status 200, :headers {}, :body "OK"})
         handler-async (fn [_ respond _]
                         (respond {:status 200, :headers {}, :body "OK"}))]
-    (is (thrown? org.apache.commons.fileupload.FileUploadBase$FileUploadIOException
+    (is (thrown? org.apache.commons.fileupload2.core.FileUploadException
                  (multipart-params-request
                   {:headers headers, :body (string-input-stream form-body)}
                   {:max-file-size 6})))
diff --git a/ring-jakarta-servlet/test/ring/util/jakarta/test/servlet.clj b/ring-jakarta-servlet/test/ring/util/jakarta/test/servlet.clj
deleted file mode 100644
index 8956f08..0000000
--- a/ring-jakarta-servlet/test/ring/util/jakarta/test/servlet.clj
+++ /dev/null
@@ -1,220 +0,0 @@
-(ns ring.util.jakarta.test.servlet
-  (:require [clojure.test :refer :all]
-            [ring.util.jakarta.servlet :refer :all]
-            [ring.core.protocols :as proto])
-  (:import [java.util Locale]))
-
-(defmacro ^:private with-locale [locale & body]
-  `(let [old-locale# (Locale/getDefault)]
-     (try (Locale/setDefault ~locale)
-          (do ~@body)
-          (finally (Locale/setDefault old-locale#)))))
-
-(defn- enumeration [coll]
-  (let [e (atom coll)]
-    (proxy [java.util.Enumeration] []
-      (hasMoreElements [] (not (empty? @e)))
-      (nextElement [] (let [f (first @e)] (swap! e rest) f)))))
-
-(defn- async-context [completed]
-  (proxy [jakarta.servlet.AsyncContext] []
-    (complete [] (reset! completed true))))
-
-(defn- servlet-request [request]
-  (let [attributes {"jakarta.servlet.request.X509Certificate"
-                    [(request :ssl-client-cert)]}]
-    (proxy [jakarta.servlet.http.HttpServletRequest] []
-      (getServerPort [] (request :server-port))
-      (getServerName [] (request :server-name))
-      (getRemoteAddr [] (request :remote-addr))
-      (getRequestURI [] (request :uri))
-      (getQueryString [] (request :query-string))
-      (getContextPath [] (request :servlet-context-path))
-      (getScheme [] (name (request :scheme)))
-      (getMethod [] (-> request :request-method name .toUpperCase))
-      (getProtocol [] (request :protocol))
-      (getHeaderNames [] (enumeration (keys (request :headers))))
-      (getHeaders [name] (enumeration (get-in request [:headers name])))
-      (getContentType [] (request :content-type))
-      (getContentLength [] (or (request :content-length) -1))
-      (getCharacterEncoding [] (request :character-encoding))
-      (getAttribute [k] (attributes k))
-      (getInputStream [] (request :body))
-      (startAsync [] (async-context (request :completed))))))
-
-(defn- servlet-response [response]
-  (let [output-stream (java.io.ByteArrayOutputStream.)]
-    (swap! response assoc :body output-stream)
-    (proxy [jakarta.servlet.http.HttpServletResponse] []
-      (getOutputStream []
-        (proxy [jakarta.servlet.ServletOutputStream] []
-          (write
-            ([b] (.write output-stream b))
-            ([b off len] (.write output-stream b off len)))))
-      (setStatus [status]
-        (swap! response assoc :status status))
-      (setHeader [name value]
-        (swap! response assoc-in [:headers name] value))
-      (setCharacterEncoding [value])
-      (setContentType [value]
-        (swap! response assoc :content-type value)))))
-
-(defn- servlet-config []
-  (proxy [jakarta.servlet.ServletConfig] []
-    (getServletContext [] nil)))
-
-(defn- run-servlet
-  ([handler request response]
-   (run-servlet handler request response {}))
-  ([handler request response options]
-   (doto (servlet handler options)
-     (.init (servlet-config))
-     (.service (servlet-request request)
-               (servlet-response response)))))
-
-(deftest make-service-method-test
-  (let [handler (constantly {:status  201
-                             :headers {}})
-        method  (make-service-method handler)
-        servlet (doto (proxy [jakarta.servlet.http.HttpServlet] [])
-                  (.init (servlet-config)))
-        request {:server-port    8080
-                 :server-name    "foobar"
-                 :remote-addr    "127.0.0.1"
-                 :uri            "/foo"
-                 :scheme         :http
-                 :request-method :get
-                 :protocol       "HTTP/1.1"
-                 :headers        {}}
-        response (atom {})]
-    (method servlet (servlet-request request) (servlet-response response))
-    (is (= (@response :status) 201))))
-
-(deftest servlet-test
-  (let [body (proxy [jakarta.servlet.ServletInputStream] [])
-        cert (proxy [java.security.cert.X509Certificate] [])
-        request {:server-port    8080
-                 :server-name    "foobar"
-                 :remote-addr    "127.0.0.1"
-                 :uri            "/foo"
-                 :query-string   "a=b"
-                 :scheme         :http
-                 :request-method :get
-                 :protocol       "HTTP/1.1"
-                 :headers        {"X-Client" ["Foo", "Bar"]
-                                  "X-Server" ["Baz"]
-                                  "X-Capital-I" ["Qux"]}
-                 :content-type   "text/plain"
-                 :content-length 10
-                 :character-encoding "UTF-8"
-                 :servlet-context-path "/foo"
-                 :ssl-client-cert cert
-                 :body            body}
-          response (atom {})]
-    (letfn [(handler [r]
-             (are [k v] (= (r k) v)
-               :server-port    8080
-               :server-name    "foobar"
-               :remote-addr    "127.0.0.1"
-               :uri            "/foo"
-               :query-string   "a=b"
-               :scheme         :http
-               :request-method :get
-               :protocol       "HTTP/1.1"
-               :headers        {"x-client" "Foo,Bar"
-                                "x-server" "Baz"
-                                "x-capital-i" "Qux"}
-               :content-type   "text/plain"
-               :content-length 10
-               :character-encoding "UTF-8"
-               :servlet-context-path "/foo"
-               :ssl-client-cert cert
-               :body            body)
-             {:status 200, :headers {}})]
-      (testing "request"
-        (run-servlet handler request response))
-      (testing "mapping request header names to lower case"
-        (with-locale (Locale. "tr")
-          (run-servlet handler request response))))
-    (testing "response"
-      (letfn [(handler [r]
-               {:status  200
-                :headers {"Content-Type" "text/plain"
-                          "X-Server" "Bar"}
-                :body    "Hello World"})]
-        (run-servlet handler request response)
-        (is (= (@response :status) 200))
-        (is (= (@response :content-type) "text/plain"))
-        (is (= (get-in @response [:headers "X-Server"]) "Bar"))
-        (is (= (.toString (@response :body)) "Hello World"))))))
-
-(deftest servlet-cps-test
-  (let [handler  (fn [_ respond _]
-                   (respond {:status  200
-                             :headers {"Content-Type" "text/plain"}
-                             :body    "Hello World"}))
-        request  {:completed      (atom false)
-                  :server-port    8080
-                  :server-name    "foobar"
-                  :remote-addr    "127.0.0.1"
-                  :uri            "/foo"
-                  :scheme         :http
-                  :request-method :get
-                  :protocol       "HTTP/1.1"
-                  :headers        {}
-                  :body           nil}
-        response (atom {})]
-    (run-servlet handler request response {:async? true})
-    (is (= @(:completed request) true))
-    (is (= (@response :status) 200))
-    (is (= (@response :content-type) "text/plain"))
-    (is (= (.toString (@response :body)) "Hello World"))))
-
-(defn- defservice-test* [service]
-  (let [body     (proxy [jakarta.servlet.ServletInputStream] [])
-        servlet  (doto (proxy [jakarta.servlet.http.HttpServlet] [])
-                   (.init (servlet-config)))
-        request  {:server-port    8080
-                  :server-name    "foobar"
-                  :remote-addr    "127.0.0.1"
-                  :uri            "/foo"
-                  :query-string   ""
-                  :scheme         :http
-                  :request-method :get
-                  :headers        {}
-                  :content-type   "text/plain"
-                  :content-length 10
-                  :character-encoding "UTF-8"
-                  :body           body}
-        response (atom {})]
-    (service servlet
-             (servlet-request request)
-             (servlet-response response))
-    (is (= (@response :status) 200))
-    (is (= (get-in @response [:headers "Content-Type" ]) "text/plain"))
-    (is (= (.toString (@response :body)) "Hello World"))))
-
-(defn- service-handler [_]
-  {:status  200
-   :headers {"Content-Type" "text/plain"}
-   :body    "Hello World"})
-
-(defservice "foo-" service-handler)
-(defservice service-handler {})
-
-(deftest defservice-test
-  (defservice-test* foo-service)
-  (defservice-test* -service))
-
-(deftest make-output-stream-test
-  (let [response (atom {})]
-    (update-servlet-response
-     (servlet-response response)
-     (async-context (atom false))
-     {:status  200
-      :headers {}
-      :body    (reify proto/StreamableResponseBody
-                 (write-body-to-stream [_ _ os]
-                   (.write os (int \h))
-                   (.write os (.getBytes "ello"))))})
-    (is (= "hello" (.toString (:body @response))))))
diff --git a/ring-jetty-adapter/test/ring/adapter/test/jetty.clj b/ring-jetty-adapter/test/ring/adapter/test/jetty.clj
index 8ffa2aa..df0c02e 100644
--- a/ring-jetty-adapter/test/ring/adapter/test/jetty.clj
+++ b/ring-jetty-adapter/test/ring/adapter/test/jetty.clj
@@ -82,13 +82,12 @@
   (doto (KeyStore/getInstance (KeyStore/getDefaultType)) (.load nil)))
 
 (def test-ssl-options
-  {:port            test-port
-   :ssl?            true
-   :ssl-port        test-ssl-port
-   :keystore        nil-keystore
-   :key-password    "hunter2"
-   :join?           false
-   :sni-host-check? false})
+  {:port         test-port
+   :ssl?         true
+   :ssl-port     test-ssl-port
+   :keystore     nil-keystore
+   :key-password "hunter2"
+   :join?        false})
 
 (deftest test-run-jetty
   (testing "HTTP server"
@@ -103,8 +102,7 @@
     (with-server hello-world {:port test-port
                               :ssl-port test-ssl-port
                               :keystore "test/keystore.jks"
-                              :key-password "password"
-                              :sni-host-check? false}
+                              :key-password "password"}
       (let [response (http/get test-ssl-url {:insecure? true})]
         (is (= (:status response) 200))
         (is (= (:body response) "Hello World")))))
@@ -124,8 +122,7 @@
                               :port test-port
                               :ssl-port test-ssl-port
                               :keystore "test/keystore.jks"
-                              :key-password "password"
-                              :sni-host-check? false}
+                              :key-password "password"}
       (let [response (http/get test-ssl-url {:insecure? true})]
         (is (= (:status response) 200))
         (is (= (:body response) "Hello World")))
@@ -138,8 +135,7 @@
                                       :key-password "password"
                                       :port test-port
                                       :ssl? true
-                                      :ssl-port test-ssl-port
-                                      :sni-host-check? false}
+                                      :ssl-port test-ssl-port}
       (is (thrown? java.io.IOException
                    (http/get test-ssl-url {:insecure? true}))
           "missing client certs will cause an exception")
@@ -157,8 +153,7 @@
                                       :key-password "password"
                                       :port test-port
                                       :ssl? true
-                                      :ssl-port test-ssl-port
-                                      :sni-host-check? false}
+                                      :ssl-port test-ssl-port}
       (let [response (http/get test-ssl-url {:insecure? true
                                              :throw-exceptions false})]
         (is (= 403 (:status response))
@@ -174,8 +169,7 @@
   (testing "HTTPS server using :ssl-context"
     (with-server hello-world {:port test-port
                               :ssl-port test-ssl-port
-                              :ssl-context (ssl-context)
-                              :sni-host-check? false}
+                              :ssl-context (ssl-context)}
       (let [response (http/get test-ssl-url {:insecure? true})]
         (is (= (:status response) 200))
         (is (= (:body response) "Hello World")))))
@@ -185,8 +179,7 @@
                                       :ssl-context (ssl-context)
                                       :port test-port
                                       :ssl? true
-                                      :ssl-port test-ssl-port
-                                      :sni-host-check? false}
+                                      :ssl-port test-ssl-port}
       (is (thrown? java.io.IOException
                    (http/get test-ssl-url {:insecure? true}))
           "missing client certs will cause an exception")
@@ -203,8 +196,7 @@
                                       :ssl-context (ssl-context)
                                       :port test-port
                                       :ssl? true
-                                      :ssl-port test-ssl-port
-                                      :sni-host-check? false}
+                                      :ssl-port test-ssl-port}
       (let [response (http/get test-ssl-url {:insecure? true
                                              :throw-exceptions false})]
         (is (= 403 (:status response))
@@ -251,8 +243,7 @@
                                          :keystore "test/keystore.jks"
                                          :key-password "password"
                                          :join? false
-                                         :max-idle-time 5000
-                                         :sni-host-check? false})
+                                         :max-idle-time 5000})
           connectors (. server getConnectors)]
       (is (= 5000 (. (first connectors) getIdleTimeout)))
       (is (= 5000 (. (second connectors) getIdleTimeout)))
@@ -263,7 +254,6 @@
                                          :ssl-port test-ssl-port
                                          :keystore "test/keystore.jks"
                                          :key-password "password"
-                                         :sni-host-check? false
                                          :join? false})
           connectors (. server getConnectors)]
       (is (= 200000 (. (first connectors) getIdleTimeout)))
@@ -614,17 +604,16 @@
   (swap! call-count inc)
   (raise (ex-info "unhandled exception" {})))
 
-(deftest broken-handler-test
-  (testing "broken handler is only called once"
-    (reset! call-count 0)
-    (with-server broken-handler {:port test-port}
-      (try (http/get test-url)
-           (catch Exception _ nil))
-      (is (= 1 @call-count))))
-
-  (testing "broken async handler is only called once"
-    (reset! call-count 0)
-    (with-server broken-handler-cps {:async? true :port test-port}
-      (try (http/get test-url)
-           (catch Exception _ nil))
-      (is (= 1 @call-count)))))
+(testing "broken handler is only called once"
+  (reset! call-count 0)
+  (with-server broken-handler {:port test-port}
+    (try (http/get test-url)
+      (catch Exception _ nil))
+    (is (= 1 @call-count))))
+
+(testing "broken async handler is only called once"
+  (reset! call-count 0)
+  (with-server broken-handler-cps {:async? true :port test-port}
+    (try (http/get test-url)
+      (catch Exception _ nil))
+    (is (= 1 @call-count))))