-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxy.hs
137 lines (98 loc) · 3.74 KB
/
proxy.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
--------------------------------------------------------------------------------
--
-- Copyright (c) 2013 Tad Doxsee
-- All rights reserved.
--
-- Author: Tad Doxsee
--
--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
--------------------------------------------------------------------------------
-- * bytestring
import Data.ByteString (ByteString)
-- * conduit
import Data.Conduit (ResourceT)
-- * cookie
import Web.Cookie (def, parseCookiesText)
-- * http-conduit
import Network.HTTP.Conduit (Manager, newManager)
-- * http-reverse-proxy
import Network.HTTP.ReverseProxy ( ProxyDest(..)
, defaultOnExc, waiProxyTo
)
-- * http-types
import Network.HTTP.Types.Header (RequestHeaders, hCookie)
-- * text
import Data.Text (Text)
-- * transformers
import Control.Monad.IO.Class (liftIO)
-- * wai
import Network.Wai ( Application, Middleware, Request, Response, pathInfo
, requestHeaders
)
-- * wai-extra
import Network.Wai.Middleware.Rewrite (rewritePure)
-- * warp
import Network.Wai.Handler.Warp (run)
-- *
import CurrentDoc
--------------------------------------------------------------------------------
-- The proxy takes requests and sends them to either the system or to
-- the doc aap
main :: IO ()
main = do
keyBS <- readKeyFromDB
run proxyPort $ modApp keyBS $ proxy keyBS
proxy :: ByteString -> Application
proxy keyBS req = do
manager :: Manager <- liftIO $ newManager def
waiProxyTo (mkWaiProxyResponse keyBS)
defaultOnExc
manager
req
modApp :: ByteString -> Middleware
modApp keyBS = rewritePure $ convertPath keyBS
-- For paths leading to the system, leave the path unchanged.
-- All other paths lead to the doc app. Strip app/orgName/docName
-- from the path and proxy to the doc app. The doc app does not
-- need the orgName and docName from the path. Instead it will
-- read the current docID from the cookie.
convertPath :: ByteString -> [Text] -> RequestHeaders -> [Text]
convertPath keyBS path0 headers =
if isPathToSystem path0
then path0
else
-- Ensure that the link and the current document cookie match.
-- The link has the form app/orgName/docName...
-- orgName and docName should match those in the cookie,
-- which was set in getGoToDocAppR (system.hs)
case eOrgAndDocNames of
Left _ -> [""]
Right (orgName, docName) ->
if length path0 > 3 && path0 !! 0 == "app"
&& path0 !! 1 == orgName
&& path0 !! 2 == docName
then drop 3 path0
else [""]
where
eOrgAndDocNames = getOrgAndDocNamesFromHeaders keyBS headers
isPathToSystem :: [Text] -> Bool
isPathToSystem p = null p || head p == "system" || head p == "auth"
mkWaiProxyResponse :: ByteString -> Request
-> ResourceT IO (Either Response ProxyDest)
mkWaiProxyResponse keyBS req = do
let
path = pathInfo req
headers = requestHeaders req
-- code copied from parseWaiRequest'
reqCookie = lookup hCookie headers
cookies = maybe [] parseCookiesText reqCookie
eCurrDocInfo = getCurrDocInfoFromCookies keyBS cookies
CurrentDocumentInfo _ _ _ docuHost docuPort = case eCurrDocInfo of
Left errMsg -> error $ "mkWaiProxyResponse:" ++ errMsg
Right cdi -> cdi
(host, port) = if isPathToSystem path
then (systemHost, systemPort)
else (docuHost, docuPort)
return $ Right $ ProxyDest host port