jaror,
jaror avatar

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.

jaror,
jaror avatar

Actually, if you combine network with network-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"
jaror,
jaror avatar

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"
  • All
  • Subscribed
  • Moderated
  • Favorites
  • haskell
  • rosin
  • Backrooms
  • thenastyranch
  • magazineikmin
  • InstantRegret
  • mdbf
  • Youngstown
  • slotface
  • hgfsjryuu7
  • ngwrru68w68
  • everett
  • kavyap
  • khanakhh
  • DreamBathrooms
  • provamag3
  • osvaldo12
  • Durango
  • ethstaker
  • cubers
  • tacticalgear
  • Leos
  • tester
  • GTA5RPClips
  • modclub
  • cisconetworking
  • anitta
  • normalnudes
  • JUstTest
  • All magazines