hastatic/src/Main.hs

97 lines
3.3 KiB
Haskell
Raw Normal View History

2018-07-21 09:12:42 +05:30
{-# LANGUAGE OverloadedStrings #-}
module Main where
2018-07-22 08:13:01 +05:30
import qualified Data.ByteString.Char8 as C8
2018-07-21 09:12:42 +05:30
import Data.Maybe (fromMaybe)
import qualified Data.List as List
import qualified Data.Text as T
2018-07-22 08:13:01 +05:30
import Data.Version (showVersion)
2018-07-21 09:12:42 +05:30
import Network.Wai
2018-07-21 19:00:42 +05:30
import qualified Network.Wai.Handler.WarpTLS as TLS
2018-07-21 09:12:42 +05:30
import Network.Wai.Middleware.Static
import Network.HTTP.Types (status404)
2018-07-22 08:13:01 +05:30
import Network.Wai.Handler.Warp ( runSettings
, defaultSettings
, setPort
, setFdCacheDuration
, setFileInfoCacheDuration
, setServerName
)
2018-07-21 19:00:42 +05:30
import System.Exit (die)
2018-07-21 09:12:42 +05:30
import System.Environment (lookupEnv)
import Text.Read (readMaybe)
2018-07-22 08:13:01 +05:30
import Paths_hastatic (version)
2018-07-21 09:12:42 +05:30
2018-07-21 19:00:42 +05:30
data TLS = Okay TLS.TLSSettings | Error String | None
2018-08-27 22:31:09 +05:30
addSecureHeaders :: Middleware
addSecureHeaders = modifyResponse $ mapResponseHeaders (++ secureHeaders)
where
secureHeaders = [ ("Referrer-Policy", "strict-origin-when-cross-origin")
, ("X-Frame-Options", "SAMEORIGIN")
, ("X-XSS-Protection", "1; mode=block")
]
2018-07-21 09:12:42 +05:30
indexHTML :: T.Text -> Middleware
indexHTML indexFile app req respond =
let path = pathInfo req
in flip app respond $ req { pathInfo = fixPath path }
where
fixPath path = case path of
[] -> [indexFile]
[""] -> [indexFile]
[x] -> if "." `T.isInfixOf` x then [x] else [x, indexFile]
(x:xs) -> x : fixPath xs
2018-07-21 19:00:42 +05:30
notFoundHandler :: FilePath -> Application
2018-07-21 09:12:42 +05:30
notFoundHandler notFoundFile _ respond = respond $
responseFile status404 [("Content-Type", "text/html")] notFoundFile Nothing
2018-07-21 19:00:42 +05:30
getTLSSettings :: IO TLS
getTLSSettings = do
tlsCertFile <- lookupEnv "TLS_CERT_FILE"
tlsKeyFile <- lookupEnv "TLS_KEY_FILE"
case (tlsCertFile, tlsKeyFile) of
(Nothing, Nothing) -> return None
(Just cert, Just key) -> return $ Okay $ TLS.tlsSettings cert key
_ -> return $ Error "Certificate file or Key file is missing"
application :: [FilePath] -> IO Application
application excludedPaths = do
notFoundFile <- fromMaybe "404.html" <$> lookupEnv "NF_FILE"
indexFile <- T.pack . fromMaybe "index.html" <$> lookupEnv "IDX_FILE"
cache <- initCaching PublicStaticCaching
return
2018-08-27 22:31:09 +05:30
. addSecureHeaders
2018-07-21 19:00:42 +05:30
. indexHTML indexFile
. staticPolicy' cache polcy
. notFoundHandler
$ notFoundFile
2018-07-21 09:12:42 +05:30
where
noDot = not . List.isPrefixOf "."
2018-07-21 19:00:42 +05:30
polcy = predicate noDot >-> predicate (not . flip elem excludedPaths)
main :: IO ()
main = do
2018-07-22 08:13:01 +05:30
mPort <- lookupEnv "PORT"
let port = fromMaybe 3000 (readMaybe =<< mPort)
tlsSettings <- getTLSSettings
let settings = setPort port
. setFdCacheDuration 10
. setFileInfoCacheDuration 10
. setServerName ("hastatic-" <> C8.pack (showVersion version))
$ defaultSettings
2018-07-21 19:00:42 +05:30
case tlsSettings of
Okay tls -> do
app <- application [TLS.certFile tls, TLS.keyFile tls]
putStrLn $ "Starting HTTPS server on port: " <> show port
2018-07-22 08:13:01 +05:30
TLS.runTLS tls settings app
2018-07-21 19:00:42 +05:30
None -> do
app <- application []
putStrLn $ "Starting HTTP server on port: " <> show port
2018-07-22 08:13:01 +05:30
runSettings settings app
2018-07-21 19:00:42 +05:30
Error msg ->
die $ "Error starting server: " <> msg