Commit 16bece62 authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

Slight refactoring of proxy code

parent 4ab1ebbb
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
module Gargantext.MicroServices.ReverseProxy ( module Gargantext.MicroServices.ReverseProxy (
microServicesProxyApp microServicesProxyApp
-- * Internals
, replaceIt
) where ) where
import Prelude import Prelude
...@@ -41,6 +38,21 @@ import Text.RE.Replace hiding (Capture) ...@@ -41,6 +38,21 @@ import Text.RE.Replace hiding (Capture)
-- Types -- Types
-- --
data ProxyDestination =
ProxyDestination
{ fwdProto :: C8.ByteString
, fwdHost :: C8.ByteString
, fwdPort :: PortNumber
}
renderProxyDestination :: ProxyDestination -> C8.ByteString
renderProxyDestination ProxyDestination{..}
= fwdProto <> "//" <> fwdHost <> ":" <> C8.pack (Prelude.show fwdPort)
--
-- The API
--
data ReverseProxyAPI mode = ReverseProxyAPI data ReverseProxyAPI mode = ReverseProxyAPI
{ notesProxy :: mode :- "notes-proxy" :> NamedRoutes NotesProxy { notesProxy :: mode :- "notes-proxy" :> NamedRoutes NotesProxy
, notesSocketIo :: mode :- "socket.io" :> NamedRoutes SocketIOProxy , notesSocketIo :: mode :- "socket.io" :> NamedRoutes SocketIOProxy
...@@ -48,8 +60,8 @@ data ReverseProxyAPI mode = ReverseProxyAPI ...@@ -48,8 +60,8 @@ data ReverseProxyAPI mode = ReverseProxyAPI
} deriving Generic } deriving Generic
data NotesProxy mode = NotesProxy data NotesProxy mode = NotesProxy
{ noteProxyEp :: mode :- Capture "frameId" T.Text { noteProxyEp :: mode :- Capture "frameId" T.Text :> Raw
:> Raw , slideEp :: mode :- Capture "frameId" T.Text :> "slide" :> Raw
} deriving Generic } deriving Generic
data SocketIOProxy mode = SocketIOProxy data SocketIOProxy mode = SocketIOProxy
...@@ -57,7 +69,7 @@ data SocketIOProxy mode = SocketIOProxy ...@@ -57,7 +69,7 @@ data SocketIOProxy mode = SocketIOProxy
} deriving Generic } deriving Generic
-- --
-- Server -- The Server
-- --
microServicesProxyApp :: Env -> Application microServicesProxyApp :: Env -> Application
...@@ -67,91 +79,108 @@ server :: Env -> ReverseProxyAPI AsServer ...@@ -67,91 +79,108 @@ server :: Env -> ReverseProxyAPI AsServer
server env = ReverseProxyAPI { server env = ReverseProxyAPI {
notesProxy = notesProxyImplementation env notesProxy = notesProxyImplementation env
, notesSocketIo = socketIOProxyImplementation env , notesSocketIo = socketIOProxyImplementation env
, meEndpoint = forwardServer env , meEndpoint = proxyPassServer env
} }
notesProxyImplementation :: Env -> NotesProxy AsServer notesProxyImplementation :: Env -> NotesProxy AsServer
notesProxyImplementation env = NotesProxy { notesProxyImplementation env = NotesProxy {
noteProxyEp = \_frameId -> forwardServer env noteProxyEp = \_frameId -> notesProxyServer env
, slideEp = \frameId -> slideProxyServer env frameId
} }
socketIOProxyImplementation :: Env -> SocketIOProxy AsServer socketIOProxyImplementation :: Env -> SocketIOProxy AsServer
socketIOProxyImplementation env = SocketIOProxy { socketIOProxyImplementation env = SocketIOProxy {
socketIoEp = \_noteId -> forwardServer env socketIoEp = \_noteId -> proxyPassServer env
} }
forwardServer :: Env -> ServerT Raw m notesProxyServer :: Env -> ServerT Raw m
forwardServer env = notesProxyServer env = defaultForwardServer (removeProxyPath "/notes-proxy") env
Tagged $ waiProxyToSettings forwardRequest proxySettings (env ^. env_manager)
slideProxyServer :: Env -> T.Text -> ServerT Raw m
slideProxyServer env frameId =
defaultForwardServer (\rq -> rq { rawPathInfo = changePath (rawPathInfo rq) }) env
where where
changePath :: ByteString -> ByteString
changePath _ = TE.encodeUtf8 $ "/p/" <> frameId <> "#/"
microSrvSettings :: MicroServicesSettings -- Generic server forwarder
microSrvSettings = env ^. env_settings . microservicesSettings proxyPassServer :: Env -> ServerT Raw m
proxyPassServer env = defaultForwardServer id env
pxyPort :: Int
pxyPort = microSrvSettings ^. msProxyPort
writeFrameURL :: T.Text mkProxyDestination :: Env -> ProxyDestination
writeFrameURL = env ^. hasConfig . gc_frame_write_url mkProxyDestination env = fromMaybe (panicTrace "Invalid URI found in the proxied Request.") $ do
URI{..} <- URI.parseURI (T.unpack $ env ^. hasConfig . gc_frame_write_url)
uriAut <- uriAuthority
port <- case uriPort uriAut of
"" -> pure 80
xs -> readMaybe (dropWhile (==':') xs)
pure $ ProxyDestination (C8.pack uriScheme) (C8.pack $ uriRegName uriAut) port
assetPath :: B.ByteString --
assetPath -- Combinators over the input Request
| snd forwardedHost /= 80 --
= TE.encodeUtf8 $ writeFrameURL <> ":" <> T.pack (Prelude.show $ snd forwardedHost)
| otherwise
= TE.encodeUtf8 writeFrameURL
removeProxyPath :: ByteString -> ByteString removeProxyPath :: T.Text -> Request -> Request
removeProxyPath = TE.encodeUtf8 removeProxyPath pth originalRequest =
. T.replace "/notes-proxy" "" originalRequest { rawPathInfo = removePath (rawPathInfo originalRequest) }
. TE.decodeUtf8 where
removePath :: ByteString -> ByteString
removePath = TE.encodeUtf8 . T.replace pth "" . TE.decodeUtf8
proxySettings :: WaiProxySettings
proxySettings = defaultWaiProxySettings { wpsProcessBody = \_req _res -> Just replaceRelativeLinks
, wpsModifyResponseHeaders = \_req _res -> tweakResponseHeaders
}
replaceRelativeLinks :: ConduitT B.ByteString (Flush Builder) IO () defaultForwardServer :: (Request -> Request) -> Env -> ServerT Raw m
replaceRelativeLinks = CC.map (flushReplace assetPath) defaultForwardServer presendModifyRequest env =
where Tagged $ waiProxyToSettings forwardRequest (proxySettings $ mkProxyDestination env) (env ^. env_manager)
where
noCache :: RequestHeaders -> RequestHeaders proxyDestination :: ProxyDestination
noCache hdrs = (hCacheControl, fromString "no-cache") : proxyDestination = mkProxyDestination env
filter ((/=) hCacheControl . fst) hdrs
newHost :: RequestHeaders -> RequestHeaders microSrvSettings :: MicroServicesSettings
newHost hdrs = microSrvSettings = env ^. env_settings . microservicesSettings
(hHost, fromString $ fst forwardedHost <> ":" <> Prelude.show (snd forwardedHost)) :
filter ((/=) hHost . fst) hdrs proxyListeningPort :: Int
proxyListeningPort = microSrvSettings ^. msProxyPort
proxySettings :: ProxyDestination -> WaiProxySettings
proxySettings h@ProxyDestination{..} =
defaultWaiProxySettings { wpsProcessBody = \_req _res -> Just $ replaceRelativeLinks assetPath
, wpsModifyResponseHeaders = \_req _res -> tweakResponseHeaders
}
where
assetPath :: B.ByteString
assetPath
| fwdPort /= 80
= renderProxyDestination h
| otherwise
= fwdProto <> "//" <> fwdHost
newHost :: ProxyDestination -> RequestHeaders -> RequestHeaders
newHost hst hdrs = (hHost, renderProxyDestination hst) : filter ((/=) hHost . fst) hdrs
newReferer :: RequestHeaders -> RequestHeaders newReferer :: RequestHeaders -> RequestHeaders
newReferer hdrs = newReferer hdrs =
(hReferer, fromString $ "http://localhost:" <> Prelude.show pxyPort) : (hReferer, fromString $ "http://localhost:" <> Prelude.show proxyListeningPort) :
filter ((/=) hHost . fst) hdrs filter ((/=) hHost . fst) hdrs
forwardedHost :: (String, Int)
forwardedHost = fromMaybe (panicTrace "Invalid URI found in the proxied Request.") $ do
URI{..} <- URI.parseURI (T.unpack writeFrameURL)
uriAut <- uriAuthority
port <- case uriPort uriAut of
"" -> pure 80
xs -> readMaybe (dropWhile (==':') xs)
pure $ (uriRegName uriAut, port)
mkProxyDest :: ProxyDest
mkProxyDest =
let (hst, prt) = forwardedHost
in ProxyDest (C8.pack hst) prt
-- | Forwards the request by substituting back the proxied address into the actual one. -- | Forwards the request by substituting back the proxied address into the actual one.
forwardRequest :: Request -> IO WaiProxyResponse forwardRequest :: Request -> IO WaiProxyResponse
forwardRequest originalRequest = do forwardRequest originalRequest = do
let proxiedReq = originalRequest { let proxiedReq = presendModifyRequest $ originalRequest {
rawPathInfo = removeProxyPath (rawPathInfo originalRequest) requestHeaders = (newReferer . newHost proxyDestination . noCache $ (requestHeaders originalRequest))
, requestHeaders = (newReferer . newHost . noCache $ (requestHeaders originalRequest))
} }
pure $ WPRModifiedRequest proxiedReq mkProxyDest pure $ WPRModifiedRequest proxiedReq ProxyDest (fwdHost proxyDestination) (fwdPort proxyDestination))
--
-- Utility functions
--
noCache :: RequestHeaders -> RequestHeaders
noCache hdrs = (hCacheControl, fromString "no-cache") : filter ((/=) hCacheControl . fst) hdrs
-- | Tweak the response headers so that they will have a bit more permissive
-- 'Content-Security-Policy'.
tweakResponseHeaders :: ResponseHeaders -> ResponseHeaders tweakResponseHeaders :: ResponseHeaders -> ResponseHeaders
tweakResponseHeaders = Prelude.map tweakHeader tweakResponseHeaders = Prelude.map tweakHeader
where where
...@@ -161,17 +190,21 @@ tweakResponseHeaders = Prelude.map tweakHeader ...@@ -161,17 +190,21 @@ tweakResponseHeaders = Prelude.map tweakHeader
| otherwise | otherwise
= (k,v) = (k,v)
-- | Replaces the relative links in the proxied page content with proper urls. -- | Replaces the relative links in any HTML blob returned by the proxy.
flushReplace :: B.ByteString -> B.ByteString -> Flush Builder replaceRelativeLinks :: B.ByteString -> ConduitT B.ByteString (Flush Builder) IO ()
flushReplace assetPath = Chunk . byteString . replaceIt assetPath replaceRelativeLinks assetPath = CC.map flushReplace
replaceIt :: B.ByteString -> B.ByteString -> B.ByteString
replaceIt assetPath htmlBlob =
replaceAllCaptures ALL makeAbsolute $ htmlBlob *=~ [re|src="\/build\/|href="\/build\/|src="\/config|src="\/js\/|]
where where
makeAbsolute _ _loc cap = case capturedText cap of -- Replaces the relative links in the proxied page content with proper urls.
"src=\"/build/" -> Just $ "src=\"" <> assetPath <> "/build/" flushReplace :: B.ByteString -> Flush Builder
"href=\"/build/" -> Just $ "href=\"" <> assetPath <> "/build/" flushReplace = Chunk . byteString . replaceIt
"src=\"/config" -> Just $ "src=\"" <> assetPath <> "/config"
"src=\"/js/" -> Just $ "src=\"" <> assetPath <> "/js/" replaceIt :: B.ByteString -> B.ByteString
_ -> Just $ assetPath <> capturedText cap replaceIt htmlBlob =
replaceAllCaptures ALL makeAbsolute $ htmlBlob *=~ [re|src="\/build\/|href="\/build\/|src="\/config|src="\/js\/|]
where
makeAbsolute _ _loc cap = case capturedText cap of
"src=\"/build/" -> Just $ "src=\"" <> assetPath <> "/build/"
"href=\"/build/" -> Just $ "href=\"" <> assetPath <> "/build/"
"src=\"/config" -> Just $ "src=\"" <> assetPath <> "/config"
"src=\"/js/" -> Just $ "src=\"" <> assetPath <> "/js/"
_ -> Just $ assetPath <> capturedText cap
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment