-
Notifications
You must be signed in to change notification settings - Fork 1
/
HHydra.hs
86 lines (59 loc) · 1.95 KB
/
HHydra.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
module Main where
import Control.Monad
import Data.List
import Network
import System.IO
import System.Random
import Text.ParserCombinators.Parsec
import Text.Regex.Posix
import Config
import Server
import Tpl
ruleEval :: String -> Bool
ruleEval r =
eval (r =~ "#\\{(.+)\\} +(.+) +(.+)" :: [[String]])
where
eval ([[_, str, re, "=~"]]) = str =~ re :: Bool
eval ([[_, str, re, "=="]]) = str == re :: Bool
eval other = error $ "misshapen config rule: " ++ show other
rulesEval :: [String] -> Bool
rulesEval = any ruleEval
randomItem :: [String] -> IO String
randomItem xs = (xs !!) `fmap` randomRIO (0, length xs - 1)
respond :: Request -> Handle -> String -> IO ()
respond request handle redirect_host = do
print request
let response = Response
{ version = "HTTP/1.1"
, statuscode = 302
, location = redirect_host
}
hPutStr handle $ show response
handleAccept :: Handle -> String -> [(String, [String], [String])] -> IO ()
handleAccept handle _hostname rules = do
rawPacket <- hGetContents handle
let request = parseRequest . lines $ rawPacket
let params = options request ++ [("Path", path request)]
let clean_rules = for rules snd3
let tpl = template params
let t_rules = for clean_rules $ map tpl
let (Just ((_, _, arr), _)) = find snd $ zip rules $ map rulesEval t_rules
redirect_host <- randomItem arr
respond request handle redirect_host
return ()
main :: IO ()
main = withSocketsDo $ do
sock <- listenOn $ PortNumber 9000
contents <- readFile "config"
case parse config "config" contents of
Left err -> print err
Right rules -> do
putStrLn "Listening on port 9000"
forever $ do
(handle, hostname, _port) <- accept sock
handleAccept handle hostname rules
hClose handle
for :: [a] -> (a -> b) -> [b]
for = flip map
snd3 :: (a, b, c) -> b
snd3 (_, r, _) = r