5 -- |The entry point of Lucu httpd.
6 module Network.HTTP.Lucu.Httpd
11 import Control.Concurrent
12 import Control.Exception
14 import Control.Monad.Unicode
18 import Network.HTTP.Lucu.Config
19 import Network.HTTP.Lucu.Interaction
20 import Network.HTTP.Lucu.RequestReader
21 import Network.HTTP.Lucu.Resource.Tree
22 import Network.HTTP.Lucu.ResponseWriter
23 import Network.HTTP.Lucu.SocketLike as SL
25 -- |This is the entry point of Lucu httpd. It listens to a socket and
26 -- waits for clients. 'runHttpd' never stops by itself so the only way
27 -- to stop it is to raise an exception in the thread running it.
31 -- > {-# LANGUAGE OverloadedStrings #-}
32 -- > {-# LANGUAGE QuasiQuotes #-}
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 = emptyResource {
45 -- > = Just $ do setContentType [mimeType| text/plain |]
46 -- > putChunk "Hello, world!"
48 runHttpd ∷ Config → ResTree → [FallbackHandler] → IO ()
53 [ do addr ← cnfServerV4Addr cnf
54 return ( launchListener =≪ listenOn AF_INET addr (cnfServerPort cnf)
56 , do addr ← cnfServerV6Addr cnf
57 return ( launchListener =≪ listenOn AF_INET6 addr (cnfServerPort cnf)
60 , do scnf ← cnfSSLConfig cnf
61 addr ← cnfServerV4Addr cnf
62 return ( do so ← listenOn AF_INET addr (sslServerPort scnf)
63 launchListener (sslContext scnf, so)
65 , do scnf ← cnfSSLConfig cnf
66 addr ← cnfServerV6Addr cnf
67 return ( do so ← listenOn AF_INET6 addr (sslServerPort scnf)
68 launchListener (sslContext scnf, so)
75 launchListener ∷ SocketLike s ⇒ s → IO ()
77 = do p ← SL.socketPort so
78 -- FIXME: Don't throw away the thread ID as we can't
79 -- kill it later then. [1]
80 void $ forkIO $ httpLoop p so
82 listenOn ∷ Family → HostName → ServiceName → IO Socket
84 = do proto ← getProtocolNumber "tcp"
85 let hints = defaultHints {
86 addrFlags = [AI_PASSIVE]
88 , addrSocketType = Stream
89 , addrProtocol = proto
91 addrs ← getAddrInfo (Just hints) (Just host) (Just srv)
94 (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))
97 do setSocketOption sock ReuseAddr 1
98 bindSocket sock (addrAddress addr)
99 listen sock maxListenQueue
103 httpLoop ∷ SocketLike s ⇒ PortNumber → s → IO ()
105 = do (h, addr) ← SL.accept so
106 tQueue ← mkInteractionQueue
107 readerTID ← forkIO $ requestReader cnf tree fbs h port addr tQueue
108 _writerTID ← forkIO $ responseWriter cnf h tQueue readerTID
112 waitForever = forever (threadDelay 1000000)