Skip to content

Commit ce01347

Browse files
bgamariBodigrim
authored andcommitted
Allow serving over UNIX domain socket
1 parent 4b12aab commit ce01347

File tree

4 files changed

+62
-25
lines changed

4 files changed

+62
-25
lines changed

hoogle.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ library
7474
js-flot,
7575
js-jquery,
7676
mmap,
77+
network,
7778
process-extras,
7879
resourcet,
7980
safe >= 0.3.20,
@@ -85,6 +86,7 @@ library
8586
time >= 1.5,
8687
tls,
8788
transformers,
89+
streaming-commons,
8890
uniplate,
8991
utf8-string >= 0.3.1,
9092
vector,

src/Action/CmdLine.hs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ module Action.CmdLine(
1111
ServerOpts(..),
1212
ReplayOpts(..),
1313
TestOpts(..),
14+
-- * Endpoints
15+
ServerEndpoint(..),
16+
showEndpoint,
1417
-- * Parsing command line
1518
getCmdLine, defaultDatabaseLang,
1619
-- * Verbosity
@@ -67,7 +70,7 @@ data GenerateOpts
6770

6871
data ServerOpts
6972
= ServerOpts
70-
{ port :: Int
73+
{ endpoint :: ServerEndpoint
7174
, database :: FilePath
7275
, cdn :: String
7376
, logs :: FilePath
@@ -76,7 +79,6 @@ data ServerOpts
7679
, links :: Bool
7780
, scope :: String
7881
, home :: String
79-
, host :: String
8082
, https :: Bool
8183
, cert :: FilePath
8284
, key :: FilePath
@@ -106,6 +108,14 @@ data Mode
106108
| Replay ReplayOpts
107109
| Test TestOpts
108110

111+
data ServerEndpoint
112+
= UnixSocket FilePath
113+
| TcpSocket String Int
114+
115+
showEndpoint :: ServerEndpoint -> String
116+
showEndpoint (TcpSocket host port) = "port " <> show port <> " on host " <> host
117+
showEndpoint (UnixSocket sock) = "socket " <> sock
118+
109119
defaultDatabaseLang :: IO FilePath
110120
defaultDatabaseLang = do
111121
xdgLocation <- getXdgDirectory XdgData "hoogle"
@@ -212,9 +222,20 @@ generateOpts = do
212222
debug <- switch (long "debug" <> help "Generate debug information")
213223
return $ GenerateOpts {..}
214224

225+
unixEndpoint :: Parser ServerEndpoint
226+
unixEndpoint =
227+
UnixSocket <$> option str (long "socket" <> metavar "PATH" <> help "UNIX socket")
228+
229+
tcpEndpoint :: Parser ServerEndpoint
230+
tcpEndpoint =
231+
TcpSocket <$> host <*> port
232+
where
233+
host = option str (long "host" <> value "*" <> help "Set the host to bind on (e.g., an ip address; '!4' for ipv4-only; '!6' for ipv6-only; default: '*' for any host).")
234+
port = option auto (long "port" <> short 'p' <> value 8080 <> metavar "PORT" <> help "Port number")
235+
215236
serverOpts :: Parser ServerOpts
216237
serverOpts = do
217-
port <- option auto (long "port" <> short 'p' <> value 8080 <> metavar "PORT" <> help "Port number")
238+
endpoint <- unixEndpoint <|> tcpEndpoint
218239
database <- databaseFlag
219240
cdn <- option str (value "" <> metavar "URL" <> help "URL prefix to use")
220241
logs <- logsFlag
@@ -223,7 +244,6 @@ serverOpts = do
223244
scope <- scopeFlag
224245
links <- switch (long "links" <> help "Display extra links")
225246
home <- option str (long "home" <> value "https://hoogle.haskell.org" <> metavar "URL" <> help "Set the URL linked to by the Hoogle logo.")
226-
host <- option str (long "host" <> value "" <> help "Set the host to bind on (e.g., an ip address; '!4' for ipv4-only; '!6' for ipv6-only; default: '*' for any host).")
227247
https <- switch (long "https" <> help "Start an https server (use --cert and --key to specify paths to the .pem files)")
228248
cert <- option str (value "cert.pem" <> metavar "FILE" <> help "Path to the certificate pem file (when running an https server)")
229249
key <- option str (long "key" <> short 'k' <> value "key.pem" <> metavar "FILE" <> help "Path to the key pem file (when running an https server)")

src/Action/Server.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ actionServer verbosity cmd@ServerOpts{..} = do
5454
-- so I can get good error messages
5555
hSetBuffering stdout LineBuffering
5656
hSetBuffering stderr LineBuffering
57-
putStrLn $ "Server started on port " ++ show port
57+
putStrLn $ "Server started on " ++ showEndpoint endpoint
5858
putStr "Reading log..." >> hFlush stdout
5959
time <- offsetTime
6060
log <- logCreate (if logs == "" then Left stdout else Right logs) $

src/General/Web.hs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
{-# LANGUAGE ScopedTypeVariables, OverloadedStrings, ViewPatterns, RecordWildCards, DeriveFunctor #-}
2+
{-# LANGUAGE MultiWayIf #-}
23

34
module General.Web(
45
Input(..),
56
Output(..), readInput, server, general_web_test
67
) where
78

9+
import Data.Streaming.Network (bindPath, bindPortTCP)
810
import Network.Wai.Handler.Warp hiding (Port, Handle)
911
import Network.Wai.Handler.WarpTLS
1012

1113
import Action.CmdLine
1214
import Network.Wai.Logger
1315
import Network.Wai
1416
import Control.DeepSeq
17+
import Network.Socket (Socket, close)
1518
import Network.HTTP.Types (parseQuery, decodePathSegments)
1619
import Network.HTTP.Types.Status
1720
import qualified Data.Text as Text
@@ -81,25 +84,37 @@ forceBS (OutputFile x) = rnf x `seq` LBS.empty
8184
instance NFData Output where
8285
rnf x = forceBS x `seq` ()
8386

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+
84115
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 []
103118
else [
104119
-- The CSP is giving additional instructions to the browser.
105120
("Content-Security-Policy",
@@ -163,9 +178,9 @@ server log ServerOpts{..} act = do
163178
-- call happens.
164179
("Strict-Transport-Security", "max-age=31536000; includeSubDomains")]
165180

166-
logAddMessage log $ "Server starting on port " ++ show port ++ " and host/IP " ++ show host'
181+
logAddMessage log $ "Server starting on " <> showEndpoint endpoint
167182

168-
runServer $ \req reply -> do
183+
runServer opts $ \req reply -> do
169184
let pq = BS.unpack $ rawPathInfo req <> rawQueryString req
170185
putStrLn pq
171186
(time, res) <- duration $ case readInput pq of

0 commit comments

Comments
 (0)