Java http insecure context (#994)

* Add support for creating insecure context.

* Add BABASHKA_FEATURE_JAVA_NET_HTTP flag.

* Clean up java.net.http tests
This commit is contained in:
Michael Glaesemann 2021-08-31 10:37:11 -05:00 committed by GitHub
parent b71278cc68
commit 125e227976
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 278 additions and 228 deletions

View file

@ -20,6 +20,7 @@ ARG BABASHKA_LEAN=
ARG BABASHKA_MUSL=
ARG BABASHKA_FEATURE_CORE_ASYNC=
ARG BABASHKA_FEATURE_CSV=
ARG BABASHKA_FEATURE_JAVA_NET_HTTP=
ARG BABASHKA_FEATURE_JAVA_NIO=
ARG BABASHKA_FEATURE_JAVA_TIME=
ARG BABAHSKA_FEATURE_TRANSIT=
@ -37,6 +38,7 @@ ARG BABASHKA_STATIC=
ENV BABASHKA_LEAN=$BABASHKA_LEAN
ENV BABASHKA_FEATURE_CORE_ASYNC=$BABASHKA_FEATURE_CORE_ASYNC
ENV BABASHKA_FEATURE_CSV=$BABASHKA_FEATURE_CSV
ENV BABASHKA_FEATURE_JAVA_NET_HTTP=$BABASHKA_FEATURE_JAVA_NET_HTTP
ENV BABASHKA_FEATURE_JAVA_NIO=$BABASHKA_FEATURE_JAVA_NIO
ENV BABASHKA_FEATURE_JAVA_TIME=$BABASHKA_FEATURE_JAVA_TIME
ENV BABAHSKA_FEATURE_TRANSIT=$BABAHSKA_FEATURE_TRANSIT

View file

@ -95,6 +95,7 @@ Babashka supports the following feature flags:
|--------|----------------------------------------------|----------|
| `BABASHKA_FEATURE_CORE_ASYNC` | Includes the [clojure.core.async](https://github.com/clojure/core.async) library | `true` |
| `BABASHKA_FEATURE_CSV` | Includes the [clojure.data.csv](https://github.com/clojure/data.csv) library | `true` |
| `BABASHKA_FEATURE_JAVA_NET_HTTP` | Includes commonly used classes from the `java.net.http` package | `true` |
| `BABASHKA_FEATURE_JAVA_NIO` | Includes commonly used classes from the `java.nio` package | `true` |
| `BABASHKA_FEATURE_JAVA_TIME` | Includes commonly used classes from the `java.time` package | `true` |
| `BABASHKA_FEATURE_TRANSIT` | Includes the [transit-clj](https://github.com/cognitect/transit-clj) library | `true` |

View file

@ -86,6 +86,7 @@ then
export BABASHKA_FEATURE_CSV="${BABASHKA_FEATURE_CSV:-false}"
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
export BABASHKA_FEATURE_JAVA_TIME="${BABASHKA_FEATURE_JAVA_TIME:-false}"
export BABASHKA_FEATURE_JAVA_NET_HTTP="${BABASHKA_FEATURE_JAVA_NET_HTTP:-false}"
export BABASHKA_FEATURE_JAVA_NIO="${BABASHKA_FEATURE_JAVA_NIO:-false}"
export BABASHKA_FEATURE_HTTPKIT_CLIENT="${BABASHKA_FEATURE_HTTPKIT_CLIENT:-false}"
export BABASHKA_FEATURE_HTTPKIT_SERVER="${BABASHKA_FEATURE_HTTPKIT_SERVER:-false}"

View file

@ -18,6 +18,7 @@ then
export BABASHKA_FEATURE_CSV="${BABASHKA_FEATURE_CSV:-false}"
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
export BABASHKA_FEATURE_JAVA_TIME="${BABASHKA_FEATURE_JAVA_TIME:-false}"
export BABASHKA_FEATURE_JAVA_NET_HTTP="${BABASHKA_FEATURE_JAVA_NET_HTTP:-false}"
export BABASHKA_FEATURE_JAVA_NIO="${BABASHKA_FEATURE_JAVA_NIO:-false}"
export BABASHKA_FEATURE_HTTPKIT_CLIENT="${BABASHKA_FEATURE_HTTPKIT_CLIENT:-false}"
export BABASHKA_FEATURE_HTTPKIT_SERVER="${BABASHKA_FEATURE_HTTPKIT_SERVER:-false}"

View file

@ -158,19 +158,12 @@
java.math.BigInteger
java.math.MathContext
java.math.RoundingMode
java.net.Authenticator
java.net.ConnectException
java.net.CookieHandler
java.net.CookieManager
java.net.CookieStore
java.net.DatagramSocket
java.net.DatagramPacket
java.net.HttpCookie
java.net.HttpURLConnection
java.net.InetAddress
java.net.InetSocketAddress
java.net.PasswordAuthentication
java.net.ProxySelector
java.net.ServerSocket
java.net.Socket
java.net.SocketException
@ -180,28 +173,41 @@
java.net.URLEncoder
java.net.URLDecoder
;; java.net.http
jdk.internal.net.http.HttpClientBuilderImpl
jdk.internal.net.http.HttpClientFacade
jdk.internal.net.http.HttpRequestBuilderImpl
jdk.internal.net.http.HttpResponseImpl
jdk.internal.net.http.common.MinimalFuture
jdk.internal.net.http.websocket.BuilderImpl
jdk.internal.net.http.websocket.WebSocketImpl
java.net.http.HttpClient
java.net.http.HttpClient$Builder
java.net.http.HttpClient$Redirect
java.net.http.HttpClient$Version
java.net.http.HttpHeaders
java.net.http.HttpRequest
java.net.http.HttpRequest$BodyPublisher
java.net.http.HttpRequest$BodyPublishers
java.net.http.HttpRequest$Builder
java.net.http.HttpResponse
java.net.http.HttpResponse$BodyHandler
java.net.http.HttpResponse$BodyHandlers
java.net.http.WebSocket
java.net.http.WebSocket$Builder
java.net.http.WebSocket$Listener
~@(when features/java-net-http?
'[java.net.Authenticator
java.net.CookieHandler
java.net.CookieManager
java.net.CookieStore
java.net.HttpCookie
java.net.PasswordAuthentication
java.net.ProxySelector
java.net.http.HttpClient
java.net.http.HttpClient$Builder
java.net.http.HttpClient$Redirect
java.net.http.HttpClient$Version
java.net.http.HttpHeaders
java.net.http.HttpRequest
java.net.http.HttpRequest$BodyPublisher
java.net.http.HttpRequest$BodyPublishers
java.net.http.HttpRequest$Builder
java.net.http.HttpResponse
java.net.http.HttpResponse$BodyHandler
java.net.http.HttpResponse$BodyHandlers
java.net.http.WebSocket
java.net.http.WebSocket$Builder
java.net.http.WebSocket$Listener
java.security.cert.X509Certificate
javax.net.ssl.SSLContext
javax.net.ssl.SSLParameters
javax.net.ssl.TrustManager
javax.net.ssl.X509TrustManager
jdk.internal.net.http.HttpClientBuilderImpl
jdk.internal.net.http.HttpClientFacade
jdk.internal.net.http.HttpRequestBuilderImpl
jdk.internal.net.http.HttpResponseImpl
jdk.internal.net.http.common.MinimalFuture
jdk.internal.net.http.websocket.BuilderImpl
jdk.internal.net.http.websocket.WebSocketImpl])
~@(when features/java-nio?
'[java.nio.ByteBuffer
java.nio.ByteOrder
@ -312,8 +318,6 @@
java.util.zip.ZipInputStream
java.util.zip.ZipOutputStream
java.util.zip.ZipEntry
javax.net.ssl.SSLContext
javax.net.ssl.SSLParameters
~(symbol "[B")
~(symbol "[I")
~(symbol "[Ljava.lang.Object;")

View file

@ -8,6 +8,7 @@
(def csv? (not= "false" (System/getenv "BABASHKA_FEATURE_CSV")))
(def transit? (not= "false" (System/getenv "BABASHKA_FEATURE_TRANSIT")))
(def java-time? (not= "false" (System/getenv "BABASHKA_FEATURE_JAVA_TIME")))
(def java-net-http? (not= "false" (System/getenv "BABASHKA_FEATURE_JAVA_NET_HTTP")))
(def java-nio? (not= "false" (System/getenv "BABASHKA_FEATURE_JAVA_NIO")))
(def httpkit-client? (not= "false" (System/getenv "BABASHKA_FEATURE_HTTPKIT_CLIENT")))
(def httpkit-server? (not= "false" (System/getenv "BABASHKA_FEATURE_HTTPKIT_SERVER")))

View file

@ -168,4 +168,9 @@
{get [[this]]}
java.lang.Comparable
{compareTo [[this other]]}}))
{compareTo [[this other]]}
javax.net.ssl.X509TrustManager
{checkClientTrusted [[this chain auth-type]]
checkServerTrusted [[this chain auth-type]]
getAcceptedIssuers [[this]]}}))

View file

@ -1,4 +1,4 @@
(ns babashka.java-http-client-test
(ns babashka.java-net-http-test
(:require
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
@ -9,7 +9,9 @@
(defn bb [expr]
(edn/read-string (apply test-utils/bb nil [(str expr)])))
(deftest java-http-client-test
;; HttpClient
(deftest send-test
(is (= [200 true]
(bb
'(do (ns net
@ -24,48 +26,91 @@
(.GET)
(.build)))
(def client
(-> (HttpClient/newBuilder)
(.build)))
(def client (HttpClient/newHttpClient))
(def resp (.send client req (HttpResponse$BodyHandlers/ofString)))
[(.statusCode resp) (string? (.body resp))])))))
(def res (.send client req (HttpResponse$BodyHandlers/ofString)))
[(.statusCode res) (string? (.body res))])))))
(deftest redirect-test
(let [redirect-prog
(fn [redirect-kind]
(str/replace (str '(do
(ns net
(:import
(java.net.http HttpClient
HttpClient$Redirect
HttpRequest
HttpRequest$BodyPublishers
HttpResponse$BodyHandlers)
(java.net URI)))
(defn log [x] (.println System/err x))
(let [req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com"))
(.GET)
(.timeout (java.time.Duration/ofSeconds 5))
(.build))
client (-> (HttpClient/newBuilder)
(.followRedirects :redirect/kind)
(.build))
handler (HttpResponse$BodyHandlers/discarding)]
(.statusCode (.send client req handler)))))
":redirect/kind"
(case redirect-kind
:never
"HttpClient$Redirect/NEVER"
:always
"HttpClient$Redirect/ALWAYS")))]
;; TODO: make graalvm repro of never-ending request with redirect always on linux aarch64 (+ musl?)
(when-not (and (= "aarch64" (System/getenv "BABASHKA_ARCH"))
(= "linux" (System/getenv "BABASHKA_PLATFORM")))
(println "Testing redirect always")
(is (= 200 (bb (redirect-prog :always)))))
(println "Testing redirect never")
(is (= 302 (bb (redirect-prog :never))))))
(deftest send-async-test
(is (= [200 true]
(bb
'(do
(ns net
(:import
(java.net URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)
(java.util.function Function)))
(let [client (HttpClient/newHttpClient)
req (-> (HttpRequest/newBuilder (URI. "https://www.clojure.org"))
(.GET)
(.build))]
(-> (.sendAsync client req (HttpResponse$BodyHandlers/ofString))
(.thenApply (reify Function (apply [_ res] [(.statusCode res) (string? (.body res))])))
(deref))))))))
;; HttpClient options
(deftest authenticator-test
(is (= [401 200]
(bb
'(do
(ns net
(:import
(java.net Authenticator
PasswordAuthentication
URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(let [no-auth-client (HttpClient/newHttpClient)
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/basic-auth"))
(.build))
handler (HttpResponse$BodyHandlers/discarding)
no-auth-res (.send no-auth-client req handler)
authenticator (proxy [Authenticator] []
(getPasswordAuthentication []
(PasswordAuthentication. "postman" (char-array "password"))))
auth-client (-> (HttpClient/newBuilder)
(.authenticator authenticator)
(.build))
auth-res (.send auth-client req handler)]
[(.statusCode no-auth-res) (.statusCode auth-res)]))))))
(deftest cookie-test
(is (= []
(bb '(do (ns net
(:import [java.net CookieManager]))
(-> (CookieManager.)
(.getCookieStore)
(.getCookies))))))
(is (= "www.postman-echo.com"
(bb '(do
(ns net
(:import
(java.net CookieManager
URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(let [client (-> (HttpClient/newBuilder)
(.cookieHandler (CookieManager.))
(.build))
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/get"))
(.GET)
(.build))]
(.send client req (HttpResponse$BodyHandlers/discarding))
(-> client
(.cookieHandler)
(.get)
(.getCookieStore)
(.getCookies)
first
(.getDomain))))))))
(deftest connect-timeout-test
(is (= "java.net.http.HttpConnectTimeoutException"
@ -94,7 +139,7 @@
:type
name)))))))))
(deftest executor
(deftest executor-test
(is (= 200
(bb
'(do
@ -105,6 +150,7 @@
HttpRequest
HttpResponse$BodyHandlers)
(java.util.concurrent Executors)))
(let [uri (URI. "https://www.postman-echo.com/get")
req (-> (HttpRequest/newBuilder uri)
(.GET)
@ -115,7 +161,7 @@
res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res)))))))
(deftest client-proxy
(deftest proxy-test
(is (= true
(bb
'(do
@ -123,6 +169,7 @@
(:import
(java.net ProxySelector)
(java.net.http HttpClient)))
(let [bespoke-proxy (proxy [ProxySelector] []
(connectFailed [_ _ _])
(select [_ _]))
@ -142,6 +189,7 @@
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(let [uri (URI. "https://www.postman-echo.com/get")
req (-> (HttpRequest/newBuilder uri)
(.build))
@ -151,50 +199,135 @@
res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res)))))))
(deftest ssl-test
(is (= 200
(bb
'(do
(ns net
(:import
(java.net URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)
(javax.net.ssl SSLContext
SSLParameters)))
(let [uri (URI. "https://www.postman-echo.com/get")
req (-> (HttpRequest/newBuilder uri)
(.build))
ssl-context (doto (SSLContext/getInstance "TLS")
(.init nil nil nil))
client (-> (HttpClient/newBuilder)
(.sslContext ssl-context)
(.build))
res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res)))))))
(deftest redirect-test
(let [redirect-prog
(fn [redirect-kind]
(str/replace (str '(do
(ns net
(:import
(java.net.http HttpClient
HttpClient$Redirect
HttpRequest
HttpRequest$BodyPublishers
HttpResponse$BodyHandlers)
(java.net URI)))
(deftest send-async-test
(is (= 200
(bb
'(do
(ns net
(:import
(java.net ProxySelector
URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)
(java.time Duration)
(java.util.function Function)))
(let [client (-> (HttpClient/newBuilder)
(.build))
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/get"))
(.GET)
(.build))]
(-> (.sendAsync client req (HttpResponse$BodyHandlers/discarding))
(.thenApply (reify Function (apply [_ t] (.statusCode t))))
(deref))))))))
(defn log [x] (.println System/err x))
(let [req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com"))
(.GET)
(.timeout (java.time.Duration/ofSeconds 5))
(.build))
client (-> (HttpClient/newBuilder)
(.followRedirects :redirect/kind)
(.build))
handler (HttpResponse$BodyHandlers/discarding)]
(.statusCode (.send client req handler)))))
":redirect/kind"
(case redirect-kind
:never
"HttpClient$Redirect/NEVER"
:always
"HttpClient$Redirect/ALWAYS")))]
;; TODO: make graalvm repro of never-ending request with redirect always on linux aarch64 (+ musl?)
(when-not (and (= "aarch64" (System/getenv "BABASHKA_ARCH"))
(= "linux" (System/getenv "BABASHKA_PLATFORM")))
(println "Testing redirect always")
(is (= 200 (bb (redirect-prog :always)))))
(println "Testing redirect never")
(is (= 302 (bb (redirect-prog :never))))))
(deftest ssl-context-test
;; TODO: investigate aarch64 issue
(when-not
(and (= "aarch64" (System/getenv "BABASHKA_ARCH"))
(= "linux" (System/getenv "BABASHKA_PLATFORM")))
(is (= {:expired "java.security.cert.CertificateExpiredException"
:revoked 200 ;; TODO: fix, "sun.security.cert.CertificateRevokedException"
:self-signed "sun.security.provider.certpath.SunCertPathBuilderException"
:untrusted-root "sun.security.provider.certpath.SunCertPathBuilderException"
:wrong-host "sun.security.provider.certpath.SunCertPathBuilderException"}
(bb
'(do
(ns net
(:import
(java.net URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(defn send-and-catch [client req handler]
(try
(let [res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res))
(catch Throwable t
(-> (Throwable->map t) :via last :type name))))
(let [client (HttpClient/newHttpClient)
handler (HttpResponse$BodyHandlers/discarding)
reqs (->> [:expired
:self-signed
:revoked
:untrusted-root
:wrong-host]
(map (fn [k]
(let [req (-> (URI. (format "https://%s.badssl.com" (name k)))
(HttpRequest/newBuilder)
(.GET)
(.build))]
[k req])))
(into {}))]
(->> reqs
(map (fn [[k req]]
[k (send-and-catch client req handler)]))
(into {})))))))
(is (= {:expired 200
:self-signed 200
:untrusted-root 200}
(bb
'(do
(ns net
(:import
(java.net URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)
(java.security SecureRandom)
(java.security.cert X509Certificate)
(javax.net.ssl SSLContext
TrustManager
X509TrustManager)))
(let [insecure-trust-manager (reify X509TrustManager
(checkClientTrusted [_ _ _])
(checkServerTrusted [_ _ _])
(getAcceptedIssuers [_] (into-array X509Certificate [])))
insecure-trust-managers (into-array TrustManager [insecure-trust-manager])
insecure-context (doto (SSLContext/getInstance "TLS")
(.init nil
insecure-trust-managers
(SecureRandom.)))
client (-> (HttpClient/newBuilder)
(.sslContext insecure-context)
(.build))
handler (HttpResponse$BodyHandlers/discarding)
reqs (->> [:expired
:self-signed
:untrusted-root]
(map (fn [k]
(let [req (-> (URI. (format "https://%s.badssl.com" (name k)))
(HttpRequest/newBuilder)
(.GET)
(.build))]
[k req])))
(into {}))]
(->> reqs
(map (fn [[k req]]
[k (-> (.send client req handler)
(.statusCode))]))
(into {})))))))))
;; HttpRequest
(deftest body-publishers-test
(is (= true
@ -212,15 +345,16 @@
HttpRequest$BodyPublishers
HttpResponse$BodyHandlers)
(java.util.function Supplier)))
(let [bp (HttpRequest$BodyPublishers/ofFile (.toPath (io/file "README.md")))
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/post"))
(.method "POST" bp)
(.build))
client (-> (HttpClient/newBuilder)
(.build))
client (HttpClient/newHttpClient)
res (.send client req (HttpResponse$BodyHandlers/ofString))
body-data (-> (.body res) (json/parse-string true) :data)]
(str/includes? body-data "babashka"))))))
(let [body "with love from java.net.http"]
(is (= {:of-input-stream body
:of-byte-array body
@ -238,6 +372,7 @@
HttpRequest$BodyPublishers
HttpResponse$BodyHandlers)
(java.util.function Supplier)))
(let [body "with love from java.net.http"
publishers {:of-input-stream (HttpRequest$BodyPublishers/ofInputStream
(reify Supplier (get [_] (io/input-stream (.getBytes body)))))
@ -272,122 +407,19 @@
HttpResponse$BodyHandlers)
(java.nio.charset Charset)
(java.util.function Supplier)))
(let [body "おはようございます!"
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/post"))
(.method "POST" (HttpRequest$BodyPublishers/ofString
body (Charset/forName "UTF-16")))
(.header "Content-Type" "text/plain; charset=utf-16")
(.build))
client (-> (HttpClient/newBuilder)
(.build))
client (HttpClient/newHttpClient)
res (.send client req (HttpResponse$BodyHandlers/ofString))]
(-> (.body res)
(json/parse-string true)
:data)))))))))
(deftest cookie-test
(is (= []
(bb '(do (ns net
(:import [java.net CookieManager]))
(-> (CookieManager.)
(.getCookieStore)
(.getCookies))))))
(is (= "www.postman-echo.com"
(bb '(do
(ns net
(:import
(java.net CookieManager
URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(let [client (-> (HttpClient/newBuilder)
(.cookieHandler (CookieManager.))
(.build))
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/get"))
(.GET)
(.build))]
(.send client req (HttpResponse$BodyHandlers/discarding))
(-> client
(.cookieHandler)
(.get)
(.getCookieStore)
(.getCookies)
first
(.getDomain))))))))
(deftest authenticator-test
(is (= [401 200]
(bb
'(do
(ns net
(:import
(java.net Authenticator
PasswordAuthentication
URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(let [no-auth-client (-> (HttpClient/newBuilder)
(.build))
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/basic-auth"))
(.build))
handler (HttpResponse$BodyHandlers/discarding)
no-auth-res (.send no-auth-client req handler)
authenticator (proxy [Authenticator] []
(getPasswordAuthentication []
(PasswordAuthentication. "postman" (char-array "password"))))
auth-client (-> (HttpClient/newBuilder)
(.authenticator authenticator)
(.build))
auth-res (.send auth-client req handler)]
[(.statusCode no-auth-res) (.statusCode auth-res)]))))))
(deftest cert-test
;; TODO: investigate aarch64 issue
(when-not
(and (= "aarch64" (System/getenv "BABASHKA_ARCH"))
(= "linux" (System/getenv "BABASHKA_PLATFORM")))
(is (= {:expired "java.security.cert.CertificateExpiredException"
:revoked 200 ;; TODO: fix, "sun.security.cert.CertificateRevokedException"
:self-signed "sun.security.provider.certpath.SunCertPathBuilderException"
:untrusted-root "sun.security.provider.certpath.SunCertPathBuilderException"
:wrong-host "sun.security.provider.certpath.SunCertPathBuilderException"}
(bb
'(do
(ns net
(:import
(java.net URI)
(java.net.http HttpClient
HttpRequest
HttpResponse$BodyHandlers)))
(defn send-and-catch [client req handler]
(try
(let [res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res))
(catch Throwable t
(-> (Throwable->map t) :via last :type name))))
(let [client (-> (HttpClient/newBuilder)
(.build))
handler (HttpResponse$BodyHandlers/discarding)
reqs (->> [:expired
:self-signed
:revoked
:untrusted-root
:wrong-host]
(map (fn [k]
(let [req (-> (URI. (format "https://%s.badssl.com" (name k)))
(HttpRequest/newBuilder)
(.GET)
(.build))]
[k req])))
(into {}))]
(->> reqs
(map (fn [[k req]]
[k (send-and-catch client req handler)]))
(into {})))))))))
(deftest request-timeout-test
(is (= "java.net.http.HttpTimeoutException"
@ -401,8 +433,7 @@
HttpResponse$BodyHandlers)
(java.time Duration)))
(let [client (-> (HttpClient/newBuilder)
(.build))
(let [client (HttpClient/newHttpClient)
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/delay/1"))
(.GET)
(.timeout (Duration/ofMillis 200))
@ -430,6 +461,7 @@
HttpResponse$BodyHandlers)
(java.nio.file Files StandardOpenOption)
(java.nio.file.attribute FileAttribute)))
(let [client (-> (HttpClient/newBuilder)
(.build))
uri (URI. "https://raw.githubusercontent.com/babashka/babashka/master/README.md")
@ -445,6 +477,8 @@
contents (slurp temp-file-path)]
(str/includes? contents "babashka")))))))
;; WebSockets
(defn ws-handler [{:keys [init] :as opts} req]
(when init (init req))
(httpkit.server/as-channel
@ -472,6 +506,7 @@
WebSocket$Listener)
(java.util.concurrent CompletableFuture)
(java.util.function Function)))
(let [p (promise)
uri (URI. "ws://localhost:1234")
listener (reify WebSocket$Listener