on master help sign in
warp-tls: ignore socket errors while sending close_notify

(fixes #640) RFC 5246 section 7.2.1 says this about closure alerts: > The client and the server must share knowledge that the connection is ending > in order to avoid a truncation attack. Either party may initiate the > exchange of closing messages. > > [...] > > Unless some other fatal alert has been transmitted, each party is required to > send a close_notify alert before closing the write side of the connection. > The other party MUST respond with a close_notify alert of its own and close > down the connection immediately, discarding any pending writes. It is not > required for the initiator of the close to wait for the responding > close_notify alert before closing the read side of the connection. This `close_notify` message is sent by `TLS.bye`, and it used to generate an exception when the receiving side closes the connection before waiting for `close_notify`. But this scenario is perfectly legal according to the RFC, so we should ignore `ConnectionClosedByPeer` exception that happens during `TLS.bye`.

commit7035bde41fc9659b845210d4bf5b93782ebe52f5 authorÖmer Sinan Ağacan <omeragacan@gmail.com> dateTue 15 Aug 2017, 10:29 (9 years ago) parent196238f
1 file changed+11−3
warp-tls/Network/Wai/Handler/WarpTLS.hs+11−3
warp-tls/Network/Wai/Handler/WarpTLS.hs+11−3
@@ -47,9 +47,9 @@ module Network.Wai.Handler.WarpTLS (
4747import Control.Applicative ((<$>))
4848#endif
4949import Control.Applicative ((<|>))
50−import Control.Exception (Exception, throwIO, bracket, finally, handle, fromException, try, IOException, onException, SomeException(..))
50+import Control.Exception (Exception, throwIO, bracket, finally, handle, fromException, try, IOException, onException, SomeException(..), handleJust)
5151import qualified Control.Exception as E
52−import Control.Monad (void)
52+import Control.Monad (void, guard)
5353import qualified Data.ByteString as S
5454import qualified Data.ByteString.Lazy as L
5555import Data.Default.Class (def)
@@ -348,9 +348,17 @@ httpOverTls TLSSettings{..} s bs0 params = do
348348 sendfile fid offset len hook headers =
349349 readSendFile writeBuf bufferSize sendall fid offset len hook headers
350350
351− close' = void (tryIO $ TLS.bye ctx) `finally`
351+ close' = void (tryIO sendBye) `finally`
352352 TLS.contextClose ctx
353353
354+ sendBye =
355+ -- It's fine if the connection was closed by the other side before
356+ -- receiving close_notify, see RFC 5246 section 7.2.1.
357+ handleJust
358+ (\e -> guard (e == ConnectionClosedByPeer) >> return e)
359+ (const (return ()))
360+ (TLS.bye ctx)
361+
354362 -- TLS version of recv with a cache for leftover input data.
355363 -- The cache is shared with recvBuf.
356364 recv cref = do