From 985974c264804ff788b3b5242fef707d4b7fa9a6 Mon Sep 17 00:00:00 2001 From: evuez Date: Mon, 1 Apr 2024 15:17:30 +0200 Subject: Initial commit --- src/Http.hs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/Http.hs (limited to 'src/Http.hs') diff --git a/src/Http.hs b/src/Http.hs new file mode 100644 index 0000000..f486920 --- /dev/null +++ b/src/Http.hs @@ -0,0 +1,75 @@ +module Http (runServer) where + +import qualified Cache as C +import Common (maybeAt, splitOn) +import qualified Html as H +import Intro +import qualified Mail as M +import Network.Socket (HostName, ServiceName, Socket, socketToHandle) +import qualified Queue as Q +import System.IO (Handle, IOMode (ReadWriteMode), hClose, hGetLine, hPutStrLn) +import qualified Tcp +import qualified Template as T +import Text.Read (readMaybe) + +runServer :: Maybe HostName -> ServiceName -> C.CacheM -> Q.QueueM M.Mail -> IO () +runServer host port cache queue = Tcp.runServer host port (sockHandler cache queue) + +sockHandler :: C.CacheM -> Q.QueueM M.Mail -> Socket -> IO () +sockHandler cache queue s = do + handle <- socketToHandle s ReadWriteMode + requestHandler handle cache queue + +requestHandler :: Handle -> C.CacheM -> Q.QueueM M.Mail -> IO () +requestHandler h cache queue = do + line <- hGetLine h + case route line of + ("GET", []) -> showInbox h cache + ("GET", ["poll", s]) -> showPolled h queue s + ("GET", ["mail", n]) -> case (readMaybe n :: Maybe Int) of + Just n' -> showMail h cache n' + Nothing -> showNotFound h + _ -> showNotFound h + hClose h + +showNotFound :: Handle -> IO () +showNotFound h = do + replyHtml h 404 [H.p ["Page not found"]] + +showInbox :: Handle -> C.CacheM -> IO () +showInbox h cache = do + inbox <- C.getInbox cache + replyHtml h 200 (T.inbox inbox) + +showMail :: Handle -> C.CacheM -> Int -> IO () +showMail h cache idx = do + mail <- maybeAt idx <$> C.getInbox cache + case mail of + Just mail' -> replyHtml h 200 (T.mail mail') + Nothing -> showNotFound h + +showPolled :: Handle -> Q.QueueM M.Mail -> String -> IO () +showPolled h queue s = do + mail <- Q.pullWith (\m -> m.to == [s]) queue + replyHtml h 200 (T.mail mail) + +route :: String -> (String, [String]) +route x = case words x of + [m, p, "HTTP/1.1"] -> (m, splitOn (== '/') p) + _ -> ("GET", []) + +replyHtml :: Handle -> Int -> [String] -> IO () +replyHtml h s body = do + let page = H.html body + hPutStrLn h $ "HTTP/1.1 " ++ status s + hPutStrLn h "content-type: text/html" + hPutStrLn h $ "content-length: " ++ show (length page) + hPutStrLn h "" + hPutStrLn h page + hPutStrLn h "" + +status :: Int -> String +status s = case s of + 200 -> "200 OK" + 404 -> "404 NOT FOUND" + _ -> "500 INTERNAL SERVER ERROR" -- cgit v1.2.3