warp-3.2.5: Network/Wai/Handler/Warp.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE PatternGuards #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-}
---------------------------------------------------------
--
-- Module : Network.Wai.Handler.Warp
-- Copyright : Michael Snoyman
-- License : BSD3
--
-- Maintainer : Michael Snoyman <michael@snoyman.com>
-- Stability : Stable
-- Portability : portable
--
-- A fast, light-weight HTTP server handler for WAI.
--
---------------------------------------------------------
-- | A fast, light-weight HTTP server handler for WAI.
--
-- HTTP\/1.0, HTTP\/1.1 and HTTP\/2 are supported. For HTTP\/2,
-- Warp supports direct and ALPN (in TLS) but not upgrade.
--
-- Note on slowloris timeouts: to prevent slowloris attacks, timeouts are used
-- at various points in request receiving and response sending. One interesting
-- corner case is partial request body consumption; in that case, Warp's
-- timeout handling is still in effect, and the timeout will not be triggered
-- again. Therefore, it is recommended that once you start consuming the
-- request body, you either:
--
-- * consume the entire body promptly
--
-- * call the 'pauseTimeout' function
--
-- For more information, see <https://github.com/yesodweb/wai/issues/351>.
--
--
module Network.Wai.Handler.Warp (
-- * Run a Warp server
-- | All of these automatically serve the same 'Application' over HTTP\/1,
-- HTTP\/1.1, and HTTP\/2.
run
, runEnv
, runSettings
, runSettingsSocket
-- * Settings
, Settings
, defaultSettings
-- ** Setters
, setPort
, setHost
, setOnException
, setOnExceptionResponse
, setOnOpen
, setOnClose
, setTimeout
, setManager
, setFdCacheDuration
, setFileInfoCacheDuration
, setBeforeMainLoop
, setNoParsePath
, setInstallShutdownHandler
, setServerName
, setMaximumBodyFlush
, setFork
, setProxyProtocolNone
, setProxyProtocolRequired
, setProxyProtocolOptional
, setSlowlorisSize
, setHTTP2Disabled
, setLogger
-- ** Getters
, getPort
, getHost
, getOnOpen
, getOnClose
, getOnException
-- ** Exception handler
, defaultOnException
, defaultShouldDisplayException
-- ** Exception response handler
, defaultOnExceptionResponse
, exceptionResponseForDebug
-- * Data types
, HostPreference
, Port
, InvalidRequest (..)
-- * Utilities
, pauseTimeout
, FileInfo(..)
, getFileInfo
, withApplication
, testWithApplication
, openFreePort
-- * Version
, warpVersion
) where
import Control.Exception (SomeException, throwIO)
import Data.ByteString (ByteString)
import Data.Maybe (fromMaybe)
import Data.Streaming.Network (HostPreference)
import qualified Data.Vault.Lazy as Vault
import qualified Network.HTTP.Types as H
import Network.Socket (SockAddr)
import Network.Wai (Request, Response, vault)
import Network.Wai.Handler.Warp.FileInfoCache
import Network.Wai.Handler.Warp.Request
import Network.Wai.Handler.Warp.Response (warpVersion)
import Network.Wai.Handler.Warp.Run
import Network.Wai.Handler.Warp.Settings
import Network.Wai.Handler.Warp.Timeout
import Network.Wai.Handler.Warp.Types hiding (getFileInfo)
import Network.Wai.Handler.Warp.WithApplication
-- | Port to listen on. Default value: 3000
--
-- Since 2.1.0
setPort :: Port -> Settings -> Settings
setPort x y = y { settingsPort = x }
-- | Interface to bind to. Default value: HostIPv4
--
-- Since 2.1.0
setHost :: HostPreference -> Settings -> Settings
setHost x y = y { settingsHost = x }
-- | What to do with exceptions thrown by either the application or server.
-- Default: 'defaultOnException'
--
-- Since 2.1.0
setOnException :: (Maybe Request -> SomeException -> IO ()) -> Settings -> Settings
setOnException x y = y { settingsOnException = x }
-- | A function to create a `Response` when an exception occurs.
--
-- Default: 'defaultOnExceptionResponse'
--
-- Since 2.1.0
setOnExceptionResponse :: (SomeException -> Response) -> Settings -> Settings
setOnExceptionResponse x y = y { settingsOnExceptionResponse = x }
-- | What to do when a connection is opened. When 'False' is returned, the
-- connection is closed immediately. Otherwise, the connection is going on.
-- Default: always returns 'True'.
--
-- Since 2.1.0
setOnOpen :: (SockAddr -> IO Bool) -> Settings -> Settings
setOnOpen x y = y { settingsOnOpen = x }
-- | What to do when a connection is closed. Default: do nothing.
--
-- Since 2.1.0
setOnClose :: (SockAddr -> IO ()) -> Settings -> Settings
setOnClose x y = y { settingsOnClose = x }
-- | Timeout value in seconds. Default value: 30
--
-- Since 2.1.0
setTimeout :: Int -> Settings -> Settings
setTimeout x y = y { settingsTimeout = x }
-- | Use an existing timeout manager instead of spawning a new one. If used,
-- 'settingsTimeout' is ignored.
--
-- Since 2.1.0
setManager :: Manager -> Settings -> Settings
setManager x y = y { settingsManager = Just x }
-- | Cache duration time of file descriptors in seconds. 0 means that the cache mechanism is not used.
--
-- The FD cache is an optimization that is useful for servers dealing with
-- static files. However, if files are being modified, it can cause incorrect
-- results in some cases. Therefore, we disable it by default. If you know that
-- your files will be static or you prefer performance to file consistency,
-- it's recommended to turn this on; a reasonable value for those cases is 10.
-- Enabling this cache results in drastic performance improvement for file
-- transfers.
--
-- Default value: 0, was previously 10
--
-- Since 3.0.13
setFdCacheDuration :: Int -> Settings -> Settings
setFdCacheDuration x y = y { settingsFdCacheDuration = x }
-- | Cache duration time of file information in seconds. 0 means that the cache mechanism is not used.
--
-- The file information cache is an optimization that is useful for servers dealing with
-- static files. However, if files are being modified, it can cause incorrect
-- results in some cases. Therefore, we disable it by default. If you know that
-- your files will be static or you prefer performance to file consistency,
-- it's recommended to turn this on; a reasonable value for those cases is 10.
-- Enabling this cache results in drastic performance improvement for file
-- transfers.
--
-- Default value: 0
setFileInfoCacheDuration :: Int -> Settings -> Settings
setFileInfoCacheDuration x y = y { settingsFileInfoCacheDuration = x }
-- | Code to run after the listening socket is ready but before entering
-- the main event loop. Useful for signaling to tests that they can start
-- running, or to drop permissions after binding to a restricted port.
--
-- Default: do nothing.
--
-- Since 2.1.0
setBeforeMainLoop :: IO () -> Settings -> Settings
setBeforeMainLoop x y = y { settingsBeforeMainLoop = x }
-- | Perform no parsing on the rawPathInfo.
--
-- This is useful for writing HTTP proxies.
--
-- Default: False
--
-- Since 2.1.0
setNoParsePath :: Bool -> Settings -> Settings
setNoParsePath x y = y { settingsNoParsePath = x }
-- | Get the listening port.
--
-- Since 2.1.1
getPort :: Settings -> Port
getPort = settingsPort
-- | Get the interface to bind to.
--
-- Since 2.1.1
getHost :: Settings -> HostPreference
getHost = settingsHost
-- | Get the action on opening connection.
getOnOpen :: Settings -> SockAddr -> IO Bool
getOnOpen = settingsOnOpen
-- | Get the action on closeing connection.
getOnClose :: Settings -> SockAddr -> IO ()
getOnClose = settingsOnClose
-- | Get the exception handler.
getOnException :: Settings -> Maybe Request -> SomeException -> IO ()
getOnException = settingsOnException
-- | A code to install shutdown handler.
--
-- For instance, this code should set up a UNIX signal
-- handler. The handler should call the first argument,
-- which closes the listen socket, at shutdown.
--
-- Default: does not install any code.
--
-- Since 3.0.1
setInstallShutdownHandler :: (IO () -> IO ()) -> Settings -> Settings
setInstallShutdownHandler x y = y { settingsInstallShutdownHandler = x }
-- | Default server name if application does not set one.
--
-- Since 3.0.2
setServerName :: ByteString -> Settings -> Settings
setServerName x y = y { settingsServerName = x }
-- | The maximum number of bytes to flush from an unconsumed request body.
--
-- By default, Warp does not flush the request body so that, if a large body is
-- present, the connection is simply terminated instead of wasting time and
-- bandwidth on transmitting it. However, some clients do not deal with that
-- situation well. You can either change this setting to @Nothing@ to flush the
-- entire body in all cases, or in your application ensure that you always
-- consume the entire request body.
--
-- Default: 8192 bytes.
--
-- Since 3.0.3
setMaximumBodyFlush :: Maybe Int -> Settings -> Settings
setMaximumBodyFlush x y
| Just x' <- x, x' < 0 = error "setMaximumBodyFlush: must be positive"
| otherwise = y { settingsMaximumBodyFlush = x }
-- | Code to fork a new thread to accept a connection.
--
-- This may be useful if you need OS bound threads, or if
-- you wish to develop an alternative threading model.
--
-- Default: void . forkIOWithUnmask
--
-- Since 3.0.4
setFork :: (((forall a. IO a -> IO a) -> IO ()) -> IO ()) -> Settings -> Settings
setFork fork' s = s { settingsFork = fork' }
-- | Do not use the PROXY protocol.
--
-- Since 3.0.5
setProxyProtocolNone :: Settings -> Settings
setProxyProtocolNone y = y { settingsProxyProtocol = ProxyProtocolNone }
-- | Require PROXY header.
--
-- This is for cases where a "dumb" TCP/SSL proxy is being used, which cannot
-- add an @X-Forwarded-For@ HTTP header field but has enabled support for the
-- PROXY protocol.
--
-- See <http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt> and
-- <http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/TerminologyandKeyConcepts.html#proxy-protocol>.
--
-- Only the human-readable header format (version 1) is supported. The binary
-- header format (version 2) is /not/ supported.
--
-- Since 3.0.5
setProxyProtocolRequired :: Settings -> Settings
setProxyProtocolRequired y = y { settingsProxyProtocol = ProxyProtocolRequired }
-- | Use the PROXY header if it exists, but also accept
-- connections without the header. See 'setProxyProtocolRequired'.
--
-- WARNING: This is contrary to the PROXY protocol specification and
-- using it can indicate a security problem with your
-- architecture if the web server is directly accessable
-- to the public, since it would allow easy IP address
-- spoofing. However, it can be useful in some cases,
-- such as if a load balancer health check uses regular
-- HTTP without the PROXY header, but proxied
-- connections /do/ include the PROXY header.
--
-- Since 3.0.5
setProxyProtocolOptional :: Settings -> Settings
setProxyProtocolOptional y = y { settingsProxyProtocol = ProxyProtocolOptional }
-- | Size in bytes read to prevent Slowloris protection. Default value: 2048
--
-- Since 3.1.2
setSlowlorisSize :: Int -> Settings -> Settings
setSlowlorisSize x y = y { settingsSlowlorisSize = x }
-- | Disable HTTP2.
--
-- Since 3.1.7
setHTTP2Disabled :: Settings -> Settings
setHTTP2Disabled y = y { settingsHTTP2Enabled = False }
-- | Setting a log function. `Integer` is the body length of a response.
--
-- Since 3.X.X
setLogger :: (Request -> H.Status -> Maybe Integer -> IO ())
-> Settings -> Settings
setLogger lgr y = y { settingsLogger = lgr }
-- | Explicitly pause the slowloris timeout.
--
-- This is useful for cases where you partially consume a request body. For
-- more information, see <https://github.com/yesodweb/wai/issues/351>
--
-- Since 3.0.10
pauseTimeout :: Request -> IO ()
pauseTimeout = fromMaybe (return ()) . Vault.lookup pauseTimeoutKey . vault
-- | Getting file information of the target file.
--
-- This function first uses a stat(2) or similar system call
-- to obtain information of the target file, then registers
-- it into the internal cache.
-- From the next time, the information is obtained
-- from the cache. This reduces the overhead to call the system call.
-- The internal cache is refreshed every duration specified by
-- 'setFileInfoCacheDuration'.
--
-- This function throws an 'IO' exception if the information is not
-- available. For instance, the target file does not exist.
-- If this function is used an a Request generated by a WAI
-- backend besides Warp, it also throws an 'IO' exception.
--
-- Since 3.1.10
getFileInfo :: Request -> FilePath -> IO FileInfo
getFileInfo = fromMaybe (\_ -> throwIO (userError "getFileInfo")) . Vault.lookup getFileInfoKey . vault