|
1 | 1 | {-# LANGUAGE ScopedTypeVariables, OverloadedStrings, ViewPatterns, RecordWildCards, DeriveFunctor #-} |
| 2 | +{-# LANGUAGE MultiWayIf #-} |
2 | 3 |
|
3 | 4 | module General.Web( |
4 | 5 | Input(..), |
5 | 6 | Output(..), readInput, server, general_web_test |
6 | 7 | ) where |
7 | 8 |
|
| 9 | +import Data.Streaming.Network (bindPath, bindPortTCP) |
8 | 10 | import Network.Wai.Handler.Warp hiding (Port, Handle) |
9 | 11 | import Network.Wai.Handler.WarpTLS |
10 | 12 |
|
11 | 13 | import Action.CmdLine |
12 | 14 | import Network.Wai.Logger |
13 | 15 | import Network.Wai |
14 | 16 | import Control.DeepSeq |
| 17 | +import Network.Socket (Socket, close) |
15 | 18 | import Network.HTTP.Types (parseQuery, decodePathSegments) |
16 | 19 | import Network.HTTP.Types.Status |
17 | 20 | import qualified Data.Text as Text |
@@ -81,25 +84,37 @@ forceBS (OutputFile x) = rnf x `seq` LBS.empty |
81 | 84 | instance NFData Output where |
82 | 85 | rnf x = forceBS x `seq` () |
83 | 86 |
|
| 87 | +runServer |
| 88 | + :: ServerOpts |
| 89 | + -> Application |
| 90 | + -> IO () |
| 91 | +runServer opts app = |
| 92 | + withEndpointSocket (local opts) (endpoint opts) $ \sock -> |
| 93 | + if https opts |
| 94 | + then runTLSSocket (tlsSettings (cert opts) (key opts)) settings sock app |
| 95 | + else runSettingsSocket settings sock app |
| 96 | + where |
| 97 | + settings = setOnExceptionResponse exceptionResponseForDebug defaultSettings |
| 98 | + |
| 99 | +withEndpointSocket |
| 100 | + :: Bool -- ^ local |
| 101 | + -> ServerEndpoint |
| 102 | + -> (Socket -> IO a) |
| 103 | + -> IO a |
| 104 | +withEndpointSocket _ (UnixSocket sock) = |
| 105 | + bracket (bindPath sock) close |
| 106 | +withEndpointSocket local (TcpSocket host port) = |
| 107 | + bracket (bindPortTCP port host') close |
| 108 | + where |
| 109 | + host' = fromString $ |
| 110 | + if | "" <- host |
| 111 | + , local -> "127.0.0.1" |
| 112 | + | "" <- host -> "*" |
| 113 | + | otherwise -> host |
| 114 | + |
84 | 115 | server :: Log -> ServerOpts -> (Input -> IO Output) -> IO () |
85 | | -server log ServerOpts{..} act = do |
86 | | - let |
87 | | - host' = fromString $ |
88 | | - if host == "" then |
89 | | - if local then |
90 | | - "127.0.0.1" |
91 | | - else |
92 | | - "*" |
93 | | - else |
94 | | - host |
95 | | - set = setOnExceptionResponse exceptionResponseForDebug |
96 | | - . setHost host' |
97 | | - . setPort port $ |
98 | | - defaultSettings |
99 | | - runServer :: Application -> IO () |
100 | | - runServer = if https then runTLS (tlsSettings cert key) set |
101 | | - else runSettings set |
102 | | - secH = if no_security_headers then [] |
| 116 | +server log opts@ServerOpts{..} act = do |
| 117 | + let secH = if no_security_headers then [] |
103 | 118 | else [ |
104 | 119 | -- The CSP is giving additional instructions to the browser. |
105 | 120 | ("Content-Security-Policy", |
@@ -163,9 +178,9 @@ server log ServerOpts{..} act = do |
163 | 178 | -- call happens. |
164 | 179 | ("Strict-Transport-Security", "max-age=31536000; includeSubDomains")] |
165 | 180 |
|
166 | | - logAddMessage log $ "Server starting on port " ++ show port ++ " and host/IP " ++ show host' |
| 181 | + logAddMessage log $ "Server starting on " <> showEndpoint endpoint |
167 | 182 |
|
168 | | - runServer $ \req reply -> do |
| 183 | + runServer opts $ \req reply -> do |
169 | 184 | let pq = BS.unpack $ rawPathInfo req <> rawQueryString req |
170 | 185 | putStrLn pq |
171 | 186 | (time, res) <- duration $ case readInput pq of |
|
0 commit comments