Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 138 additions & 88 deletions README.md

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
[ring/ring-anti-forgery "1.4.0"]
[metosin/reitit-ring "0.10.1"]]
:resource-paths ["dev-resources"]
:plugins [[dev.weavejester/lein-cljfmt "0.16.3"]]}
:plugins [[dev.weavejester/lein-cljfmt "0.16.4"]]}
:pedantic {:pedantic? :abort}}

:aliases {"check" ["with-profile" "+pedantic" "check"]
"kondo" ["with-profile" "+pedantic" "run" "-m" "clj-kondo.main" "--lint" "src:test" "--parallel"]
"fmt" ["with-profile" "+pedantic" "cljfmt" "check"]
"fmtfix" ["with-profile" "+pedantic" "cljfmt" "fix"]}

:aot [slipway.handler.sync-handler]
:aot [slipway.sync-handler]

:dependencies [[org.clojure/clojure "1.12.5"]
[org.clojure/tools.logging "1.3.1"]
Expand All @@ -34,10 +34,11 @@
[org.eclipse.jetty/jetty-server "12.1.10"]
[org.eclipse.jetty/jetty-session "12.1.10"]
[org.eclipse.jetty/jetty-security "12.1.10"]
[org.eclipse.jetty/jetty-openid "12.1.10"]
[org.eclipse.jetty.compression/jetty-compression-server "12.1.10"]
[org.eclipse.jetty.compression/jetty-compression-gzip "12.1.10"]]

:source-paths ["src"]
:test-paths ["test"]
:test-paths ["test/unit" "test/integration"]

:javac-options ["--release" "17"])
65 changes: 37 additions & 28 deletions src/slipway.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@
(:require [clojure.tools.logging :as log]
[slipway.connector.http]
[slipway.connector.https]
[slipway.handler]
[slipway.security :as security]
[slipway.context]
[slipway.security]
[slipway.server :as server]
[slipway.user]
[slipway.websockets])
(:import (org.eclipse.jetty.server Handler Server)))
(:import (org.eclipse.jetty.server Server)))

(comment
#:slipway.handler.compression{:enabled? "is compression handler enabled? default true"
:path-spec "the compression path-spec, default '/*'"
:format "compression format, defaults to :gzip"
:compress-min-bytes "min response size to trigger compression (default 1024 bytes)"
:compression-config "a concrete Jetty CompressConfig instance (nil for default configuration)"}
#:slipway.compression{:enabled? "is a compression handler enabled? default true"
:path-spec "the compression path-spec, default '/*'"
:format "compression format, defaults to :gzip"
:compress-min-bytes "min response size to trigger compression (default 1024 bytes)"
:compression-config "a concrete Jetty CompressionConfig instance (nil for default configuration)"}

#:slipway.connector.https{:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
#:slipway.connector.https{:name "the name of this connector (useful for VirtualHosts configuration)"
:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
:port "port this connector listens on. If set to 0 a random port is assigned which may be obtained with getLocalPort(). default 443"
:idle-timeout-ms "max idle time for a connection, roughly translates to the Socket.setSoTimeout. Default 200000 ms"
:http-forwarded? "if true, add the ForwardRequestCustomizer. See Jetty Forward HTTP docs"
Expand Down Expand Up @@ -45,9 +46,10 @@
:send-server-version? "if true, send the Server header in responses"
:send-date-header? "if true, send the Date header in responses"
:relative-redirect-allowed? "if true, allow relative redirects, default false"
:http-compliance "set 'RFC2616' to support reduced HttpCompliance, default is Jetty HttpCompliance/default"}
:http-compliance "set the HttpCompliance mode, defaults to HttpCompliance/RFC9110"}

#:slipway.connector.http{:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
#:slipway.connector.http{:name "the name of this connector (useful for VirtualHosts configuration)"
:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
:port "port this connector listens on. If set to 0 a random port is assigned which may be obtained with getLocalPort(), default 80"
:idle-timeout-ms "max idle time for a connection, roughly translates to the Socket.setSoTimeout. Default 200000 ms"
:http-forwarded? "if true, add the ForwardRequestCustomizer. See Jetty Forward HTTP docs"
Expand All @@ -57,14 +59,21 @@
:send-server-version? "if true, send the Server header in responses"
:send-date-header? "if true, send the Date header in responses"
:relative-redirect-allowed? "if true, allow relative redirects, default false"
:http-compliance "set 'RFC2616' to support reduced HttpCompliance, default is Jetty HttpCompliance/default"}
:http-compliance "set the HttpCompliance mode, defaults to HttpCompliance/RFC9110"}

#:slipway.security{:realm "the Jetty authentication realm"
:hash-user-file "the path to a Jetty Hash User File"
:login-service "a Jetty LoginService identifier, 'jaas' and 'hash' supported by default"
:identity-service "a concrete Jetty IdentityService"
:authenticator "a concrete Jetty Authenticator (e.g. FormAuthenticator or BasicAuthenticator)"
:constraint-mappings "a vector of [^String pathSpec, org.eclipse.jetty.security.Constraint]"}
#:slipway.security{:handler "identifies a SecurityHandler impl, 'jaas', 'hash', and 'openid' supported by default"}

#:slipway.security.hash{:realm "an (optional) Jetty authentication realm"
:user-file "the path to a Jetty hash-user file"
:users "a sequence of [^String user-name, ^String credential, ^String[] [roles]]"
:authenticator "a concrete Jetty Authenticator (e.g. FormAuthenticator or BasicAuthenticator)"
:constraint-mappings "a vector of [^String pathSpec, org.eclipse.jetty.security.Constraint]"
:identity-service "an (optional) concrete Jetty IdentityService"}

#:slipway.security.jaas{:realm "the Jetty authentication realm"
:authenticator "a concrete Jetty Authenticator (e.g. FormAuthenticator or BasicAuthenticator)"
:constraint-mappings "a vector of [^String pathSpec, org.eclipse.jetty.security.Constraint]"
:identity-service "an (optional) concrete Jetty IdentityService"}

#:slipway.session{:secure-request-only? "set the secure flag on session cookies"
:http-only? "set the http-only flag on session cookies"
Expand All @@ -79,7 +88,7 @@

#:slipway.sente{:options "A map of options passed directly to sente/make-channel-socket-server!"}

#:slipway.websockets{:enabled? "are websockets enabled? default true"
#:slipway.websockets{:enabled? "are websockets enabled? default false"
:path-spec "the websocket path-spec, default '/chsk'"
:idle-timeout-ms "max websocket idle time, default 300000"
:input-buffer-bytes "max websocket input buffer size"
Expand All @@ -90,11 +99,14 @@
:max-outgoing-frames "max websocket frames waiting to be sent per session, default -1"
:auto-fragment "websocket auto fragment (boolean), default true"}

#:slipway.handler{:context-path "the root context path, default '/'"
:ws-path "the path serving the websocket upgrade handler, default '/chsk'"
:null-path-info? "true if /path is not redirected to /path/, default true"}
#:slipway.context{:ring-handler "the ring-handler descendant of this context-handler"
:context-path "the root context path, default '/'"
:null-path-info? "true if /path is not redirected to /path/, default true"
:virtual-hosts "a list of ^String virtual hosts for the context"
:error-handler "the error-handler used by this context-handler for context level errors"
:handlers "an (optional) sequence of [#:slipway.context] for a ContextHandlerCollection"}

#:slipway.server{:handler "the base Jetty handler implementation (:default defmethod impl found in slipway.handler)"
#:slipway.server{:handler "the handler impl dispatch-val (:default defmethod found in slipway.context)"
:connectors "the connectors supported by this server"
:thread-pool "the thread-pool used by this server (nil for default behaviour)"
:scheduler "the scheduler used by this server (nil for default behaviour)"
Expand All @@ -104,12 +116,9 @@
#:slipway{:join? "join the Jetty threadpool, blocks the calling thread until jetty exits, default false"})

(defn start ^Server
[ring-handler {::keys [join?] :as opts}]
[{::keys [join?] :as opts}]
(log/debugf "starting jetty server %s" opts)
(let [server (server/create-server opts)
login-service (security/login-service opts)
handler (server/handler server ring-handler login-service opts)]
(.setHandler server ^Handler handler)
(let [server (server/create-server opts)]
(.start server)
(when join?
(log/debug "joining jetty thread")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
(ns slipway.handler.compression
(ns slipway.compression
(:refer-clojure :exclude [format])
(:require [clojure.tools.logging :as log])
(:import (org.eclipse.jetty.compression.gzip GzipCompression)
(org.eclipse.jetty.compression.server CompressionConfig CompressionHandler)))

(comment
#:slipway.handler.compression{:enabled? "is compression handler enabled? default true"
:path-spec "the compression path-spec, default '/*'"
:format "compression format, defaults to :gzip"
:compress-min-bytes "min response size to trigger compression (default 1024 bytes)"
:compression-config "a concrete Jetty CompressConfig instance (nil for default configuration)"})
#:slipway.compression{:enabled? "is a compression handler enabled? default true"
:path-spec "the compression path-spec, default '/*'"
:format "compression format, defaults to :gzip"
:compress-min-bytes "min response size to trigger compression (default 1024 bytes)"
:compression-config "a concrete Jetty CompressionConfig instance (nil for default configuration)"})

(defmulti format ::format)

Expand Down
13 changes: 7 additions & 6 deletions src/slipway/connector/http.clj
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
config))

(comment
#:slipway.connector.http{:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
#:slipway.connector.http{:name "the name of this connector (useful for VirtualHosts configuration)"
:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
:port "port this connector listens on. If set to 0 a random port is assigned which may be obtained with getLocalPort(), default 80"
:idle-timeout-ms "max idle time for a connection, roughly translates to the Socket.setSoTimeout. Default 200000 ms"
:idle-timeout-ms "max idle time for a connection, roughly translates to the Socket.setSoTimeout. Default 30000 ms"
:http-forwarded? "if true, add the ForwardRequestCustomizer. See Jetty Forward HTTP docs"
:proxy-protocol? "if true, add the ProxyConnectionFactory. See Jetty Proxy Protocol docs"
:http-config "a concrete HttpConfiguration object to replace the default config entirely"
Expand All @@ -40,9 +41,8 @@
:http-compliance "set the HttpCompliance mode, defaults to HttpCompliance/RFC9110"})

(defmethod server/connector ::connector
[^Server server {::keys [host port idle-timeout-ms proxy-protocol? http-forwarded? configurator http-config]
:or {idle-timeout-ms 200000
port 80}
[^Server server {::keys [host port name idle-timeout-ms proxy-protocol? http-forwarded? configurator http-config]
:or {port 80}
:as opts}]
(log/debugf (str "starting " (when proxy-protocol? "proxied ") "HTTP connector on %s:%s" (when http-forwarded? " with http-forwarded support")) (or host "all-interfaces") port)
(let [http-factory (HttpConnectionFactory. (or http-config (default-config opts)))
Expand All @@ -51,6 +51,7 @@
connector (ServerConnector. ^Server server ^"[Lorg.eclipse.jetty.server.ConnectionFactory;" factories)]
(.setHost connector host)
(.setPort connector port)
(.setIdleTimeout connector idle-timeout-ms)
(some->> name (.setName connector))
(some->> idle-timeout-ms (.setIdleTimeout connector))
(when configurator (configurator connector))
connector))
19 changes: 9 additions & 10 deletions src/slipway/connector/https.clj
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@
(when key-manager-password
(.setKeyManagerPassword context-factory key-manager-password))
(cond
(string? truststore)
(.setTrustStorePath context-factory truststore)
(instance? KeyStore truststore)
(.setTrustStore context-factory ^KeyStore truststore))
(string? truststore) (.setTrustStorePath context-factory truststore)
(instance? KeyStore truststore) (.setTrustStore context-factory ^KeyStore truststore))
(when truststore-password
(.setTrustStorePassword context-factory truststore-password))
(when truststore-type
Expand Down Expand Up @@ -91,9 +89,10 @@
(ServerConnector. server (context-factory opts) ^"[Lorg.eclipse.jetty.server.ConnectionFactory;" (into-array ConnectionFactory [http-factory])))

(comment
#:slipway.connector.https{:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
#:slipway.connector.https{:name "the name of this connector (useful for VirtualHosts configuration)"
:host "the network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, then bind to all interfaces. Default null/all interfaces"
:port "port this connector listens on. If set to 0 a random port is assigned which may be obtained with getLocalPort(). default 443"
:idle-timeout-ms "max idle time for a connection, roughly translates to the Socket.setSoTimeout. Default 200000 ms"
:idle-timeout-ms "max idle time for a connection, roughly translates to the Socket.setSoTimeout. Default 30000 ms"
:http-forwarded? "if true, add the ForwardRequestCustomizer. See Jetty Forward HTTP docs"
:proxy-protocol? "if true, add the ProxyConnectionFactory. See Jetty Proxy Protocol docs"
:http-config "a concrete HttpConfiguration object to replace the default config entirely"
Expand Down Expand Up @@ -123,14 +122,14 @@
:http-compliance "set the HttpCompliance mode, defaults to HttpCompliance/RFC9110"})

(defmethod server/connector ::connector
[^Server server {::keys [host port idle-timeout-ms proxy-protocol? http-config configurator]
:or {idle-timeout-ms 200000
port 443}
[^Server server {::keys [host port name idle-timeout-ms proxy-protocol? http-config configurator]
:or {port 443}
:as opts}]
(let [http-factory (HttpConnectionFactory. (or http-config (default-config opts)))
connector (if proxy-protocol? (proxied-connector server http-factory opts) (standard-connector server http-factory opts))]
(.setHost connector host)
(.setPort connector port)
(.setIdleTimeout connector idle-timeout-ms)
(some->> name (.setName connector))
(some->> idle-timeout-ms (.setIdleTimeout connector))
(when configurator (configurator connector))
connector))
Loading