packages feed

hoogle-4.2.1: src/Web/Server.hs

{-# LANGUAGE RecordWildCards #-}

module Web.Server(server) where

import General.Base
import General.Web
import CmdLine.All
import Web.Response
import Control.Monad.IO.Class
import General.System
import Control.Concurrent

import Network.Wai
import Network.Wai.Handler.Warp
import qualified Data.ByteString.Lazy.Char8 as LBS
import qualified Data.ByteString.Char8 as BS


server :: CmdLine -> IO ()
server q@Server{..} = do
    v <- newMVar ()
    putStrLn $ "Starting Hoogle Server on port " ++ show port
    run port $ \r -> liftIO $ do
        withMVar v $ const $ putStrLn $ bsUnpack (pathInfo r) ++ bsUnpack (queryString r)
        talk q r


-- FIXME: Avoid all the conversions to/from LBS
talk :: CmdLine -> Request -> IO Response
talk Server{..} Request{pathInfo=path_, queryString=query_}
    | path `elem` ["/","/hoogle"] = do
        let args = parseHttpQueryArgs $ drop 1 query
        cmd <- cmdLineWeb args
        r <- response "/res" cmd{databases=databases}
        if local_ then rewriteFileLinks r else return r
    | takeDirectory path == "/res" = serveFile True $ resources </> takeFileName path
    | local_ && "/file/" `isPrefixOf` path = serveFile False $ drop 6 path
    | otherwise = return $ responseNotFound $ show path
    where (path,query) = (bsUnpack path_, bsUnpack query_)


serveFile :: Bool -> FilePath -> IO Response
serveFile cache file = do
    b <- doesFileExist file
    return $ if not b
        then responseNotFound file
        else ResponseFile statusOK hdr file
    where hdr = [(hdrContentType, fromString $ contentExt $ takeExtension file)] ++
                [(hdrCacheControl, fromString "max-age=604800" {- 1 week -}) | cache]


rewriteFileLinks :: Response -> IO Response
rewriteFileLinks r = do
    (a,b,c) <- responseFlatten r
    let res = LBS.fromChunks $ f $ BS.concat $ LBS.toChunks c
    return $ responseLBS a b res
    where
        f x | BS.null b = [a]
            | otherwise = a : rep : f (BS.drop nfind b) 
            where (a,b) = BS.breakSubstring find x

        find = fromString "href='file://"
        rep = fromString "href='/file/"
        nfind = BS.length find


contentExt ".png" = "image/png"
contentExt ".css" = "text/css"
contentExt ".js" = "text/javascript"
contentExt ".html" = "text/html"
contentExt ".htm" = "text/html"
contentExt _ = "text/plain"