content: -- | A benchmark for measuring the impact of lazy bytestring chunk size on
  -- server performance.
  --
  {-# LANGUAGE OverloadedStrings #-}
  module Main where
  
  import Control.Concurrent (forkIO)
  import Control.Monad (forever)
  import Data.Monoid (mappend)
  import Network (listenOn, PortID (PortNumber))
  import Network.Socket (accept, sClose)
  import Prelude hiding (putStrLn)
  import System.Environment (getArgs)
  
  import Network.Socket.ByteString (recv, send)
  import Network.Socket.ByteString.Lazy (sendAll)
  import qualified Data.ByteString.Char8 as SBC
  import qualified Data.ByteString.Lazy as LB
  
  -- | Generate a 128k response, with a given chunk size.
  --
  makeResponse :: Int            -- ^ Chunk size.
               -> LB.ByteString  -- ^ Result.
  makeResponse chunkSize =
      let chunks = createChunks chunkSize totalSize
      in LB.fromChunks chunks
    where
      -- A 64 kilobyte response.
      totalSize = 128 * 1024
  
      createChunks c s
        | c < s     = SBC.replicate c 'a' : createChunks c (s - c)
        | otherwise = SBC.replicate s 'a' : []
  
  main :: IO ()
  main = do
      args <- getArgs
      let port = PortNumber $ fromIntegral $ (read $ head args :: Int)
          chunkSize = read $ args !! 1
  
      socket <- listenOn port
      forever $ do
          (s, _) <- accept socket
          forkIO (respond chunkSize s)
    where
      respond chunkSize s = do
          _ <- recv s 1024
          _ <- send s $ "HTTP/1.1 200 OK\r\n"
              `mappend` "Content-Type: text/html; charset=UTF-8\r\n"
              `mappend` "\r\n"
          sendAll s $ makeResponse chunkSize
          sClose s
  