module General.Web(
filePathToURL, combineURL, escapeURL, (++%), unescapeURL,
escapeHTML, (++&), htmlTag,
cgiArgs,
parseHttpQueryArgs
) where
import General.System
import General.Base
import Network.HTTP
instance Functor Response where
fmap f x = x{rspBody = f $ rspBody x}
escapeHTML :: String -> String
escapeHTML = concatMap f
where
f '<' = "<"
f '>' = ">"
f '&' = "&"
f x = [x]
(++&) :: String -> String -> String
a ++& b = a ++ escapeHTML b
htmlTag :: String -> String -> String
htmlTag x y = "<" ++ x ++ ">" ++ y ++ "</" ++ x ++ ">"
filePathToURL :: FilePath -> URL
filePathToURL xs = "file://" ++ ['/' | not $ "/" `isPrefixOf` ys] ++ ys
where ys = map (\x -> if isPathSeparator x then '/' else x) xs
combineURL :: String -> String -> String
combineURL a b
| any (`isPrefixOf` b) ["http:","https:","file:"] = b
| otherwise = a ++ b
unescapeURL :: String -> String
unescapeURL ('+':xs) = ' ' : unescapeURL xs
unescapeURL ('%':a:b:xs) | [(v,"")] <- readHex [a,b] = chr v : unescapeURL xs
unescapeURL (x:xs) = x : unescapeURL xs
unescapeURL [] = []
escapeURL :: String -> String
escapeURL = concatMap f
where
f x | isAlphaNum x || x `elem` "-" = [x]
| x == ' ' = "+"
| otherwise = '%' : ['0'|length s == 1] ++ s
where s = showHex (ord x) ""
(++%) :: String -> String -> String
a ++% b = a ++ escapeURL b
cgiVariable :: IO (Maybe String)
cgiVariable = do
str <- envVariable "QUERY_STRING"
if isJust str
then return str
else fmap (fmap $ const "") $ envVariable "REQUEST_URI"
envVariable :: String -> IO (Maybe String)
envVariable x = catch (fmap Just $ getEnv x) (const $ return Nothing)
cgiArgs :: IO (Maybe [(String, String)])
cgiArgs = do
x <- cgiVariable
return $ case x of
Nothing -> Nothing
Just y -> Just $ parseHttpQueryArgs $ ['=' | '=' `notElem` y] ++ y
parseHttpQueryArgs :: String -> [(String, String)]
parseHttpQueryArgs xs = mapMaybe (f . splitPair "=") $ splitList "&" xs
where f Nothing = Nothing
f (Just (a,b)) = Just (unescapeURL a, unescapeURL b)
splitList :: Eq a => [a] -> [a] -> [[a]]
splitList find str = if isJust q then a : splitList find b else [str]
where
q = splitPair find str
Just (a, b) = q
splitPair :: Eq a => [a] -> [a] -> Maybe ([a], [a])
splitPair find str = f str
where
f [] = Nothing
f x | isPrefixOf find x = Just ([], drop (length find) x)
| otherwise = if isJust q then Just (head x:a, b) else Nothing
where
q = f (tail x)
Just (a, b) = q