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_MUSL=
|
||||||
ARG BABASHKA_FEATURE_CORE_ASYNC=
|
ARG BABASHKA_FEATURE_CORE_ASYNC=
|
||||||
ARG BABASHKA_FEATURE_CSV=
|
ARG BABASHKA_FEATURE_CSV=
|
||||||
|
ARG BABASHKA_FEATURE_JAVA_NET_HTTP=
|
||||||
ARG BABASHKA_FEATURE_JAVA_NIO=
|
ARG BABASHKA_FEATURE_JAVA_NIO=
|
||||||
ARG BABASHKA_FEATURE_JAVA_TIME=
|
ARG BABASHKA_FEATURE_JAVA_TIME=
|
||||||
ARG BABAHSKA_FEATURE_TRANSIT=
|
ARG BABAHSKA_FEATURE_TRANSIT=
|
||||||
|
|
@ -37,6 +38,7 @@ ARG BABASHKA_STATIC=
|
||||||
ENV BABASHKA_LEAN=$BABASHKA_LEAN
|
ENV BABASHKA_LEAN=$BABASHKA_LEAN
|
||||||
ENV BABASHKA_FEATURE_CORE_ASYNC=$BABASHKA_FEATURE_CORE_ASYNC
|
ENV BABASHKA_FEATURE_CORE_ASYNC=$BABASHKA_FEATURE_CORE_ASYNC
|
||||||
ENV BABASHKA_FEATURE_CSV=$BABASHKA_FEATURE_CSV
|
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_NIO=$BABASHKA_FEATURE_JAVA_NIO
|
||||||
ENV BABASHKA_FEATURE_JAVA_TIME=$BABASHKA_FEATURE_JAVA_TIME
|
ENV BABASHKA_FEATURE_JAVA_TIME=$BABASHKA_FEATURE_JAVA_TIME
|
||||||
ENV BABAHSKA_FEATURE_TRANSIT=$BABAHSKA_FEATURE_TRANSIT
|
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_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_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_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_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` |
|
| `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 BABASHKA_FEATURE_CSV="${BABASHKA_FEATURE_CSV:-false}"
|
||||||
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
|
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
|
||||||
export BABASHKA_FEATURE_JAVA_TIME="${BABASHKA_FEATURE_JAVA_TIME:-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_JAVA_NIO="${BABASHKA_FEATURE_JAVA_NIO:-false}"
|
||||||
export BABASHKA_FEATURE_HTTPKIT_CLIENT="${BABASHKA_FEATURE_HTTPKIT_CLIENT:-false}"
|
export BABASHKA_FEATURE_HTTPKIT_CLIENT="${BABASHKA_FEATURE_HTTPKIT_CLIENT:-false}"
|
||||||
export BABASHKA_FEATURE_HTTPKIT_SERVER="${BABASHKA_FEATURE_HTTPKIT_SERVER:-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 BABASHKA_FEATURE_CSV="${BABASHKA_FEATURE_CSV:-false}"
|
||||||
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
|
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
|
||||||
export BABASHKA_FEATURE_JAVA_TIME="${BABASHKA_FEATURE_JAVA_TIME:-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_JAVA_NIO="${BABASHKA_FEATURE_JAVA_NIO:-false}"
|
||||||
export BABASHKA_FEATURE_HTTPKIT_CLIENT="${BABASHKA_FEATURE_HTTPKIT_CLIENT:-false}"
|
export BABASHKA_FEATURE_HTTPKIT_CLIENT="${BABASHKA_FEATURE_HTTPKIT_CLIENT:-false}"
|
||||||
export BABASHKA_FEATURE_HTTPKIT_SERVER="${BABASHKA_FEATURE_HTTPKIT_SERVER:-false}"
|
export BABASHKA_FEATURE_HTTPKIT_SERVER="${BABASHKA_FEATURE_HTTPKIT_SERVER:-false}"
|
||||||
|
|
|
||||||
|
|
@ -158,19 +158,12 @@
|
||||||
java.math.BigInteger
|
java.math.BigInteger
|
||||||
java.math.MathContext
|
java.math.MathContext
|
||||||
java.math.RoundingMode
|
java.math.RoundingMode
|
||||||
java.net.Authenticator
|
|
||||||
java.net.ConnectException
|
java.net.ConnectException
|
||||||
java.net.CookieHandler
|
|
||||||
java.net.CookieManager
|
|
||||||
java.net.CookieStore
|
|
||||||
java.net.DatagramSocket
|
java.net.DatagramSocket
|
||||||
java.net.DatagramPacket
|
java.net.DatagramPacket
|
||||||
java.net.HttpCookie
|
|
||||||
java.net.HttpURLConnection
|
java.net.HttpURLConnection
|
||||||
java.net.InetAddress
|
java.net.InetAddress
|
||||||
java.net.InetSocketAddress
|
java.net.InetSocketAddress
|
||||||
java.net.PasswordAuthentication
|
|
||||||
java.net.ProxySelector
|
|
||||||
java.net.ServerSocket
|
java.net.ServerSocket
|
||||||
java.net.Socket
|
java.net.Socket
|
||||||
java.net.SocketException
|
java.net.SocketException
|
||||||
|
|
@ -180,28 +173,41 @@
|
||||||
java.net.URLEncoder
|
java.net.URLEncoder
|
||||||
java.net.URLDecoder
|
java.net.URLDecoder
|
||||||
;; java.net.http
|
;; java.net.http
|
||||||
jdk.internal.net.http.HttpClientBuilderImpl
|
~@(when features/java-net-http?
|
||||||
jdk.internal.net.http.HttpClientFacade
|
'[java.net.Authenticator
|
||||||
jdk.internal.net.http.HttpRequestBuilderImpl
|
java.net.CookieHandler
|
||||||
jdk.internal.net.http.HttpResponseImpl
|
java.net.CookieManager
|
||||||
jdk.internal.net.http.common.MinimalFuture
|
java.net.CookieStore
|
||||||
jdk.internal.net.http.websocket.BuilderImpl
|
java.net.HttpCookie
|
||||||
jdk.internal.net.http.websocket.WebSocketImpl
|
java.net.PasswordAuthentication
|
||||||
java.net.http.HttpClient
|
java.net.ProxySelector
|
||||||
java.net.http.HttpClient$Builder
|
java.net.http.HttpClient
|
||||||
java.net.http.HttpClient$Redirect
|
java.net.http.HttpClient$Builder
|
||||||
java.net.http.HttpClient$Version
|
java.net.http.HttpClient$Redirect
|
||||||
java.net.http.HttpHeaders
|
java.net.http.HttpClient$Version
|
||||||
java.net.http.HttpRequest
|
java.net.http.HttpHeaders
|
||||||
java.net.http.HttpRequest$BodyPublisher
|
java.net.http.HttpRequest
|
||||||
java.net.http.HttpRequest$BodyPublishers
|
java.net.http.HttpRequest$BodyPublisher
|
||||||
java.net.http.HttpRequest$Builder
|
java.net.http.HttpRequest$BodyPublishers
|
||||||
java.net.http.HttpResponse
|
java.net.http.HttpRequest$Builder
|
||||||
java.net.http.HttpResponse$BodyHandler
|
java.net.http.HttpResponse
|
||||||
java.net.http.HttpResponse$BodyHandlers
|
java.net.http.HttpResponse$BodyHandler
|
||||||
java.net.http.WebSocket
|
java.net.http.HttpResponse$BodyHandlers
|
||||||
java.net.http.WebSocket$Builder
|
java.net.http.WebSocket
|
||||||
java.net.http.WebSocket$Listener
|
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?
|
~@(when features/java-nio?
|
||||||
'[java.nio.ByteBuffer
|
'[java.nio.ByteBuffer
|
||||||
java.nio.ByteOrder
|
java.nio.ByteOrder
|
||||||
|
|
@ -312,8 +318,6 @@
|
||||||
java.util.zip.ZipInputStream
|
java.util.zip.ZipInputStream
|
||||||
java.util.zip.ZipOutputStream
|
java.util.zip.ZipOutputStream
|
||||||
java.util.zip.ZipEntry
|
java.util.zip.ZipEntry
|
||||||
javax.net.ssl.SSLContext
|
|
||||||
javax.net.ssl.SSLParameters
|
|
||||||
~(symbol "[B")
|
~(symbol "[B")
|
||||||
~(symbol "[I")
|
~(symbol "[I")
|
||||||
~(symbol "[Ljava.lang.Object;")
|
~(symbol "[Ljava.lang.Object;")
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
(def csv? (not= "false" (System/getenv "BABASHKA_FEATURE_CSV")))
|
(def csv? (not= "false" (System/getenv "BABASHKA_FEATURE_CSV")))
|
||||||
(def transit? (not= "false" (System/getenv "BABASHKA_FEATURE_TRANSIT")))
|
(def transit? (not= "false" (System/getenv "BABASHKA_FEATURE_TRANSIT")))
|
||||||
(def java-time? (not= "false" (System/getenv "BABASHKA_FEATURE_JAVA_TIME")))
|
(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 java-nio? (not= "false" (System/getenv "BABASHKA_FEATURE_JAVA_NIO")))
|
||||||
(def httpkit-client? (not= "false" (System/getenv "BABASHKA_FEATURE_HTTPKIT_CLIENT")))
|
(def httpkit-client? (not= "false" (System/getenv "BABASHKA_FEATURE_HTTPKIT_CLIENT")))
|
||||||
(def httpkit-server? (not= "false" (System/getenv "BABASHKA_FEATURE_HTTPKIT_SERVER")))
|
(def httpkit-server? (not= "false" (System/getenv "BABASHKA_FEATURE_HTTPKIT_SERVER")))
|
||||||
|
|
|
||||||
|
|
@ -168,4 +168,9 @@
|
||||||
{get [[this]]}
|
{get [[this]]}
|
||||||
|
|
||||||
java.lang.Comparable
|
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
|
(:require
|
||||||
[babashka.test-utils :as test-utils]
|
[babashka.test-utils :as test-utils]
|
||||||
[clojure.edn :as edn]
|
[clojure.edn :as edn]
|
||||||
|
|
@ -9,7 +9,9 @@
|
||||||
(defn bb [expr]
|
(defn bb [expr]
|
||||||
(edn/read-string (apply test-utils/bb nil [(str expr)])))
|
(edn/read-string (apply test-utils/bb nil [(str expr)])))
|
||||||
|
|
||||||
(deftest java-http-client-test
|
;; HttpClient
|
||||||
|
|
||||||
|
(deftest send-test
|
||||||
(is (= [200 true]
|
(is (= [200 true]
|
||||||
(bb
|
(bb
|
||||||
'(do (ns net
|
'(do (ns net
|
||||||
|
|
@ -24,48 +26,91 @@
|
||||||
(.GET)
|
(.GET)
|
||||||
(.build)))
|
(.build)))
|
||||||
|
|
||||||
(def client
|
(def client (HttpClient/newHttpClient))
|
||||||
(-> (HttpClient/newBuilder)
|
|
||||||
(.build)))
|
|
||||||
|
|
||||||
(def resp (.send client req (HttpResponse$BodyHandlers/ofString)))
|
(def res (.send client req (HttpResponse$BodyHandlers/ofString)))
|
||||||
[(.statusCode resp) (string? (.body resp))])))))
|
[(.statusCode res) (string? (.body res))])))))
|
||||||
|
|
||||||
(deftest redirect-test
|
(deftest send-async-test
|
||||||
(let [redirect-prog
|
(is (= [200 true]
|
||||||
(fn [redirect-kind]
|
(bb
|
||||||
(str/replace (str '(do
|
'(do
|
||||||
(ns net
|
(ns net
|
||||||
(:import
|
(:import
|
||||||
(java.net.http HttpClient
|
(java.net URI)
|
||||||
HttpClient$Redirect
|
(java.net.http HttpClient
|
||||||
HttpRequest
|
HttpRequest
|
||||||
HttpRequest$BodyPublishers
|
HttpResponse$BodyHandlers)
|
||||||
HttpResponse$BodyHandlers)
|
(java.util.function Function)))
|
||||||
(java.net URI)))
|
|
||||||
(defn log [x] (.println System/err x))
|
(let [client (HttpClient/newHttpClient)
|
||||||
(let [req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com"))
|
req (-> (HttpRequest/newBuilder (URI. "https://www.clojure.org"))
|
||||||
(.GET)
|
(.GET)
|
||||||
(.timeout (java.time.Duration/ofSeconds 5))
|
(.build))]
|
||||||
(.build))
|
(-> (.sendAsync client req (HttpResponse$BodyHandlers/ofString))
|
||||||
client (-> (HttpClient/newBuilder)
|
(.thenApply (reify Function (apply [_ res] [(.statusCode res) (string? (.body res))])))
|
||||||
(.followRedirects :redirect/kind)
|
(deref))))))))
|
||||||
(.build))
|
|
||||||
handler (HttpResponse$BodyHandlers/discarding)]
|
;; HttpClient options
|
||||||
(.statusCode (.send client req handler)))))
|
|
||||||
":redirect/kind"
|
(deftest authenticator-test
|
||||||
(case redirect-kind
|
(is (= [401 200]
|
||||||
:never
|
(bb
|
||||||
"HttpClient$Redirect/NEVER"
|
'(do
|
||||||
:always
|
(ns net
|
||||||
"HttpClient$Redirect/ALWAYS")))]
|
(:import
|
||||||
;; TODO: make graalvm repro of never-ending request with redirect always on linux aarch64 (+ musl?)
|
(java.net Authenticator
|
||||||
(when-not (and (= "aarch64" (System/getenv "BABASHKA_ARCH"))
|
PasswordAuthentication
|
||||||
(= "linux" (System/getenv "BABASHKA_PLATFORM")))
|
URI)
|
||||||
(println "Testing redirect always")
|
(java.net.http HttpClient
|
||||||
(is (= 200 (bb (redirect-prog :always)))))
|
HttpRequest
|
||||||
(println "Testing redirect never")
|
HttpResponse$BodyHandlers)))
|
||||||
(is (= 302 (bb (redirect-prog :never))))))
|
|
||||||
|
(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
|
(deftest connect-timeout-test
|
||||||
(is (= "java.net.http.HttpConnectTimeoutException"
|
(is (= "java.net.http.HttpConnectTimeoutException"
|
||||||
|
|
@ -94,7 +139,7 @@
|
||||||
:type
|
:type
|
||||||
name)))))))))
|
name)))))))))
|
||||||
|
|
||||||
(deftest executor
|
(deftest executor-test
|
||||||
(is (= 200
|
(is (= 200
|
||||||
(bb
|
(bb
|
||||||
'(do
|
'(do
|
||||||
|
|
@ -105,6 +150,7 @@
|
||||||
HttpRequest
|
HttpRequest
|
||||||
HttpResponse$BodyHandlers)
|
HttpResponse$BodyHandlers)
|
||||||
(java.util.concurrent Executors)))
|
(java.util.concurrent Executors)))
|
||||||
|
|
||||||
(let [uri (URI. "https://www.postman-echo.com/get")
|
(let [uri (URI. "https://www.postman-echo.com/get")
|
||||||
req (-> (HttpRequest/newBuilder uri)
|
req (-> (HttpRequest/newBuilder uri)
|
||||||
(.GET)
|
(.GET)
|
||||||
|
|
@ -115,7 +161,7 @@
|
||||||
res (.send client req (HttpResponse$BodyHandlers/discarding))]
|
res (.send client req (HttpResponse$BodyHandlers/discarding))]
|
||||||
(.statusCode res)))))))
|
(.statusCode res)))))))
|
||||||
|
|
||||||
(deftest client-proxy
|
(deftest proxy-test
|
||||||
(is (= true
|
(is (= true
|
||||||
(bb
|
(bb
|
||||||
'(do
|
'(do
|
||||||
|
|
@ -123,6 +169,7 @@
|
||||||
(:import
|
(:import
|
||||||
(java.net ProxySelector)
|
(java.net ProxySelector)
|
||||||
(java.net.http HttpClient)))
|
(java.net.http HttpClient)))
|
||||||
|
|
||||||
(let [bespoke-proxy (proxy [ProxySelector] []
|
(let [bespoke-proxy (proxy [ProxySelector] []
|
||||||
(connectFailed [_ _ _])
|
(connectFailed [_ _ _])
|
||||||
(select [_ _]))
|
(select [_ _]))
|
||||||
|
|
@ -142,6 +189,7 @@
|
||||||
(java.net.http HttpClient
|
(java.net.http HttpClient
|
||||||
HttpRequest
|
HttpRequest
|
||||||
HttpResponse$BodyHandlers)))
|
HttpResponse$BodyHandlers)))
|
||||||
|
|
||||||
(let [uri (URI. "https://www.postman-echo.com/get")
|
(let [uri (URI. "https://www.postman-echo.com/get")
|
||||||
req (-> (HttpRequest/newBuilder uri)
|
req (-> (HttpRequest/newBuilder uri)
|
||||||
(.build))
|
(.build))
|
||||||
|
|
@ -151,50 +199,135 @@
|
||||||
res (.send client req (HttpResponse$BodyHandlers/discarding))]
|
res (.send client req (HttpResponse$BodyHandlers/discarding))]
|
||||||
(.statusCode res)))))))
|
(.statusCode res)))))))
|
||||||
|
|
||||||
(deftest ssl-test
|
(deftest redirect-test
|
||||||
(is (= 200
|
(let [redirect-prog
|
||||||
(bb
|
(fn [redirect-kind]
|
||||||
'(do
|
(str/replace (str '(do
|
||||||
(ns net
|
(ns net
|
||||||
(:import
|
(:import
|
||||||
(java.net URI)
|
(java.net.http HttpClient
|
||||||
(java.net.http HttpClient
|
HttpClient$Redirect
|
||||||
HttpRequest
|
HttpRequest
|
||||||
HttpResponse$BodyHandlers)
|
HttpRequest$BodyPublishers
|
||||||
(javax.net.ssl SSLContext
|
HttpResponse$BodyHandlers)
|
||||||
SSLParameters)))
|
(java.net URI)))
|
||||||
(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 send-async-test
|
(defn log [x] (.println System/err x))
|
||||||
(is (= 200
|
(let [req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com"))
|
||||||
(bb
|
(.GET)
|
||||||
'(do
|
(.timeout (java.time.Duration/ofSeconds 5))
|
||||||
(ns net
|
(.build))
|
||||||
(:import
|
client (-> (HttpClient/newBuilder)
|
||||||
(java.net ProxySelector
|
(.followRedirects :redirect/kind)
|
||||||
URI)
|
(.build))
|
||||||
(java.net.http HttpClient
|
handler (HttpResponse$BodyHandlers/discarding)]
|
||||||
HttpRequest
|
(.statusCode (.send client req handler)))))
|
||||||
HttpResponse$BodyHandlers)
|
":redirect/kind"
|
||||||
(java.time Duration)
|
(case redirect-kind
|
||||||
(java.util.function Function)))
|
:never
|
||||||
(let [client (-> (HttpClient/newBuilder)
|
"HttpClient$Redirect/NEVER"
|
||||||
(.build))
|
:always
|
||||||
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/get"))
|
"HttpClient$Redirect/ALWAYS")))]
|
||||||
(.GET)
|
;; TODO: make graalvm repro of never-ending request with redirect always on linux aarch64 (+ musl?)
|
||||||
(.build))]
|
(when-not (and (= "aarch64" (System/getenv "BABASHKA_ARCH"))
|
||||||
(-> (.sendAsync client req (HttpResponse$BodyHandlers/discarding))
|
(= "linux" (System/getenv "BABASHKA_PLATFORM")))
|
||||||
(.thenApply (reify Function (apply [_ t] (.statusCode t))))
|
(println "Testing redirect always")
|
||||||
(deref))))))))
|
(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
|
(deftest body-publishers-test
|
||||||
(is (= true
|
(is (= true
|
||||||
|
|
@ -212,15 +345,16 @@
|
||||||
HttpRequest$BodyPublishers
|
HttpRequest$BodyPublishers
|
||||||
HttpResponse$BodyHandlers)
|
HttpResponse$BodyHandlers)
|
||||||
(java.util.function Supplier)))
|
(java.util.function Supplier)))
|
||||||
|
|
||||||
(let [bp (HttpRequest$BodyPublishers/ofFile (.toPath (io/file "README.md")))
|
(let [bp (HttpRequest$BodyPublishers/ofFile (.toPath (io/file "README.md")))
|
||||||
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/post"))
|
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/post"))
|
||||||
(.method "POST" bp)
|
(.method "POST" bp)
|
||||||
(.build))
|
(.build))
|
||||||
client (-> (HttpClient/newBuilder)
|
client (HttpClient/newHttpClient)
|
||||||
(.build))
|
|
||||||
res (.send client req (HttpResponse$BodyHandlers/ofString))
|
res (.send client req (HttpResponse$BodyHandlers/ofString))
|
||||||
body-data (-> (.body res) (json/parse-string true) :data)]
|
body-data (-> (.body res) (json/parse-string true) :data)]
|
||||||
(str/includes? body-data "babashka"))))))
|
(str/includes? body-data "babashka"))))))
|
||||||
|
|
||||||
(let [body "with love from java.net.http"]
|
(let [body "with love from java.net.http"]
|
||||||
(is (= {:of-input-stream body
|
(is (= {:of-input-stream body
|
||||||
:of-byte-array body
|
:of-byte-array body
|
||||||
|
|
@ -238,6 +372,7 @@
|
||||||
HttpRequest$BodyPublishers
|
HttpRequest$BodyPublishers
|
||||||
HttpResponse$BodyHandlers)
|
HttpResponse$BodyHandlers)
|
||||||
(java.util.function Supplier)))
|
(java.util.function Supplier)))
|
||||||
|
|
||||||
(let [body "with love from java.net.http"
|
(let [body "with love from java.net.http"
|
||||||
publishers {:of-input-stream (HttpRequest$BodyPublishers/ofInputStream
|
publishers {:of-input-stream (HttpRequest$BodyPublishers/ofInputStream
|
||||||
(reify Supplier (get [_] (io/input-stream (.getBytes body)))))
|
(reify Supplier (get [_] (io/input-stream (.getBytes body)))))
|
||||||
|
|
@ -272,122 +407,19 @@
|
||||||
HttpResponse$BodyHandlers)
|
HttpResponse$BodyHandlers)
|
||||||
(java.nio.charset Charset)
|
(java.nio.charset Charset)
|
||||||
(java.util.function Supplier)))
|
(java.util.function Supplier)))
|
||||||
|
|
||||||
(let [body "おはようございます!"
|
(let [body "おはようございます!"
|
||||||
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/post"))
|
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/post"))
|
||||||
(.method "POST" (HttpRequest$BodyPublishers/ofString
|
(.method "POST" (HttpRequest$BodyPublishers/ofString
|
||||||
body (Charset/forName "UTF-16")))
|
body (Charset/forName "UTF-16")))
|
||||||
(.header "Content-Type" "text/plain; charset=utf-16")
|
(.header "Content-Type" "text/plain; charset=utf-16")
|
||||||
(.build))
|
(.build))
|
||||||
client (-> (HttpClient/newBuilder)
|
client (HttpClient/newHttpClient)
|
||||||
(.build))
|
|
||||||
res (.send client req (HttpResponse$BodyHandlers/ofString))]
|
res (.send client req (HttpResponse$BodyHandlers/ofString))]
|
||||||
(-> (.body res)
|
(-> (.body res)
|
||||||
(json/parse-string true)
|
(json/parse-string true)
|
||||||
:data)))))))))
|
: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
|
(deftest request-timeout-test
|
||||||
(is (= "java.net.http.HttpTimeoutException"
|
(is (= "java.net.http.HttpTimeoutException"
|
||||||
|
|
@ -401,8 +433,7 @@
|
||||||
HttpResponse$BodyHandlers)
|
HttpResponse$BodyHandlers)
|
||||||
(java.time Duration)))
|
(java.time Duration)))
|
||||||
|
|
||||||
(let [client (-> (HttpClient/newBuilder)
|
(let [client (HttpClient/newHttpClient)
|
||||||
(.build))
|
|
||||||
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/delay/1"))
|
req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/delay/1"))
|
||||||
(.GET)
|
(.GET)
|
||||||
(.timeout (Duration/ofMillis 200))
|
(.timeout (Duration/ofMillis 200))
|
||||||
|
|
@ -430,6 +461,7 @@
|
||||||
HttpResponse$BodyHandlers)
|
HttpResponse$BodyHandlers)
|
||||||
(java.nio.file Files StandardOpenOption)
|
(java.nio.file Files StandardOpenOption)
|
||||||
(java.nio.file.attribute FileAttribute)))
|
(java.nio.file.attribute FileAttribute)))
|
||||||
|
|
||||||
(let [client (-> (HttpClient/newBuilder)
|
(let [client (-> (HttpClient/newBuilder)
|
||||||
(.build))
|
(.build))
|
||||||
uri (URI. "https://raw.githubusercontent.com/babashka/babashka/master/README.md")
|
uri (URI. "https://raw.githubusercontent.com/babashka/babashka/master/README.md")
|
||||||
|
|
@ -445,6 +477,8 @@
|
||||||
contents (slurp temp-file-path)]
|
contents (slurp temp-file-path)]
|
||||||
(str/includes? contents "babashka")))))))
|
(str/includes? contents "babashka")))))))
|
||||||
|
|
||||||
|
;; WebSockets
|
||||||
|
|
||||||
(defn ws-handler [{:keys [init] :as opts} req]
|
(defn ws-handler [{:keys [init] :as opts} req]
|
||||||
(when init (init req))
|
(when init (init req))
|
||||||
(httpkit.server/as-channel
|
(httpkit.server/as-channel
|
||||||
|
|
@ -472,6 +506,7 @@
|
||||||
WebSocket$Listener)
|
WebSocket$Listener)
|
||||||
(java.util.concurrent CompletableFuture)
|
(java.util.concurrent CompletableFuture)
|
||||||
(java.util.function Function)))
|
(java.util.function Function)))
|
||||||
|
|
||||||
(let [p (promise)
|
(let [p (promise)
|
||||||
uri (URI. "ws://localhost:1234")
|
uri (URI. "ws://localhost:1234")
|
||||||
listener (reify WebSocket$Listener
|
listener (reify WebSocket$Listener
|
||||||
Loading…
Reference in a new issue