Skip to content

Commit ae3f589

Browse files
Merge pull request #623 from clj-commons/only-yield-tcp-ssl-client-stream-after-successful-handshake
Only yield client streams after successful SSL handshake
2 parents cfc6ee9 + b3dc690 commit ae3f589

File tree

4 files changed

+73
-37
lines changed

4 files changed

+73
-37
lines changed

src/aleph/http/client.clj

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,12 @@
680680

681681
:channel-active
682682
([_ ctx]
683-
(let [ch (.channel ctx)]
684-
(reset! in (netty/buffered-source ch (constantly 1) 16))
685-
(.handshake handshaker ch))
683+
(-> (.channel ctx)
684+
netty/maybe-ssl-handshake-future
685+
(d/on-realized (fn [ch]
686+
(reset! in (netty/buffered-source ch (constantly 1) 16))
687+
(.handshake handshaker ch))
688+
netty/ignore-ssl-handshake-errors))
686689
(.fireChannelActive ctx))
687690

688691
:user-event-triggered

src/aleph/netty.clj

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,25 @@ initialize an DnsAddressResolverGroup instance.
11311131
[dns-options]
11321132
(DnsAddressResolverGroup. (dns-resolver-group-builder dns-options)))
11331133

1134+
(defn ^:nodoc maybe-ssl-handshake-future
1135+
"Returns a deferred which resolves to the channel after a potential
1136+
SSL handshake has completed successfully. If no `SslHandler` is
1137+
present on the associated pipeline, resolves immediately."
1138+
[^Channel ch]
1139+
(if-let [^SslHandler ssl-handler (-> ch .pipeline (.get SslHandler))]
1140+
(-> ssl-handler
1141+
.handshakeFuture
1142+
wrap-future)
1143+
(d/success-deferred ch)))
1144+
1145+
(defn ^:nodoc ignore-ssl-handshake-errors
1146+
"Intended for use as error callback on a `maybe-ssl-handshake-future`
1147+
within a `:channel-active` handler. In this context, SSL handshake
1148+
errors don't need to be handled since the SSL handler will terminate
1149+
the whole pipeline by throwing `javax.net.ssl.SSLHandshakeException`
1150+
anyway."
1151+
[_])
1152+
11341153
(defn create-client
11351154
([pipeline-builder
11361155
ssl-context
@@ -1197,7 +1216,7 @@ initialize an DnsAddressResolverGroup instance.
11971216
(d/chain' (wrap-future f)
11981217
(fn [_]
11991218
(let [ch (.channel ^ChannelFuture f)]
1200-
ch))))))))
1219+
(maybe-ssl-handshake-future ch)))))))))
12011220

12021221
(defn start-server
12031222
[pipeline-builder

src/aleph/tcp.clj

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,7 @@
2828

2929
(defn- ^ChannelHandler server-channel-handler
3030
[handler {:keys [raw-stream?] :as options}]
31-
(let [in (atom nil)
32-
call-handler (fn [^ChannelHandlerContext ctx]
33-
(let [ch (.channel ctx)]
34-
(handler
35-
(doto
36-
(s/splice
37-
(netty/sink ch true netty/to-byte-buf)
38-
(reset! in (netty/source ch)))
39-
(reset-meta! {:aleph/channel ch}))
40-
(->TcpConnection ch))))]
31+
(let [in (atom nil)]
4132
(netty/channel-inbound-handler
4233

4334
:exception-caught
@@ -58,19 +49,16 @@
5849

5950
:channel-active
6051
([_ ctx]
61-
(if-let [^SslHandler ssl-handler (-> ctx .pipeline (.get SslHandler))]
62-
(-> ssl-handler
63-
.handshakeFuture
64-
netty/wrap-future
65-
(d/on-realized (fn [_]
66-
(call-handler ctx))
67-
;; No need to handle errors here since
68-
;; the SSL handler will terminate the
69-
;; whole pipeline by throwing a
70-
;; `javax.net.ssl.SSLHandshakeException`
71-
;; in this case anyway.
72-
(fn [_])))
73-
(call-handler ctx))
52+
(-> (.channel ctx)
53+
netty/maybe-ssl-handshake-future
54+
(d/on-realized (fn [ch]
55+
(handler
56+
(doto (s/splice
57+
(netty/sink ch true netty/to-byte-buf)
58+
(reset! in (netty/source ch)))
59+
(reset-meta! {:aleph/channel ch}))
60+
(->TcpConnection ch)))
61+
netty/ignore-ssl-handshake-errors))
7462
(.fireChannelActive ctx))
7563

7664
:channel-read
@@ -129,19 +117,20 @@
129117

130118
:channel-inactive
131119
([_ ctx]
132-
(s/close! @in)
120+
(some-> @in s/close!)
133121
(.fireChannelInactive ctx))
134122

135123
:channel-active
136124
([_ ctx]
137-
(let [ch (.channel ctx)]
138-
(d/success! d
139-
(doto
140-
(s/splice
141-
(netty/sink ch true netty/to-byte-buf)
142-
(reset! in (netty/source ch)))
143-
(reset-meta! {:aleph/channel ch}))))
144-
(.fireChannelActive ctx))
125+
(-> (.channel ctx)
126+
netty/maybe-ssl-handshake-future
127+
(d/on-realized (fn [ch]
128+
(d/success! d (doto (s/splice
129+
(netty/sink ch true netty/to-byte-buf)
130+
(reset! in (netty/source ch)))
131+
(reset-meta! {:aleph/channel ch}))))
132+
netty/ignore-ssl-handshake-errors))
133+
(.fireChannelActive ctx))
145134

146135
:channel-read
147136
([_ ctx msg]

test/aleph/tcp_ssl_test.clj

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
[aleph.tcp-test :refer [with-server]]
77
[clj-commons.byte-streams :as bs]
88
[clojure.test :refer [deftest is]]
9+
[manifold.deferred :as d]
910
[manifold.stream :as s])
1011
(:import
11-
(java.security.cert X509Certificate)))
12+
(java.security.cert X509Certificate)
13+
(java.util.concurrent TimeoutException)))
1214

1315
(netty/leak-detector-level! :paranoid)
1416

@@ -80,3 +82,26 @@
8082
(s/close! c)
8183
(is (deref connection-closed 1000 false))
8284
(is (nil? @ssl-session) "SSL session should be undefined")))))
85+
86+
(deftest test-client-yields-stream-only-after-successful-handshake
87+
(let [connection-active (promise)
88+
continue-handshake (promise)
89+
notify-connection-active #_:clj-kondo/ignore (netty/channel-inbound-handler
90+
:channel-active
91+
([_ ctx]
92+
(deliver connection-active true)
93+
(when-not (deref continue-handshake 5000 false)
94+
(throw (TimeoutException.)))
95+
(.fireChannelActive ctx)))]
96+
(with-server (tcp/start-server (fn [s _])
97+
{:port 10001
98+
:ssl-context ssl/server-ssl-context})
99+
(let [c (tcp/client {:host "localhost"
100+
:port 10001
101+
:ssl-context ssl/client-ssl-context-opts
102+
:pipeline-transform (fn [p]
103+
(.addAfter p "handler" "notify-active" notify-connection-active))})]
104+
(is (deref connection-active 1000 false))
105+
(is (not (d/realized? c)))
106+
(deliver continue-handshake true)
107+
(is (deref c 1000 false))))))

0 commit comments

Comments
 (0)