module General.CGI(cgiArgs, escape, escapeUpper, escapeLower, asCgi, escapeHTML, escapeAttrib) where
import General.TextUtil
import System.Environment
import Control.Monad
import Data.Maybe
import Data.Char
import Numeric
import Data.List
cgiVariable :: IO (Maybe String)
cgiVariable = do
str <- envVariable "QUERY_STRING"
if isJust str
then return str
else liftM (liftM $ const "") $ envVariable "REQUEST_URI"
envVariable :: String -> IO (Maybe String)
envVariable x = catch (liftM Just $ getEnv x) (const $ return Nothing)
cgiArgs :: IO (Maybe [(String, String)])
cgiArgs = do x <- cgiVariable
return $ case x of
Nothing -> Nothing
Just y -> Just $ parseArgs $ ['=' | '=' `notElem` y] ++ y
asCgi :: [(String, String)] -> String
asCgi x = concat $ intersperse "&" $ map f x
where
f (a,b) = a ++ "=" ++ escape b
parseArgs :: String -> [(String, String)]
parseArgs xs = mapMaybe (parseArg . splitPair "=") $ splitList "&" xs
parseArg Nothing = Nothing
parseArg (Just (a,b)) = Just (unescape a, unescape b)
unescape :: String -> String
unescape ('+':xs) = ' ' : unescape xs
unescape ('%':a:b:xs) = unescapeChar a b : unescape xs
unescape (x:xs) = x : unescape xs
unescape [] = []
unescapeChar :: Char -> Char -> Char
unescapeChar a b = chr $ (f a * 16) + f b
where
f x | isDigit x = ord x ord '0'
| otherwise = ord (toLower x) ord 'a' + 10
escapeWith :: (Char -> Char) -> String -> String
escapeWith f (x:xs) | isAlphaNum x = x : escapeWith f xs
| otherwise = '%' : escapeCharWith f x ++ escapeWith f xs
escapeWith f [] = []
escapeCharWith :: (Char -> Char) -> Char -> String
escapeCharWith f x = case map f $ showHex (ord x) "" of
[x] -> ['0',x]
x -> x
escapeUpper = escapeWith toUpper
escapeLower = escapeWith toLower
escape = escapeLower
escapeHTML :: String -> String
escapeHTML = concatMap f
where
f '<' = "<"
f '>' = ">"
f '&' = "&"
f x = [x]
escapeAttrib :: String -> String
escapeAttrib = concatMap f . escapeHTML
where
f '\"' = """
f x = [x]