I enjoyed the simplicity of this recent Computerphile video on web servers: https://www.youtube.com/watch?v=7GBlCinu9yg
I attempted to recreate it in #haskell, but we don’t really have a library on the same level of abstraction. wai is too abstract and network is not abstract enough.
You must log in or register to comment.
Actually, if you combine
network
withnetwork-run
then it is the right level of abstraction:{- cabal: build-depends: base, network, network-run, monad-loops -} import Network.Run.TCP import Network.Socket import System.IO import Control.Monad.Loops main = runTCPServer (Just "127.0.0.1") "9999" talk where talk s = do h <- socketToHandle s ReadWriteMode l <- hGetLine h case words l of ["GET", resource, "HTTP/1.1"] -> do whileM_ (("\r" /=) <$> hGetLine h) (pure ()) let path = concat [ "htdocs/" , dropWhile (== '/') resource , if last resource == '/' then "index.html" else "" ] hPutStr h "HTTP/1.1 200 OK\r\n\r\n" hPutStr h =<< readFile path hClose h _ -> error "todo"
We can make it a lot more performant, shorter, and also safer by using lazy byte strings:
{- cabal: build-depends: base, network, network-run, bytestring -} {-# LANGUAGE OverloadedStrings #-} import Network.Run.TCP (runTCPServer) import qualified Network.Socket.ByteString.Lazy as Net import qualified Data.ByteString.Lazy.Char8 as Str main = runTCPServer (Just "127.0.0.1") "9999" $ \s -> do request <- Net.getContents s case Str.words (Str.takeWhile (/= '\r') request) of ["GET", resource, "HTTP/1.1"] -> do let path = Str.concat [ "htdocs/" , Str.dropWhile (== '/') resource , if Str.last resource == '/' then "index.html" else "" ] page <- Str.readFile (Str.unpack path) Net.sendAll s ("HTTP/1.1 200 OK\r\n\r\n" <> page) _ -> error "todo"