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:
parent
b71278cc68
commit
125e227976
8 changed files with 278 additions and 228 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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` |
|
||||
|
|
|
|||
|
|
@ -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}"
|
||||
|
|
|
|||
|
|
@ -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}"
|
||||
|
|
|
|||
|
|
@ -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;")
|
||||
|
|
|
|||
|
|
@ -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")))
|
||||
|
|
|
|||
|
|
@ -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]]}}))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in a new issue