1 -- |The entry point of Lucu httpd.
2 module Network.HTTP.Lucu.Httpd
8 import Control.Concurrent
9 import Control.Exception
13 import Network.HTTP.Lucu.Config
14 import Network.HTTP.Lucu.Interaction
15 import Network.HTTP.Lucu.RequestReader
16 import Network.HTTP.Lucu.Resource.Tree
17 import Network.HTTP.Lucu.ResponseWriter
18 import Network.HTTP.Lucu.SocketLike as SL
19 import System.Posix.Signals
21 -- |This is the entry point of Lucu httpd. It listens to a socket and
22 -- waits for clients. Computation of 'runHttpd' never stops by itself
23 -- so the only way to stop it is to raise an exception in the thread
26 -- Note that 'runHttpd' automatically makes SIGPIPE be ignored by
27 -- computing @'System.Posix.Signals.installHandler'
28 -- 'System.Posix.Signals.sigPIPE' 'System.Posix.Signals.Ignore'
29 -- 'Prelude.Nothing'@. This can hardly cause a problem but it may do.
33 -- > module Main where
34 -- > import Network.HTTP.Lucu
37 -- > main = let config = defaultConfig
38 -- > resources = mkResTree [ ([], helloWorld) ]
40 -- > runHttpd config resourcees []
42 -- > helloWorld :: ResourceDef
43 -- > helloWorld = ResourceDef {
44 -- > resUsesNativeThread = False
45 -- > , resIsGreedy = False
47 -- > = Just $ do setContentType $ read "text/plain"
48 -- > output "Hello, world!"
49 -- > , resHead = Nothing
50 -- > , resPost = Nothing
51 -- > , resPut = Nothing
52 -- > , resDelete = Nothing
54 runHttpd :: Config -> ResTree -> [FallbackHandler] -> IO ()
57 do _ <- installHandler sigPIPE Ignore Nothing
59 -- FIXME: TERRIBLE CODE. NEED MAJOR REWRITE.
60 case cnfSSLConfig cnf of
64 -> do case cnfServerV4Addr cnf of
68 -> do so <- listenOn AF_INET v4addr (sslServerPort scnf)
70 -- FIXME: Don't throw away the thread
71 -- ID as we can't kill it later
73 _ <- forkIO $ httpLoop p (sslContext scnf, so)
76 case cnfServerV6Addr cnf of
80 -> do so <- listenOn AF_INET6 v6addr (sslServerPort scnf)
83 _ <- forkIO $ httpLoop p (sslContext scnf, so)
86 case cnfServerV4Addr cnf of
90 -> do so <- listenOn AF_INET v4addr (cnfServerPort cnf)
93 _ <- forkIO $ httpLoop p so
96 case cnfServerV6Addr cnf of
100 -> do so <- listenOn AF_INET6 v6addr (cnfServerPort cnf)
103 _ <- forkIO $ httpLoop p so
108 listenOn :: Family -> HostName -> ServiceName -> IO Socket
109 listenOn fam host srv
110 = do proto <- getProtocolNumber "tcp"
111 let hints = defaultHints {
112 addrFlags = [AI_PASSIVE]
114 , addrSocketType = Stream
115 , addrProtocol = proto
117 addrs <- getAddrInfo (Just hints) (Just host) (Just srv)
118 let addr = head addrs
120 (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))
123 do setSocketOption sock ReuseAddr 1
124 bindSocket sock (addrAddress addr)
125 listen sock maxListenQueue
129 httpLoop :: SocketLike s => PortNumber -> s -> IO ()
131 = do (h, addr) <- SL.accept so
132 tQueue <- newInteractionQueue
133 readerTID <- forkIO $ requestReader cnf tree fbs h port addr tQueue
134 _writerTID <- forkIO $ responseWriter cnf h tQueue readerTID
138 waitForever = forever (threadDelay 1000000)