/
jetty.clj
157 lines (145 loc) · 7.08 KB
/
jetty.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
(ns ring.adapter.jetty
"A Ring adapter that uses the Jetty 9 embedded web server.
Adapters are used to convert Ring handlers into running web servers."
(:require [ring.util.servlet :as servlet])
(:import [org.eclipse.jetty.server
Request
Server
ServerConnector
ConnectionFactory
HttpConfiguration
HttpConnectionFactory
SslConnectionFactory
SecureRequestCustomizer]
[org.eclipse.jetty.server.handler AbstractHandler]
[org.eclipse.jetty.util.thread ThreadPool QueuedThreadPool]
[org.eclipse.jetty.util.ssl SslContextFactory]
[javax.servlet AsyncContext]
[javax.servlet.http HttpServletRequest HttpServletResponse]))
(defn- ^AbstractHandler proxy-handler [handler]
(proxy [AbstractHandler] []
(handle [_ ^Request base-request request response]
(let [request-map (servlet/build-request-map request)
response-map (handler request-map)]
(servlet/update-servlet-response response response-map)
(.setHandled base-request true)))))
(defn- ^AbstractHandler async-proxy-handler [handler]
(proxy [AbstractHandler] []
(handle [_ ^Request base-request request ^HttpServletResponse response]
(let [^AsyncContext context (.startAsync request)]
(handler
(servlet/build-request-map request)
(fn [response-map]
(servlet/update-servlet-response response context response-map))
(fn [^Throwable exception]
(.sendError response 500 (.getMessage exception))
(.complete context)))
(.setHandled base-request true)))))
(defn- ^ServerConnector server-connector [server & factories]
(ServerConnector. server (into-array ConnectionFactory factories)))
(defn- ^HttpConfiguration http-config [options]
(doto (HttpConfiguration.)
(.setSendDateHeader (:send-date-header? options true))
(.setOutputBufferSize (:output-buffer-size options 32768))
(.setRequestHeaderSize (:request-header-size options 8192))
(.setResponseHeaderSize (:response-header-size options 8192))
(.setSendServerVersion (:send-server-version? options true))))
(defn- ^ServerConnector http-connector [server options]
(let [http-factory (HttpConnectionFactory. (http-config options))]
(doto (server-connector server http-factory)
(.setPort (options :port 80))
(.setHost (options :host))
(.setIdleTimeout (options :max-idle-time 200000)))))
(defn- ^SslContextFactory ssl-context-factory [options]
(let [context (SslContextFactory.)]
(if (string? (options :keystore))
(.setKeyStorePath context (options :keystore))
(.setKeyStore context ^java.security.KeyStore (options :keystore)))
(.setKeyStorePassword context (options :key-password))
(cond
(string? (options :truststore))
(.setTrustStorePath context (options :truststore))
(instance? java.security.KeyStore (options :truststore))
(.setTrustStore context ^java.security.KeyStore (options :truststore)))
(when (options :trust-password)
(.setTrustStorePassword context (options :trust-password)))
(case (options :client-auth)
:need (.setNeedClientAuth context true)
:want (.setWantClientAuth context true)
nil)
(if-let [exclude-ciphers (options :exclude-ciphers)]
(.addExcludeCipherSuites context (into-array String exclude-ciphers)))
(if-let [exclude-protocols (options :exclude-protocols)]
(.addExcludeProtocols context (into-array String exclude-protocols)))
context))
(defn- ^ServerConnector ssl-connector [server options]
(let [ssl-port (options :ssl-port 443)
http-factory (HttpConnectionFactory.
(doto (http-config options)
(.setSecureScheme "https")
(.setSecurePort ssl-port)
(.addCustomizer (SecureRequestCustomizer.))))
ssl-factory (SslConnectionFactory.
(ssl-context-factory options)
"http/1.1")]
(doto (server-connector server ssl-factory http-factory)
(.setPort ssl-port)
(.setHost (options :host))
(.setIdleTimeout (options :max-idle-time 200000)))))
(defn- ^ThreadPool create-threadpool [options]
(let [pool (QueuedThreadPool. ^Integer (options :max-threads 50))]
(.setMinThreads pool (options :min-threads 8))
(when (:daemon? options false)
(.setDaemon pool true))
pool))
(defn- ^Server create-server [options]
(let [server (Server. (create-threadpool options))]
(when (:http? options true)
(.addConnector server (http-connector server options)))
(when (or (options :ssl?) (options :ssl-port))
(.addConnector server (ssl-connector server options)))
server))
(defn ^Server run-jetty
"Start a Jetty webserver to serve the given handler according to the
supplied options:
:configurator - a function called with the Jetty Server instance
:async? - if true, treat the handler as asynchronous
:port - the port to listen on (defaults to 80)
:host - the hostname to listen on
:join? - blocks the thread until server ends (defaults to true)
:daemon? - use daemon threads (defaults to false)
:http? - listen on :port for HTTP traffic (defaults to true)
:ssl? - allow connections over HTTPS
:ssl-port - the SSL port to listen on (defaults to 443, implies
:ssl? is true)
:exclude-ciphers - When :ssl? is true, exclude these cipher suites
:exclude-protocols - When :ssl? is true, exclude these protocols
:keystore - the keystore to use for SSL connections
:key-password - the password to the keystore
:truststore - a truststore to use for SSL connections
:trust-password - the password to the truststore
:max-threads - the maximum number of threads to use (default 50)
:min-threads - the minimum number of threads to use (default 8)
:max-idle-time - the maximum idle time in milliseconds for a connection
(default 200000)
:client-auth - SSL client certificate authenticate, may be set to
:need,:want or :none (defaults to :none)
:send-date-header? - add a date header to the response (default true)
:output-buffer-size - the response body buffer size (default 32768)
:request-header-size - the maximum size of a request header (default 8192)
:response-header-size - the maximum size of a response header (default 8192)
:send-server-version? - add Server header to HTTP response (default true)"
[handler options]
(let [server (create-server (dissoc options :configurator))
proxyf (if (:async? options) async-proxy-handler proxy-handler)]
(.setHandler server (proxyf handler))
(when-let [configurator (:configurator options)]
(configurator server))
(try
(.start server)
(when (:join? options true)
(.join server))
server
(catch Exception ex
(.stop server)
(throw ex)))))