packages feed

webapp-0.3.0: Web/App/HTTP.hs

{-# LANGUAGE OverloadedStrings, RankNTypes, ScopedTypeVariables #-}

{-|
Module      : Web.App.HTTP
Copyright   : (c) Nathaniel Symer, 2015
License     : MIT
Maintainer  : nate@symer.io
Stability   : experimental
Portability : POSIX

Start an HTTP server.
-}

module Web.App.HTTP
(
  -- * Running Warp
  runSecure,
  runInsecure,
  -- * Configuring Warp
  mkWarpSettings,
  -- * Bind to a TCP port for HTTP
  bindTCP
)
where

import Control.Monad

import Network.Wai (Application)
import Network.Wai.Handler.Warp (defaultSettings,runSettingsSocket,Port)
import Network.Wai.Handler.WarpTLS (tlsSettings,runTLSSocket,TLSSettings(..),OnInsecure(..))
import Network.Wai.Handler.Warp.Internal
import Network.Socket (sClose,withSocketsDo,Socket)
import Data.Streaming.Network (bindPortTCP)
import Control.Exception (bracket)

import System.Exit
import System.Posix

bindTCP :: Port -> (Socket -> IO ()) -> IO ()
bindTCP port f = withSocketsDo $ bracket (bindPortTCP port "*4") sClose f

-- |Build a Warp Settings struct
mkWarpSettings :: IO () -- ^ function to be called on a SIGTERM or SIGINT
               -> Int -- ^ port
               -> Settings
mkWarpSettings teardown port = defaultSettings {
    settingsHTTP2Enabled = True, -- explicitly enable HTTP2 support
    settingsPort = port,
    settingsInstallShutdownHandler = \killSockets -> void $ do
      installHandler sigTERM (handler $ killSockets >> teardown) Nothing
      installHandler sigINT (handler $ killSockets >> teardown) Nothing
  }
  where handler = Catch . (>> exitImmediately ExitSuccess)
    
-- |Serve a WAI app using Warp over TLS.
runSecure :: FilePath -- ^ 'FilePath' to an SSL certificate
          -> FilePath -- ^ 'FilePath' to an SSL private key
          -> Socket -- ^ Socket to use
          -> Settings -- ^ Warp settings structure
          -> Application -- ^ WAI application
          -> IO ()
runSecure cert key sock set app = do
  settingsInstallShutdownHandler set (sClose sock) -- ignored by Warp's @runTLSSocket@
  runTLSSocket tset set sock app
  where tset = (tlsSettings cert key) { onInsecure = AllowInsecure }

-- |Serve a WAI app using Warp over unencrypted HTTP.
runInsecure :: Socket -- ^ Socket to use
            -> Settings -- ^ Warp settings structure
            -> Application -- ^ WAI application
            -> IO ()
runInsecure = flip runSettingsSocket