From 24aa08e8221718a79f92873e465f24fe272ed943 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 30 May 2018 23:47:42 -0400 Subject: [PATCH] ConnectionPool: monitor idle connections (#236) * ConnectionPool: monitor idle connections When a connection is returned to the (read) pool, add a monitor to it for receiving unexpected data (or EOF), and kill / close the Connection object if any activity occurs before the next write (when it should have simply been waiting idle in the pool) per https://github.com/JuliaWeb/MbedTLS.jl/pull/145#issuecomment-381832442 closes #214 closes #199 closes #220 closes JuliaWeb/GitHub.jl#106 * - Encapsulate read|writebusy/sequence/count logic in new isbusy function. - Move close() on eof() || !isbusy() to new monitor_idle_connection function. - Make monitor_idle_connection() a noop for ::Connection{SSLContext} * require Julia 0.6.3 https://github.com/JuliaWeb/HTTP.jl/pull/236#issuecomment-385320064 --- REQUIRE | 4 ++-- src/ConnectionPool.jl | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/REQUIRE b/REQUIRE index c87497786..07836cd36 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,3 +1,3 @@ -julia 0.6.2 -MbedTLS 0.5.7 +julia 0.6.3 +MbedTLS 0.5.9 IniFile diff --git a/src/ConnectionPool.jl b/src/ConnectionPool.jl index 06b21ecf1..4bcfcd975 100644 --- a/src/ConnectionPool.jl +++ b/src/ConnectionPool.jl @@ -138,6 +138,12 @@ Base.isopen(t::Transaction) = isopen(t.c) && t.c.readcount <= t.sequence && t.c.writecount <= t.sequence +""" +Is `c` currently in use or expecting a response to request already sent? +""" +isbusy(c::Connection) = isopen(c) && (c.writebusy || c.readbusy || + c.writecount > c.readcount) + function Base.eof(t::Transaction) @require isreadable(t) || !isopen(t) if bytesavailable(t) > 0 @@ -264,10 +270,32 @@ function IOExtras.closeread(t::Transaction) notify(t.c.readdone) ;@debug 2 "✉️ Read done: $t" notify(poolcondition) + if !isbusy(t.c) + @schedule monitor_idle_connection(t.c) + end + @ensure !isreadable(t) return end +""" +Wait for `c` to receive data or reach EOF. +Close `c` on EOF or if response data arrives when no request was sent. +""" +function monitor_idle_connection(c::Connection) + if eof(c.io) ;@debug 2 "💀 Closed: $c" + close(c.io) + elseif !isbusy(c) ;@debug 1 "😈 Idle RX!!: $c" + close(c.io) + end +end + +function monitor_idle_connection(c::Connection{SSLContext}) + # MbedTLS.jl monitors idle connections for TLS close_notify messages. + # https://github.com/JuliaWeb/MbedTLS.jl/pull/145 +end + + function Base.close(t::Transaction) close(t.c) if iswritable(t)