From e0e6079c9141a0c2d7d2a6dda50496e237bfc8bb Mon Sep 17 00:00:00 2001 From: hallgren Date: Tue, 2 Sep 2014 12:27:47 +0000 Subject: src/server: refactoring to isolate dependencies on the cgi/fastcgi packages * Introducing the module CGI, re-exporting a subset of the cgi package. It might complete replace the cgi package in the future. * Introducing the module CGIUtils, containing functions from FastCGIUtils that have nothing to do with fastcgi. Some low level hackery with unsafePerformIO and global variables was left in FastCGIUtils, but it is actually not used, neither for gf -server nor exec/pgf-fcgi.hs. --- src/server/CGIUtils.hs | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/server/CGIUtils.hs (limited to 'src/server/CGIUtils.hs') diff --git a/src/server/CGIUtils.hs b/src/server/CGIUtils.hs new file mode 100644 index 000000000..ba41dc180 --- /dev/null +++ b/src/server/CGIUtils.hs @@ -0,0 +1,103 @@ +{-# LANGUAGE DeriveDataTypeable, CPP #-} +-- | CGI utility functions for output, error handling and logging +module CGIUtils (throwCGIError, handleCGIErrors, + stderrToFile,logError, + outputJSONP,outputEncodedJSONP, + outputPNG,outputBinary,outputBinary', + outputHTML,outputPlain) where + +import Control.Exception(Exception(..),SomeException(..),throw) +import Data.Dynamic(Typeable,cast) +import Prelude hiding (catch) +import System.IO(hPutStrLn,stderr) +#ifndef mingw32_HOST_OS +import System.Posix +#endif + +import CGI(CGI,CGIResult,setHeader,output,outputFPS,outputError, + getInput,catchCGI,throwCGI) + +import Text.JSON +import qualified Codec.Binary.UTF8.String as UTF8 (encodeString) +import qualified Data.ByteString.Lazy as BS + +-- * Logging + +#ifndef mingw32_HOST_OS +logError :: String -> IO () +logError s = hPutStrLn stderr s + +stderrToFile :: FilePath -> IO () +stderrToFile file = + do let mode = ownerReadMode<>ownerWriteMode<>groupReadMode<>otherReadMode + (<>) = unionFileModes + flags = defaultFileFlags { append = True } + fileFd <- openFd file WriteOnly (Just mode) flags + dupTo fileFd stdError + return () +#else +logError :: String -> IO () +logError s = return () + +stderrToFile :: FilePath -> IO () +stderrToFile s = return () +#endif + +-- * General CGI Error exception mechanism + +data CGIError = CGIError { cgiErrorCode :: Int, cgiErrorMessage :: String, cgiErrorText :: [String] } + deriving (Show,Typeable) + +instance Exception CGIError where + toException e = SomeException e + fromException (SomeException e) = cast e + +throwCGIError :: Int -> String -> [String] -> CGI a +throwCGIError c m t = throwCGI $ toException $ CGIError c m t + +handleCGIErrors :: CGI CGIResult -> CGI CGIResult +handleCGIErrors x = + x `catchCGI` \e -> case fromException e of + Nothing -> throw e + Just (CGIError c m t) -> do setXO; outputError c m t + +-- * General CGI and JSON stuff + +outputJSONP :: JSON a => a -> CGI CGIResult +outputJSONP = outputEncodedJSONP . encode + +outputEncodedJSONP :: String -> CGI CGIResult +outputEncodedJSONP json = + do mc <- getInput "jsonp" + let (ty,str) = case mc of + Nothing -> ("json",json) + Just c -> ("javascript",c ++ "(" ++ json ++ ")") + ct = "application/"++ty++"; charset=utf-8" + outputStrict ct $ UTF8.encodeString str + +outputPNG :: BS.ByteString -> CGI CGIResult +outputPNG = outputBinary' "image/png" + +outputBinary :: BS.ByteString -> CGI CGIResult +outputBinary = outputBinary' "application/binary" + +outputBinary' :: String -> BS.ByteString -> CGI CGIResult +outputBinary' ct x = do + setHeader "Content-Type" ct + setXO + outputFPS x + +outputHTML :: String -> CGI CGIResult +outputHTML = outputStrict "text/html; charset=utf-8" . UTF8.encodeString + +outputPlain :: String -> CGI CGIResult +outputPlain = outputStrict "text/plain; charset=utf-8" . UTF8.encodeString + +outputStrict :: String -> String -> CGI CGIResult +outputStrict ct x | x == x = do setHeader "Content-Type" ct + setXO + output x + | otherwise = fail "I am the pope." + +setXO = setHeader "Access-Control-Allow-Origin" "*" + -- https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS -- cgit v1.2.3