@@ -1,9 +1,17 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE RankNTypes #-}
3+{-# LANGUAGE RecordWildCards #-}
4+{-# LANGUAGE DeriveDataTypeable #-}
3module Network.Wai.Handler.WarpTLS
5module Network.Wai.Handler.WarpTLS
4− ( TLSSettings (..)
6+ ( TLSSettings
6 , runTLSSocket
13 , runTLSSocket
14+ , WarpTLSException (..)
9import qualified Network.TLS as TLS
17import qualified Network.TLS as TLS
@@ -28,16 +36,37 @@ import Data.Maybe (fromMaybe)
28import qualified Data.IORef as I
36import qualified Data.IORef as I
29import Control.Monad (unless)
37import Control.Monad (unless)
30import Crypto.Random.API (getSystemRandomGen)
38import Crypto.Random.API (getSystemRandomGen)
39+import Control.Exception (Exception, throwIO)
40+import Data.Typeable (Typeable)
32data TLSSettings = TLSSettings
42data TLSSettings = TLSSettings
33 { certFile :: FilePath
43 { certFile :: FilePath
44+ -- ^ File containing the certificate.
34 , keyFile :: FilePath
45 , keyFile :: FilePath
46+ -- ^ File containing the key
47+ , onInsecure :: OnInsecure
48+ -- ^ Do we allow insecure connections with this server as well? Default
49+ -- is a simple text response stating that a secure connection is required.
54+data OnInsecure = DenyInsecure L.ByteString
57+tlsSettings :: FilePath -- ^ Certificate file
58+ -> FilePath -- ^ key file
60+tlsSettings cert key = TLSSettings
63+ , onInsecure = DenyInsecure "This server only accepts secure HTTPS connections."
37runTLSSocket :: TLSSettings -> Settings -> Socket -> Application -> IO ()
66runTLSSocket :: TLSSettings -> Settings -> Socket -> Application -> IO ()
38−runTLSSocket tset set sock app = do
67+runTLSSocket TLSSettings {..} set sock app = do
39− certs <- readCertificates $ certFile tset
68+ certs <- readCertificates certFile
40− pk <- readPrivateKey $ keyFile tset
69+ pk <- readPrivateKey keyFile
41 let params =
70 let params =
42 TLS.updateServerParams
71 TLS.updateServerParams
43 (\sp -> sp { TLS.serverWantClientCert = False }) $
72 (\sp -> sp { TLS.serverWantClientCert = False }) $
@@ -84,13 +113,26 @@ runTLSSocket tset set sock app = do
84 , connRecv = TLS.recvData ctx
113 , connRecv = TLS.recvData ctx
86 return conn
115 return conn
88− let conn = (socketConnection s)
119+ let conn = (socketConnection s)
89− { connRecv = getNext $ fmap (fromMaybe B.empty) C.await
120+ { connRecv = getNext $ fmap (fromMaybe B.empty) C.await
91− return conn
122+ in return conn
123+ DenyInsecure lbs -> do
125+ C.yield "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"
126+ mapM_ C.yield $ L.toChunks lbs
127+ src C.$$ sinkSocket s
129+ throwIO InsecureConnectionDenied
92 return (mkConn, sa)
130 return (mkConn, sa)
132+data WarpTLSException = InsecureConnectionDenied
133+ deriving (Show, Typeable)
134+instance Exception WarpTLSException
94runTLS :: TLSSettings -> Settings -> Application -> IO ()
136runTLS :: TLSSettings -> Settings -> Application -> IO ()
95runTLS tset set app =
137runTLS tset set app =