packages feed

mighttpd2 3.4.6 → 4.0.0

raw patch · 16 files changed

+541/−210 lines, 16 filesdep +base16-bytestringdep +dhalldep +quicdep ~basedep ~wai-http2-extradep ~warpPVP ok

version bump matches the API change (PVP)

Dependencies added: base16-bytestring, dhall, quic, split, text, time-manager, unliftio, warp-quic

Dependency ranges changed: base, wai-http2-extra, warp, warp-tls

API changes (from Hackage documentation)

- Program.Mighty.Config: instance Program.Mighty.Config.FromConf GHC.Types.Int
- Program.Mighty.Report: finReporter :: Reporter -> IO ()
+ Program.Mighty.Config: [opt_quic_addr] :: Option -> [String]
+ Program.Mighty.Config: [opt_quic_debug_dir] :: Option -> Maybe FilePath
+ Program.Mighty.Config: [opt_quic_port] :: Option -> Natural
+ Program.Mighty.Config: [opt_quic_qlog_dir] :: Option -> Maybe FilePath
+ Program.Mighty.Config: instance Program.Mighty.Config.FromConf (GHC.Maybe.Maybe GHC.Base.String)
+ Program.Mighty.Config: instance Program.Mighty.Config.FromConf Program.Mighty.Types.Natural
+ Program.Mighty.Config: instance Program.Mighty.Config.FromConf [GHC.Base.String]
+ Program.Mighty.Config: type Natural = Int
+ Program.Mighty.Types: naturalToInt :: Natural -> Int
+ Program.Mighty.Types: type Natural = Int
- Program.Mighty.Config: Option :: !Int -> !String -> !Bool -> !String -> !String -> !FilePath -> !FilePath -> !Bool -> !FilePath -> !Int -> !Int -> !FilePath -> !FilePath -> !FilePath -> !Int -> !Int -> !Int -> !String -> !Maybe FilePath -> !Int -> !FilePath -> !FilePath -> !FilePath -> !Int -> Option
+ Program.Mighty.Config: Option :: Natural -> String -> Bool -> String -> String -> FilePath -> FilePath -> Bool -> FilePath -> Natural -> Natural -> FilePath -> FilePath -> FilePath -> Natural -> Natural -> Natural -> Natural -> Natural -> FilePath -> FilePath -> FilePath -> Natural -> [String] -> Maybe FilePath -> Maybe FilePath -> String -> Maybe String -> Option
- Program.Mighty.Config: [opt_connection_timeout] :: Option -> !Int
+ Program.Mighty.Config: [opt_connection_timeout] :: Option -> Natural
- Program.Mighty.Config: [opt_debug_mode] :: Option -> !Bool
+ Program.Mighty.Config: [opt_debug_mode] :: Option -> Bool
- Program.Mighty.Config: [opt_fd_cache_duration] :: Option -> !Int
+ Program.Mighty.Config: [opt_fd_cache_duration] :: Option -> Natural
- Program.Mighty.Config: [opt_group] :: Option -> !String
+ Program.Mighty.Config: [opt_group] :: Option -> String
- Program.Mighty.Config: [opt_host] :: Option -> !String
+ Program.Mighty.Config: [opt_host] :: Option -> String
- Program.Mighty.Config: [opt_index_cgi] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_index_cgi] :: Option -> FilePath
- Program.Mighty.Config: [opt_index_file] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_index_file] :: Option -> FilePath
- Program.Mighty.Config: [opt_log_backup_number] :: Option -> !Int
+ Program.Mighty.Config: [opt_log_backup_number] :: Option -> Natural
- Program.Mighty.Config: [opt_log_file] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_log_file] :: Option -> FilePath
- Program.Mighty.Config: [opt_log_file_size] :: Option -> !Int
+ Program.Mighty.Config: [opt_log_file_size] :: Option -> Natural
- Program.Mighty.Config: [opt_logging] :: Option -> !Bool
+ Program.Mighty.Config: [opt_logging] :: Option -> Bool
- Program.Mighty.Config: [opt_pid_file] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_pid_file] :: Option -> FilePath
- Program.Mighty.Config: [opt_port] :: Option -> !Int
+ Program.Mighty.Config: [opt_port] :: Option -> Natural
- Program.Mighty.Config: [opt_proxy_timeout] :: Option -> !Int
+ Program.Mighty.Config: [opt_proxy_timeout] :: Option -> Natural
- Program.Mighty.Config: [opt_report_file] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_report_file] :: Option -> FilePath
- Program.Mighty.Config: [opt_routing_file] :: Option -> !Maybe FilePath
+ Program.Mighty.Config: [opt_routing_file] :: Option -> Maybe String
- Program.Mighty.Config: [opt_server_name] :: Option -> !String
+ Program.Mighty.Config: [opt_server_name] :: Option -> String
- Program.Mighty.Config: [opt_service] :: Option -> !Int
+ Program.Mighty.Config: [opt_service] :: Option -> Natural
- Program.Mighty.Config: [opt_status_file_dir] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_status_file_dir] :: Option -> FilePath
- Program.Mighty.Config: [opt_tls_cert_file] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_tls_cert_file] :: Option -> FilePath
- Program.Mighty.Config: [opt_tls_chain_files] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_tls_chain_files] :: Option -> FilePath
- Program.Mighty.Config: [opt_tls_key_file] :: Option -> !FilePath
+ Program.Mighty.Config: [opt_tls_key_file] :: Option -> FilePath
- Program.Mighty.Config: [opt_tls_port] :: Option -> !Int
+ Program.Mighty.Config: [opt_tls_port] :: Option -> Natural
- Program.Mighty.Config: [opt_user] :: Option -> !String
+ Program.Mighty.Config: [opt_user] :: Option -> String
- Program.Mighty.Config: defaultOption :: String -> Option
+ Program.Mighty.Config: defaultOption :: Option
- Program.Mighty.Config: parseOption :: FilePath -> String -> IO Option
+ Program.Mighty.Config: parseOption :: FilePath -> IO Option
- Program.Mighty.Report: initReporter :: Bool -> FilePath -> IO (Either SomeException Reporter)
+ Program.Mighty.Report: initReporter :: Bool -> FilePath -> Reporter
- Program.Mighty.Resource: setGroupUser :: String -> String -> IO ()
+ Program.Mighty.Resource: setGroupUser :: String -> String -> IO Bool

Files

Program/Mighty.hs view
@@ -12,6 +12,7 @@   , module Program.Mighty.Process   , module Program.Mighty.Resource   , module Program.Mighty.Signal+  , module Program.Mighty.Types   ) where  import Program.Mighty.ByteString@@ -23,3 +24,4 @@ import Program.Mighty.Resource import Program.Mighty.Route import Program.Mighty.Signal+import Program.Mighty.Types
Program/Mighty/Config.hs view
@@ -1,87 +1,153 @@-{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, OverloadedStrings #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}  module Program.Mighty.Config (   -- * Parsing a configuration file.     parseOption+#ifdef DHALL+  , parseOptionDhall+#else+  , Natural+#endif   -- * Creating 'Option'.   , defaultOption   -- * Types   , Option(..)   ) where -#if __GLASGOW_HASKELL__ < 709-import Control.Applicative hiding (many,optional,(<|>))-#endif-import Program.Mighty.Parser+import Data.List.Split (splitOn) import Text.Parsec import Text.Parsec.ByteString.Lazy+#ifdef DHALL+import Data.String (fromString)+import qualified Data.Text as T+import Dhall(Generic, Natural, input, auto, FromDhall)+import qualified Program.Mighty.Dhall.Option as Do +#else+import Program.Mighty.Types+#endif++import Program.Mighty.Parser+ ---------------------------------------------------------------- +data Option = Option {+    opt_port :: Natural+  , opt_host :: String+  , opt_debug_mode :: Bool+  , opt_user  :: String+  , opt_group :: String+  , opt_pid_file    :: FilePath+  , opt_report_file :: FilePath+  , opt_logging :: Bool+  , opt_log_file :: FilePath+  , opt_log_file_size :: Natural+  , opt_log_backup_number :: Natural+  , opt_index_file :: FilePath+  , opt_index_cgi  :: FilePath+  , opt_status_file_dir :: FilePath+  , opt_connection_timeout :: Natural+  , opt_proxy_timeout      :: Natural+  , opt_fd_cache_duration  :: Natural+  , opt_service :: Natural+  , opt_tls_port :: Natural+  , opt_tls_cert_file   :: FilePath+  , opt_tls_chain_files :: FilePath+  , opt_tls_key_file    :: FilePath+  , opt_quic_port :: Natural+  , opt_quic_addr :: [String]+  , opt_quic_debug_dir :: Maybe FilePath+  , opt_quic_qlog_dir  :: Maybe FilePath+  , opt_server_name :: String+  , opt_routing_file :: Maybe String+#ifdef DHALL+} deriving (Eq, Show, Generic)+#else+} deriving (Eq, Show)+#endif++#ifdef DHALL+instance FromDhall Option+#endif+ -- | Getting a default 'Option'.-defaultOption :: String -- ^ A default server name (e.g. \"Mighttpd/3.0.0\")-              -> Option-defaultOption svrnm = Option {+defaultOption :: Option+defaultOption = Option {     opt_port = 8080   , opt_host = "*"   , opt_debug_mode = True-  , opt_user = "root"+  , opt_user  = "root"   , opt_group = "root"-  , opt_pid_file = "/var/run/mighty.pid"+  , opt_pid_file    = "/var/run/mighty.pid"   , opt_report_file = "/tmp/mighty_report"   , opt_logging = True   , opt_log_file = "/var/log/mighty"   , opt_log_file_size = 16777216   , opt_log_backup_number = 10   , opt_index_file = "index.html"-  , opt_index_cgi = "index.cgi"+  , opt_index_cgi  = "index.cgi"   , opt_status_file_dir = "/usr/local/share/mighty/status"   , opt_connection_timeout = 30-  , opt_proxy_timeout = 0-  , opt_fd_cache_duration = 10-  , opt_server_name = svrnm-  , opt_routing_file = Nothing+  , opt_proxy_timeout      = 0+  , opt_fd_cache_duration  = 10+  , opt_service = 0   , opt_tls_port = 443-  , opt_tls_cert_file = "cert.pem"+  , opt_tls_cert_file   = "cert.pem"   , opt_tls_chain_files = "chain.pem"-  , opt_tls_key_file = "privkey.pem"-  , opt_service = 0+  , opt_tls_key_file    = "privkey.pem"+  , opt_quic_port = 443+  , opt_quic_addr = ["127.0.0.1"]+  , opt_quic_debug_dir = Nothing+  , opt_quic_qlog_dir  = Nothing+  , opt_server_name = "Dummy"+  , opt_routing_file = Nothing } -data Option = Option {-    opt_port :: !Int-  , opt_host :: !String-  , opt_debug_mode :: !Bool-  , opt_user :: !String-  , opt_group :: !String-  , opt_pid_file :: !FilePath-  , opt_report_file :: !FilePath-  , opt_logging :: !Bool-  , opt_log_file :: !FilePath-  , opt_log_file_size :: !Int-  , opt_log_backup_number :: !Int-  , opt_index_file :: !FilePath-  , opt_index_cgi  :: !FilePath-  , opt_status_file_dir :: !FilePath-  , opt_connection_timeout :: !Int-  , opt_proxy_timeout :: !Int-  , opt_fd_cache_duration :: !Int-  , opt_server_name :: !String-  , opt_routing_file :: !(Maybe FilePath)-  , opt_tls_port :: !Int-  , opt_tls_cert_file :: !FilePath-  , opt_tls_chain_files :: !FilePath-  , opt_tls_key_file :: !FilePath-  , opt_service :: !Int-} deriving (Eq,Show)- ----------------------------------------------------------------- -- | Parsing a configuration file to get an 'Option'.-parseOption :: FilePath -> String -> IO Option-parseOption file svrnm = makeOpt (defaultOption svrnm) <$> parseConfig file+parseOption :: FilePath -> IO Option+parseOption file = makeOpt defaultOption <$> parseConfig file +#ifdef DHALL+parseOptionDhall :: FilePath -> IO Option+parseOptionDhall = fmap optionFromDhall . input auto . fromString++optionFromDhall :: Do.Option -> Option+optionFromDhall o = Option+  { opt_port = Do.port o+  , opt_host = T.unpack $ Do.host o+  , opt_debug_mode = Do.debugMode o+  , opt_user  = T.unpack $ Do.user o+  , opt_group = T.unpack $ Do.group o+  , opt_pid_file    = T.unpack $ Do.pidFile o+  , opt_report_file = T.unpack $ Do.reportFile o+  , opt_logging = Do.logging o+  , opt_log_file = T.unpack $ Do.logFile o+  , opt_log_file_size = Do.logFileSize o+  , opt_log_backup_number = Do.logBackupNumber o+  , opt_index_file = T.unpack $ Do.indexFile o+  , opt_index_cgi  = T.unpack $ Do.indexCgi o+  , opt_status_file_dir = T.unpack $ Do.statusFileDir o+  , opt_connection_timeout = Do.connectionTimeout o+  , opt_proxy_timeout      = Do.proxyTimeout o+  , opt_fd_cache_duration  = Do.fdCacheDuration o+  , opt_service = Do.service o+  , opt_tls_port = Do.tlsPort o+  , opt_tls_cert_file   = T.unpack $ Do.tlsCertFile o+  , opt_tls_chain_files = T.unpack $ Do.tlsChainFiles o+  , opt_tls_key_file    = T.unpack $ Do.tlsKeyFile o+  , opt_quic_addr = T.unpack <$> Do.quicAddr o+  , opt_quic_port = Do.quicPort o+  , opt_quic_debug_dir = T.unpack <$> Do.quicDebugDir o+  , opt_quic_qlog_dir  = T.unpack <$> Do.quicQlogDir o+  , opt_server_name = "Dummy"+  , opt_routing_file = Nothing+}+#endif+ ----------------------------------------------------------------  makeOpt :: Option -> [Conf] -> Option@@ -103,13 +169,17 @@   , opt_connection_timeout = get "Connection_Timeout" opt_connection_timeout   , opt_proxy_timeout      = get "Proxy_Timeout" opt_proxy_timeout   , opt_fd_cache_duration  = get "Fd_Cache_Duration" opt_fd_cache_duration-  , opt_server_name        = get "Server_Name" opt_server_name-  , opt_routing_file       = Nothing+  , opt_service            = get "Service" opt_service   , opt_tls_port           = get "Tls_Port" opt_tls_port   , opt_tls_cert_file      = get "Tls_Cert_File" opt_tls_cert_file   , opt_tls_chain_files    = get "Tls_Chain_Files" opt_tls_chain_files   , opt_tls_key_file       = get "Tls_Key_File" opt_tls_key_file-  , opt_service            = get "Service" opt_service+  , opt_quic_addr          = get "Quic_Addr" opt_quic_addr+  , opt_quic_port          = get "Quic_Port" opt_quic_port+  , opt_quic_debug_dir     = get "Quic_Debug_Dir" opt_quic_debug_dir+  , opt_quic_qlog_dir      = get "Quic_Qlog_Dir" opt_quic_qlog_dir+  , opt_server_name        = "Dummy"+  , opt_routing_file       = Nothing   }   where     get k func = maybe (func def) fromConf $ lookup k conf@@ -118,13 +188,13 @@  type Conf = (String, ConfValue) -data ConfValue = CV_Int Int | CV_Bool Bool | CV_String String deriving (Eq,Show)+data ConfValue = CV_Natural Natural | CV_Bool Bool | CV_String String deriving (Eq,Show)  class FromConf a where     fromConf :: ConfValue -> a -instance FromConf Int where-    fromConf (CV_Int n) = n+instance FromConf Natural where+    fromConf (CV_Natural n) = n     fromConf _ = error "fromConf int"  instance FromConf Bool where@@ -135,6 +205,15 @@     fromConf (CV_String s) = s     fromConf _ = error "fromConf string" +instance FromConf (Maybe String) where+    fromConf (CV_String "") = Nothing+    fromConf (CV_String s)  = Just s+    fromConf _ = error "fromConf string"++instance FromConf [String] where+    fromConf (CV_String s)  = splitOn "," s+    fromConf _ = error "fromConf string"+ ----------------------------------------------------------------  parseConfig :: FilePath -> IO [Conf]@@ -157,15 +236,15 @@ sep = () <$ char ':' *> spcs  value :: Parser ConfValue-value = choice [try cv_int, try cv_bool, cv_string]+value = choice [try cv_natural, try cv_bool, cv_string]  -- Trailing should be included in try to allow IP addresses.-cv_int :: Parser ConfValue-cv_int = CV_Int . read <$> many1 digit <* trailing+cv_natural :: Parser ConfValue+cv_natural = CV_Natural . read <$> many1 digit <* trailing  cv_bool :: Parser ConfValue cv_bool = CV_Bool True  <$ string "Yes" <* trailing <|>-          CV_Bool False <$ string "No"   <* trailing+          CV_Bool False <$ string "No"  <* trailing  cv_string :: Parser ConfValue cv_string = CV_String <$> many (noneOf " \t\n") <* trailing
+ Program/Mighty/Dhall/Option.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE DeriveAnyClass     #-}+{-# LANGUAGE DeriveGeneric      #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings  #-}+{-# LANGUAGE TemplateHaskell    #-}+{-# LANGUAGE CPP                #-}++module Program.Mighty.Dhall.Option where++#ifdef DHALL+import Dhall.TH++Dhall.TH.makeHaskellTypes+    [ SingleConstructor "Option" "MakeOption" "./Program/Mighty/Dhall/Option.dhall"+    ]+#endif
Program/Mighty/Parser.hs view
@@ -14,14 +14,11 @@   , comment   ) where -#if __GLASGOW_HASKELL__ < 709-import Control.Applicative hiding (many,(<|>))-#endif-import Control.Exception import qualified Data.ByteString.Lazy.Char8 as BL import System.IO import Text.Parsec import Text.Parsec.ByteString.Lazy+import UnliftIO.Exception  -- $setup -- >>> import Data.Either
Program/Mighty/Process.hs view
@@ -1,13 +1,10 @@-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Program.Mighty.Process (     getMightyPid   ) where -#if __GLASGOW_HASKELL__ < 709-import Control.Applicative-#endif import Control.Monad.Trans.Resource (runResourceT) import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as BS@@ -17,7 +14,6 @@ import Data.Conduit.Process import Data.Function import Data.List-import Data.Ord import System.Posix.Types  ----------------------------------------------------------------@@ -65,7 +61,7 @@     candidates = map head                $ filter (\xs -> length xs == 1) -- master is alone                $ groupBy ((==) `on` ppid)-               $ sortBy (comparing ppid) rest+               $ sortOn ppid rest   deleteAloneChild :: [PsResult] -> [PsResult]@@ -79,7 +75,7 @@  -- | Getting the process id of a running Mighty. getMightyPid :: IO [ProcessID]-getMightyPid = (map pid . findParent) <$> runPS+getMightyPid = map pid . findParent <$> runPS  ---------------------------------------------------------------- 
Program/Mighty/Report.hs view
@@ -1,10 +1,10 @@-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}  module Program.Mighty.Report (     Reporter   , initReporter-  , finReporter   , report   , reportDo   , warpHandler@@ -14,8 +14,6 @@ #if __GLASGOW_HASKELL__ < 709 import Control.Applicative #endif-import Control.Exception-import qualified Control.Exception as E (catch) import Control.Monad import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BS@@ -23,65 +21,46 @@ import GHC.IO.Exception (IOErrorType(..)) import Network.Wai import Network.Wai.Handler.Warp (InvalidRequest)-import Network.Wai.Handler.Warp.Internal (TimeoutThread(..)) import System.IO import System.IO.Error (ioeGetErrorType) import System.Posix (getProcessID)+import UnliftIO.Exception  import Program.Mighty.ByteString  data Method = FileOnly | FileAndStdout deriving Eq-data Reporter = Reporter Method Handle+data Reporter = Reporter Method FilePath -initReporter :: Bool -> FilePath -> IO (Either SomeException Reporter)-initReporter debug reportFile = try $ Reporter method <$> openFile reportFile AppendMode+initReporter :: Bool -> FilePath -> Reporter+initReporter debug reportFile = Reporter method reportFile   where     method       | debug     = FileAndStdout       | otherwise = FileOnly -finReporter :: Reporter -> IO ()-finReporter (Reporter _ rpthdl) = hClose rpthdl- report :: Reporter -> ByteString -> IO ()-report (Reporter method rpthdl) msg = handle (\(SomeException _) -> return ()) $ do+report (Reporter method reportFile) msg = handle (\(SomeException _) -> return ()) $ do     pid <- BS.pack . show <$> getProcessID     tm <- getUnixTime >>= formatUnixTime "%d %b %Y %H:%M:%S"     let logmsg = BS.concat [tm, ": pid = ", pid, ": ", msg, "\n"]-    BS.hPutStr rpthdl logmsg-    hFlush rpthdl+    BS.appendFile reportFile logmsg     when (method == FileAndStdout) $ BS.putStr logmsg  ----------------------------------------------------------------  reportDo :: Reporter -> IO () -> IO ()-reportDo rpt act = act `E.catch` warpHandler rpt Nothing+reportDo rpt act = act `catchAny` warpHandler rpt Nothing  ----------------------------------------------------------------  warpHandler :: Reporter -> Maybe Request -> SomeException -> IO ()-warpHandler rpt _ e = throwIO e `catches` handlers-  where-    handlers = [Handler ah, Handler th, Handler ih, Handler oh, Handler sh]-    ah :: AsyncException -> IO ()-    ah ThreadKilled = norecode-    ah x            = recode x-    th :: TimeoutThread -> IO ()-    th TimeoutThread = norecode-    ih :: InvalidRequest -> IO ()-    ih _ = norecode-    oh :: IOException -> IO ()-    oh x-      | et `elem` ignEts = norecode-      | otherwise        = recode x-      where-        et = ioeGetErrorType x-        ignEts = [ResourceVanished, InvalidArgument]-    sh :: SomeException -> IO ()-    sh x = recode x-    norecode = return ()-    recode :: Exception e => e -> IO ()-    recode   = report rpt . bshow+warpHandler rpt _ se+  | Just (_ :: InvalidRequest) <- fromException se = return ()+  | Just (e :: IOException)    <- fromException se =+        if ioeGetErrorType e `elem` [ResourceVanished,InvalidArgument]+        then return ()+        else report rpt $ bshow se+  | otherwise = report rpt $ bshow se  ---------------------------------------------------------------- 
Program/Mighty/Resource.hs view
@@ -6,12 +6,8 @@   , unlimit   ) where -#if __GLASGOW_HASKELL__ < 709-import Control.Applicative-#endif-import Control.Exception-import Control.Monad import System.Posix+import UnliftIO.Exception  ---------------------------------------------------------------- @@ -24,12 +20,15 @@ -- | Setting user and group. setGroupUser :: String -- ^ User              -> String -- ^ Group-             -> IO ()+             -> IO Bool setGroupUser user group = do     root <- amIrootUser-    when root $ do+    if root then do         getGroupEntryForName group >>= setGroupID . groupID         getUserEntryForName user >>= setUserID . userID+        return True+      else+        return False  ---------------------------------------------------------------- 
Program/Mighty/Route.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE OverloadedStrings, TupleSections #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}  module Program.Mighty.Route (   -- * Paring a routing file@@ -19,13 +20,13 @@   , writeRouteDBRef   ) where -#if __GLASGOW_HASKELL__ < 709-import Control.Applicative hiding (many,(<|>))-#endif import Control.Monad import Data.ByteString import qualified Data.ByteString.Char8 as BS import Data.IORef+#ifdef DHALL+import GHC.Natural (Natural)+#endif import Network.Wai.Application.Classic import Text.Parsec import Text.Parsec.ByteString.Lazy@@ -39,7 +40,12 @@ -- | A physical path in a file system. type Dst      = Path type Domain   = ByteString+#ifdef DHALL+type Port     = Natural+#else type Port     = Int+#endif+ data Block    = Block [Domain] [Route] deriving (Eq,Show) data Route    = RouteFile     Src Dst               | RouteRedirect Src Dst
+ Program/Mighty/Types.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE CPP #-}++module Program.Mighty.Types (Natural, naturalToInt) where++#ifdef DHALL+import GHC.Natural (Natural, naturalToInt)+#else+type Natural = Int++naturalToInt :: Natural -> Int+naturalToInt = id+#endif
+ cbits/setcap.c view
@@ -0,0 +1,53 @@+#if defined(__linux__)+#include <linux/securebits.h>+#include <signal.h>+#include <stdio.h>+#include <string.h>+#include <sys/capability.h>+#include <sys/prctl.h>+#include <sys/syscall.h>+#include <sys/types.h>+#include <unistd.h>++#include "Rts.h"++void set_capabilities (uint32_t cap) {+  cap_user_header_t header = malloc(sizeof(*header));+  header->version = _LINUX_CAPABILITY_VERSION_3;+  header->pid = 0;++  cap_user_data_t data = malloc(sizeof(*data));+  data->effective   = cap;+  data->permitted   = cap;+  data->inheritable = 0;++  capset(header,data);++  free(header);+  free(data);+}++void handler(int signum) {+  uint32_t cap = 1 << CAP_NET_BIND_SERVICE;+  set_capabilities (cap);+}++void FlagDefaultsHook () {+  if (geteuid() == 0) {+    prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS, 0L, 0L, 0L);++    struct sigaction sa;+    memset(&sa, 0, sizeof(sa));+    sa.sa_handler = handler;+    sa.sa_flags = SA_RESTART;+    sigaction(SIGUSR1, &sa, NULL);+  }+}++void send_signal (int tid, int sig) {+  int tgid = getpid();+  syscall(SYS_tgkill, tgid, tid, sig);+}+#else+void send_signal (int tid, int sig) {}+#endif
conf/example.conf view
@@ -3,14 +3,15 @@ # IP address or "*" Host: * Debug_Mode: Yes # Yes or No-# If available, "nobody" is much more secure for User:.+# If available, "nobody" is much more secure for User: User: root-# If available, "nobody" is much more secure for Group:.+# If available, "nobody" is much more secure for Group: Group: root Pid_File: /var/run/mighty.pid Report_File: /tmp/mighty_report Logging: Yes # Yes or No-Log_File: /var/log/mighty # The directory must be writable by User:+# The directory must be writable by User:+Log_File: /var/log/mighty Log_File_Size: 16777216 # bytes Log_Backup_Number: 10 Index_File: index.html@@ -19,11 +20,19 @@ Connection_Timeout: 30 # seconds Proxy_Timeout: 0 # seconds, 0 is default of http-client, ie 30 seconds Fd_Cache_Duration: 10 # seconds-# Server_Name: Mighttpd/3.x.y+# 0 is HTTP only+# 1 is HTTPS only+# 2 is for both HTTP and HTTPs+# 3 is for HTTP, HTTPs and QUIC(HTTP/3)+Service: 0 Tls_Port: 443-Tls_Cert_File: cert.pem # should change this with an absolute path+# should change this with an absolute path+Tls_Cert_File: cert.pem # should change this with comma-separated absolute paths Tls_Chain_Files: chain.pem-# Currently, Tls_Key_File must not be encrypted.+# Currently, Tls_Key_File must not be encrypted Tls_Key_File: privkey.pem # should change this with an absolute path-Service: 0 # 0 is HTTP only, 1 is HTTPS only, 2 is both+Quic_Addr: 127.0.0.1,::1+Quic_Port: 443+#Quic_Debug_Dir: /var/log/mighy/quic-debug/+#Quic_Qlog_Dir: /varlog/mighty/qlog/
mighttpd2.cabal view
@@ -1,5 +1,5 @@ Name:                   mighttpd2-Version:                3.4.6+Version:                4.0.0 Author:                 Kazu Yamamoto <kazu@iij.ad.jp> Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp> License:                BSD3@@ -9,7 +9,7 @@                         files and CGI on WAI/warp.                         Reverse proxy functionality is also provided                         to connect web applications behind.-Homepage:               http://www.mew.org/~kazu/proj/mighttpd/+Homepage:               https://kazu-yamamoto.github.io/mighttpd2/ Category:               Network, Web Cabal-Version:          >= 1.10 Build-Type:             Simple@@ -17,9 +17,17 @@ Data-Files:             example.conf example.route  Flag tls-  Description:          Support http over tls (https).+  Description:          Support HTTP over TLS (HTTPS).   Default:              False +Flag quic+  Description:          Support HTTP over QUIC (HTTP/3).+  Default:              False++Flag dhall+  Description:          Support Dhall+  Default:              False+ Library   Default-Language:     Haskell2010   GHC-Options:          -Wall@@ -33,6 +41,8 @@                         Program.Mighty.Resource                         Program.Mighty.Route                         Program.Mighty.Signal+                        Program.Mighty.Dhall.Option+                        Program.Mighty.Types   Build-Depends:        base >= 4.9 && < 5                       , array                       , async@@ -50,14 +60,20 @@                       , parsec >= 3                       , resourcet                       , streaming-commons+                      , split+                      , text                       , unix                       , unix-time                       , unordered-containers                       , wai >= 3.2 && < 3.3                       , wai-app-file-cgi >= 3.1.9 && < 3.2-                      , warp >= 3.3 && < 3.4+                      , warp >= 3.3.15 && < 3.4+                      , unliftio   if impl(ghc >= 8)     Default-Extensions:  Strict StrictData+  if flag(dhall)+    Cpp-Options:        -DDHALL+    Build-Depends:      dhall  Executable mighty   Default-Language:     Haskell2010@@ -68,7 +84,18 @@     Cpp-Options:        -DHTTP_OVER_TLS     Build-Depends:      async                       , tls-session-manager >= 0.0.2.0-  Build-Depends:        base >= 4.0 && < 5+  if flag(quic)+    Cpp-Options:        -DHTTP_OVER_QUIC+    Build-Depends:      async+                      , base16-bytestring+    if os(linux)+      C-sources:        cbits/setcap.c+      Cpp-Options:      -DDROP_EXCEPT_BIND++  if flag(dhall)+    Cpp-Options:        -DDHALL+    Build-Depends:      dhall+  Build-Depends:        base >= 4.9 && < 5                       , bytestring                       , directory                       , filepath@@ -81,14 +108,18 @@                       , transformers                       , unix                       , streaming-commons+                      , time-manager                       , wai >= 3.2 && < 3.3                       , wai-app-file-cgi >= 3.1.9 && < 3.2                       , wai-logger >= 2.3.0-                      , warp >= 3.3 && < 3.4-                      , wai-http2-extra >= 0.1+                      , warp >= 3.3.13 && < 3.4+                      , wai-http2-extra >= 0.1.3   if flag(tls)     Build-Depends:      tls-                      , warp-tls >= 3.2.7 && < 3.3+                      , warp-tls >= 3.2.12 && < 3.4+  if flag(quic)+    Build-Depends:      quic+                      , warp-quic   Other-Modules:        Server                         WaiApp                         Paths_mighttpd2@@ -100,7 +131,7 @@   HS-Source-Dirs:       utils, src   Main-Is:              mkindex.hs   GHC-Options:          -Wall-  Build-Depends:        base >= 4 && < 5+  Build-Depends:        base >= 4.9 && < 5                       , directory                       , old-locale                       , time@@ -111,7 +142,7 @@   HS-Source-Dirs:       utils, src   Main-Is:              mightyctl.hs   GHC-Options:          -Wall-  Build-Depends:        base >= 4 && < 5+  Build-Depends:        base >= 4.9 && < 5                       , unix                       , mighttpd2   if impl(ghc >= 8)@@ -124,15 +155,18 @@   Type:                 exitcode-stdio-1.0   Other-Modules:        ConfigSpec                         RouteSpec-  Build-Depends:        base >= 4 && < 5+  Build-Depends:        base >= 4.9 && < 5                       , hspec >= 1.3                       , mighttpd2                       , http-client >= 0.5   if flag(tls)     Build-Depends:      tls-                      , warp-tls >= 3.2.7 && < 3.3+                      , warp-tls >= 3.2.12 && < 3.4   if impl(ghc >= 8)     Default-Extensions:  Strict StrictData+  if flag(dhall)+    Cpp-Options:        -DDHALL+    Build-Depends:      dhall  Source-Repository head   Type:                 git
src/Mighty.hs view
@@ -1,10 +1,15 @@-{-# LANGUAGE OverloadedStrings, CPP #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Main where -#ifndef HTTP_OVER_TLS+#ifndef HTTP_OVER_QUIC import Control.Monad (when) #endif++#ifdef DHALL+import Data.List (isSuffixOf)+#endif import Data.Version (showVersion) import Network.Wai.Application.Classic hiding ((</>)) import System.Directory (getCurrentDirectory)@@ -34,8 +39,8 @@     checkTLS opt     let reportFile = reportFileName opt         debug = opt_debug_mode opt-    rpt <- initReporter debug reportFile >>= checkReporter reportFile-    let run = server opt rpt route+        rpt = initReporter debug reportFile+        run = server opt rpt route     if debug then run else background opt run   where     getOptRoute = getArgs >>= eachCase@@ -43,8 +48,9 @@     eachCase args       | n == 0 = do           root <- amIrootUser-          let opt | root      = (defaultOption svrnm) { opt_port = 80 }-                  | otherwise = defaultOption svrnm+          let opt0 = defaultOption { opt_server_name = svrnm }+          let opt | root      = opt0 { opt_port = 80 }+                  | otherwise = opt0           dir <- getCurrentDirectory           let dst = fromString . addTrailingPathSeparator $ dir               route = [Block ["*"] [RouteFile "/" dst]]@@ -52,9 +58,18 @@       | n == 2 = do           let config_file = args !! 0           routing_file <- getAbsoluteFile (args !! 1)-          opt   <- parseOption config_file svrnm+#ifdef DHALL+          let isDhall = ".dhall" `Data.List.isSuffixOf` config_file+          opt   <- if isDhall+                   then parseOptionDhall config_file+                   else parseOption config_file+#else+          opt   <- parseOption config_file+#endif           route <- parseRoute  routing_file defaultDomain defaultPort-          let opt' = opt {opt_routing_file = Just routing_file}+          let opt' = opt { opt_routing_file = Just routing_file+                         , opt_server_name = svrnm+                         }           return (opt',route)       | otherwise = do           hPutStrLn stderr "Usage: mighty"@@ -67,13 +82,14 @@       | otherwise       = do           dir <- getCurrentDirectory           return $ dir </> normalise file-    checkReporter _          (Right rpt) = return rpt-    checkReporter reportFile (Left e)    = do-        hPutStrLn stderr $ reportFile ++ " is not writable"-        hPrint stderr e-        exitFailure #ifdef HTTP_OVER_TLS+#ifdef HTTP_OVER_QUIC     checkTLS _ = return ()+#else+    checkTLS opt = when (opt_service opt > 2) $ do+        hPutStrLn stderr "This mighty does not support QUIC"+        exitFailure+#endif #else     checkTLS opt = when (opt_service opt > 1) $ do         hPutStrLn stderr "This mighty does not support TLS"
src/Server.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE OverloadedStrings, CPP, BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}  module Server (server, defaultDomain, defaultPort) where @@ -6,13 +8,9 @@ import Control.Exception (try) import Control.Monad (unless, when) import qualified Data.ByteString.Char8 as BS-#ifdef HTTP_OVER_TLS-import Data.Char (isSpace)-import Data.List (dropWhile, dropWhileEnd, break)-#endif import Data.Streaming.Network (bindPortTCP)-import Network.Socket (Socket, close) import qualified Network.HTTP.Client as H+import Network.Socket (Socket, close) import Network.Wai.Application.Classic hiding ((</>)) import Network.Wai.Handler.Warp import Network.Wai.Logger@@ -21,6 +19,7 @@ import System.IO.Error (ioeGetErrorString) import System.Posix (exitImmediately, Handler(..), getProcessID, setFileMode) import System.Posix.Signals (sigCHLD)+import qualified System.TimeManager as T  import Program.Mighty import WaiApp@@ -28,12 +27,32 @@ import qualified Network.Wai.Middleware.Push.Referer as P  #ifdef HTTP_OVER_TLS-import Control.Concurrent.Async (concurrently)-import Control.Monad (void)-import Network.Wai.Handler.WarpTLS+import Control.Concurrent.Async (concurrently_)+import Data.Char (isSpace)+import Data.List (dropWhileEnd)+import Network.TLS (Credentials(..),SessionManager)+import qualified Network.TLS as TLS import Network.TLS.SessionManager+import qualified Network.TLS.SessionManager as SM+import Network.Wai.Handler.WarpTLS+#ifdef HTTP_OVER_QUIC+import Control.Concurrent.Async (mapConcurrently_)+import Data.Bits+import Data.ByteString (ByteString)+import Data.List (find)+import Data.Maybe (fromJust)+import qualified Network.QUIC.Internal as Q+import Network.Wai.Handler.WarpQUIC+#ifdef DROP_EXCEPT_BIND+import Control.Monad (forM_)+import Foreign.C.Types (CInt(..))+import System.Directory (listDirectory)+import System.Posix.Signals (sigUSR1)+#endif+#endif #else-data TLSSettings = TLSSettings+data Credentials+data SessionManager #endif  ----------------------------------------------------------------@@ -41,13 +60,13 @@ defaultDomain :: Domain defaultDomain = "localhost" -defaultPort :: Int+defaultPort :: Natural defaultPort = 80  openFileNumber :: Integer openFileNumber = 10000 -logBufferSize :: Int+logBufferSize :: Natural logBufferSize = 4 * 1024 * 10  managerNumber :: Int@@ -65,8 +84,18 @@     svc <- openService opt     unless debug writePidFile     rdr <- newRouteDBRef route-    tlsSetting <- getTlsSetting opt-    setGroupUser (opt_user opt) (opt_group opt)+    tmgr <- T.initialize (naturalToInt (opt_connection_timeout opt) * 1000000)+#ifdef HTTP_OVER_TLS+    mcred <- Just <$> loadCredentials opt+    smgr <- Just <$> SM.newSessionManager SM.defaultConfig { dbMaxSize = 1000 }+#else+    let mcred = Nothing+        smgr = Nothing+#endif+    _changed <- setGroupUser (opt_user opt) (opt_group opt)+#ifdef DROP_EXCEPT_BIND+    when _changed dropExceptBind+#endif     logCheck logtype     (zdater,_) <- clockDateCacher     ap <- initLogger FromSocket logtype zdater@@ -77,9 +106,8 @@     setHandlers opt rpt svc remover rdr      report rpt "Mighty started"-    runInUnboundThread $ mighty opt rpt svc lgr pushlgr mgr rdr tlsSetting+    runInUnboundThread $ mighty opt rpt svc lgr pushlgr mgr rdr mcred smgr tmgr     report rpt "Mighty retired"-    finReporter rpt     remover     exitSuccess   where@@ -95,12 +123,12 @@     logspec = FileLogSpec {         log_file          = opt_log_file opt       , log_file_size     = fromIntegral $ opt_log_file_size opt-      , log_backup_number = opt_log_backup_number opt+      , log_backup_number = naturalToInt $ opt_log_backup_number opt       }     logtype       | not (opt_logging opt) = LogNone-      | debug                 = LogStdout logBufferSize-      | otherwise             = LogFile logspec logBufferSize+      | debug                 = LogStdout $ naturalToInt logBufferSize+      | otherwise             = LogFile logspec $ naturalToInt logBufferSize  setHandlers :: Option -> Reporter -> Service -> LogRemover -> RouteDBRef -> IO () setHandlers opt rpt svc remover rdr = do@@ -112,41 +140,34 @@   where     stopHandler = Catch $ do         report rpt "Mighty finished"-        finReporter rpt         closeService svc         remover         exitImmediately ExitSuccess     retireHandler = Catch $ do         report rpt "Mighty retiring"         closeService svc -- this lets warp break-    infoHandler = Catch $ report rpt "obsolted"+    infoHandler = Catch $ report rpt "obsoleted"     reloadHandler = Catch $ do         ifRouteFileIsValid rpt opt $ \newroute -> do             writeRouteDBRef rdr newroute             report rpt "Mighty reloaded" -getTlsSetting :: Option -> IO TLSSettings-getTlsSetting _opt = #ifdef HTTP_OVER_TLS-    case opt_service _opt of-        0 -> return defaultTlsSettings -- this is dummy-        _ -> do cert <- BS.readFile $ opt_tls_cert_file _opt-                let strip = dropWhileEnd isSpace . dropWhile isSpace-                    split "" = []-                    split s = case break (',' ==) s of-                      ("",r)  -> split (tail r)-                      (s',"") -> [s']-                      (s',r)  -> s' : split (tail r)-                    chain_files = map strip $ split $ opt_tls_chain_files _opt-                chains <- mapM BS.readFile chain_files-                key  <- BS.readFile $ opt_tls_key_file _opt-                let settings0 = tlsSettingsChainMemory cert chains key-                    settings = settings0 {-                        tlsSessionManagerConfig = Just defaultConfig { dbMaxSize = 1000 }-                      }-                return settings-#else-    return TLSSettings+loadCredentials :: Option -> IO Credentials+loadCredentials opt = do+    cert   <- BS.readFile $ opt_tls_cert_file opt+    chains <- mapM BS.readFile chain_files+    key    <- BS.readFile $ opt_tls_key_file opt+    let Right cred = TLS.credentialLoadX509ChainFromMemory cert chains key+    return $ Credentials [cred]+  where+    strip = dropWhileEnd isSpace . dropWhile isSpace+    split "" = []+    split s = case break (',' ==) s of+      ("",r)  -> split (tail r)+      (s',"") -> [s']+      (s',r)  -> s' : split (tail r)+    chain_files = map strip $ split $ opt_tls_chain_files opt #endif  ----------------------------------------------------------------@@ -163,35 +184,56 @@ mighty :: Option -> Reporter -> Service        -> ApacheLogger -> ServerPushLogger        -> ConnPool -> RouteDBRef-       -> TLSSettings+       -> Maybe Credentials -> Maybe SessionManager -> T.Manager        -> IO ()-mighty opt rpt svc lgr pushlgr mgr rdr _tlsSetting+mighty opt rpt svc lgr pushlgr mgr rdr _mcreds _msmgr tmgr   = reportDo rpt $ case svc of     HttpOnly s  -> runSettingsSocket setting s app #ifdef HTTP_OVER_TLS-    HttpsOnly s -> runTLSSocket _tlsSetting setting s app-    HttpAndHttps s1 s2 -> void $ concurrently+    HttpsOnly s -> runTLSSocket tlsSetting setting s app+    HttpAndHttps s1 s2 -> concurrently_         (runSettingsSocket setting s1 app)-        (runTLSSocket _tlsSetting setting s2 app)+        (runTLSSocket tlsSetting setting s2 app)+#ifdef HTTP_OVER_QUIC+    QUIC s1 s2 -> do+        let quicPort' = BS.pack $ show quicPort+            strver Q.Version1 = ""+            strver v = BS.append "-" $ BS.pack $ show $ fromVersion v+            quicDrafts = map strver quicVersions+            value v = BS.concat ["h3",v,"=\":",quicPort',"\""]+            altsvc = BS.intercalate "," $ map value quicDrafts+            settingT = setAltSvc altsvc setting+        mapConcurrently_ id [runSettingsSocket        setting  s1 app+                            ,runTLSSocket  tlsSetting settingT s2 app+                            ,runQUIC       qconf      setting     app+                            ] #else     _ -> error "never reach" #endif+#else+    _ -> error "never reach"+#endif   where-    app = P.pushOnReferer P.defaultSettings-                          (fileCgiApp cspec filespec cgispec revproxyspec rdr)+    app = P.pushOnReferer P.defaultSettings $ fileCgiApp cspec filespec cgispec revproxyspec rdr     debug = opt_debug_mode opt     -- We don't use setInstallShutdownHandler because we may use     -- two sockets for HTTP and HTTPS.-    setting = setPort            (opt_port opt) -- just in case+    setting = setPort            (naturalToInt $ opt_port opt) -- just in case             $ setHost            (fromString (opt_host opt))  -- just in case             $ setOnException     (if debug then printStdout else warpHandler rpt)-            $ setTimeout         (opt_connection_timeout opt) -- seconds-            $ setFdCacheDuration (opt_fd_cache_duration opt)+            $ setManager         tmgr+            $ setFdCacheDuration (naturalToInt $ opt_fd_cache_duration opt)             $ setFileInfoCacheDuration 10             $ setServerName      serverName             $ setLogger          lgr             $ setServerPushLogger pushlgr             defaultSettings+#ifdef HTTP_OVER_TLS+    tlsSetting = defaultTlsSettings {+        tlsCredentials    = _mcreds+      , tlsSessionManager = _msmgr+      }+#endif     serverName = BS.pack $ opt_server_name opt     cspec = ClassicAppSpec {         softwareName = serverName@@ -207,10 +249,41 @@     revproxyspec = RevProxyAppSpec {         revProxyManager = mgr       }+#ifdef HTTP_OVER_QUIC+    quicAddr = read <$> opt_quic_addr opt+    quicPort = fromIntegral $ opt_quic_port opt+    quicVersions = Q.scVersions Q.defaultServerConfig+    qconf = Q.defaultServerConfig {+            Q.scAddresses      = (,quicPort) <$> quicAddr+          , Q.scALPN           = Just chooseALPN+          , Q.scRequireRetry   = False+          , Q.scSessionManager = fromJust _msmgr+          , Q.scUse0RTT        = True+          , Q.scDebugLog       = opt_quic_debug_dir opt+          , Q.scQLog           = opt_quic_qlog_dir opt+          , Q.scCredentials    = fromJust _mcreds+          } +chooseALPN :: Q.Version -> [ByteString] -> IO ByteString+chooseALPN ver protos = case find (\x -> x == h3 || x == hq) protos of+  Nothing    -> return ""+  Just proto -> return proto+  where+    h3 | ver == Q.Version1 = "h3"+       | otherwise = "h3-" `BS.append` BS.pack (show (fromVersion ver))+    hq | ver == Q.Version1 = "hq-interop"+       | otherwise = "hq-" `BS.append` BS.pack (show (fromVersion ver))++fromVersion :: Q.Version -> Int+fromVersion (Q.Version ver) = fromIntegral (0x000000ff .&. ver)+#endif+ ---------------------------------------------------------------- -data Service = HttpOnly Socket | HttpsOnly Socket | HttpAndHttps Socket Socket+data Service = HttpOnly Socket+             | HttpsOnly Socket+             | HttpAndHttps Socket Socket+             | QUIC Socket Socket  ---------------------------------------------------------------- @@ -226,13 +299,20 @@       debugMessage $ urlForHTTP httpPort       debugMessage $ urlForHTTPS httpsPort       return $ HttpAndHttps s1 s2+  | service == 3 = do+      s1 <- bindPortTCP httpPort hostpref+      s2 <- bindPortTCP httpsPort hostpref+      debugMessage $ urlForHTTP httpPort+      debugMessage $ urlForHTTPS httpsPort+      debugMessage "QUIC is also available via Alt-Svc"+      return $ QUIC s1 s2   | otherwise = do       s <- bindPortTCP httpPort hostpref       debugMessage $ urlForHTTP httpPort       return $ HttpOnly s   where-    httpPort  = opt_port opt-    httpsPort = opt_tls_port opt+    httpPort  = naturalToInt $ opt_port opt+    httpsPort = naturalToInt $ opt_tls_port opt     hostpref  = fromString $ opt_host opt     service = opt_service opt     debug = opt_debug_mode opt@@ -251,6 +331,7 @@ closeService (HttpOnly s)         = close s closeService (HttpsOnly s)        = close s closeService (HttpAndHttps s1 s2) = close s1 >> close s2+closeService (QUIC s1 s2)         = close s1 >> close s2  ---------------------------------------------------------------- @@ -264,4 +345,16 @@   where     responseTimeout       | opt_proxy_timeout opt == 0 = H.managerResponseTimeout H.defaultManagerSettings-      | otherwise                  = H.responseTimeoutMicro (opt_proxy_timeout opt * 1000000) -- micro seconds+      | otherwise                  = H.responseTimeoutMicro (naturalToInt $ opt_proxy_timeout opt * 1000000) -- micro seconds++#ifdef DROP_EXCEPT_BIND+foreign import ccall unsafe "send_signal"+  c_send_signal :: CInt -> CInt -> IO ()++dropExceptBind :: IO ()+dropExceptBind = do+    pid <- getProcessID+    strtids <- listDirectory ("/proc/" ++ show pid ++ "/task")+    let tids = map read strtids :: [Int]+    forM_ tids $ \tid -> c_send_signal (fromIntegral tid) sigUSR1+#endif
src/WaiApp.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE OverloadedStrings, CPP #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module WaiApp (fileCgiApp) where @@ -36,7 +37,7 @@         Found (RouteCGI   src dst) ->             cgiApp cspec cgispec (CgiRoute src dst) req' respond         Found (RouteRevProxy src dst dom prt) ->-            revProxyApp cspec revproxyspec (RevProxyRoute src dst dom prt) req respond+            revProxyApp cspec revproxyspec (RevProxyRoute src dst dom (naturalToInt prt)) req respond   where     (host, _) = hostPort req     rawpath = rawPathInfo req
test/ConfigSpec.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+ module ConfigSpec where  import Program.Mighty@@ -7,8 +10,44 @@ spec = do     describe "parseConfig" $ do         it "parses example.conf correctly" $ do-            res <- parseOption "conf/example.conf" "foo"-            res `shouldBe` ans+            res <- parseOption "conf/example.conf"+            res { opt_server_name = "foo" } `shouldBe` ans +#ifdef DHALL+    describe "parseDhall" $ do+        it "parses example.dhall correctly" $ do+            res <- parseOptionDhall "./conf/example.dhall"+            res { opt_server_name = "foo" } `shouldBe` ans+#endif+ ans :: Option-ans = Option {opt_port = 80, opt_host = "*", opt_debug_mode = True, opt_user = "root", opt_group = "root", opt_pid_file = "/var/run/mighty.pid", opt_logging = True, opt_log_file = "/var/log/mighty", opt_log_file_size = 16777216, opt_log_backup_number = 10, opt_index_file = "index.html", opt_index_cgi = "index.cgi", opt_status_file_dir = "/usr/local/share/mighty/status", opt_connection_timeout = 30, opt_fd_cache_duration = 10, opt_server_name = "foo", opt_routing_file = Nothing, opt_tls_port = 443, opt_tls_cert_file = "cert.pem", opt_tls_chain_files = "chain.pem", opt_tls_key_file = "privkey.pem", opt_service = 0, opt_report_file = "/tmp/mighty_report", opt_proxy_timeout = 0}+ans = Option+    { opt_port = 80+    , opt_host = "*"+    , opt_debug_mode = True+    , opt_user  = "root"+    , opt_group = "root"+    , opt_pid_file    = "/var/run/mighty.pid"+    , opt_report_file = "/tmp/mighty_report"+    , opt_logging = True+    , opt_log_file = "/var/log/mighty"+    , opt_log_file_size = 16777216+    , opt_log_backup_number = 10+    , opt_index_file = "index.html"+    , opt_index_cgi  = "index.cgi"+    , opt_status_file_dir = "/usr/local/share/mighty/status"+    , opt_connection_timeout = 30+    , opt_proxy_timeout      = 0+    , opt_fd_cache_duration  = 10+    , opt_service = 0+    , opt_tls_port = 443+    , opt_tls_cert_file   = "cert.pem"+    , opt_tls_chain_files = "chain.pem"+    , opt_tls_key_file    = "privkey.pem"+    , opt_quic_addr = ["127.0.0.1","::1"]+    , opt_quic_port = 443+    , opt_quic_debug_dir = Nothing+    , opt_quic_qlog_dir  = Nothing+    , opt_server_name = "foo"+    , opt_routing_file = Nothing+    }