{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}

module Network.Wai.Middleware.Rewrite (
    -- * How to use this module
    -- $howto

    -- ** A note on semantics
    -- $semantics

    -- ** Paths and Queries
    -- $pathsandqueries
    PathsAndQueries,

    -- ** An example rewriting paths with queries
    -- $takeover

    -- ** Upgrading from wai-extra ≤ 3.0.16.1
    -- $upgrading

    -- * 'Middleware'

    -- ** Recommended functions
    rewriteWithQueries,
    rewritePureWithQueries,
    rewriteRoot,

    -- ** Deprecated
    rewrite,
    rewritePure,

    -- * Operating on 'Request's
    rewriteRequest,
    rewriteRequestPure,
) where

-- GHC ≤ 7.10 does not export Applicative functions from the prelude.
#if __GLASGOW_HASKELL__ <= 710
import Control.Applicative
#endif
import Control.Monad.IO.Class (liftIO)
import Data.Functor.Identity (Identity (..))
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Network.HTTP.Types as H
import Network.Wai

-- $howto
-- This module provides 'Middleware' to rewrite URL paths. It also provides
-- functions that will convert a 'Request' to a modified 'Request'.
-- Both operations require a function that takes URL parameters and
-- headers, and returns new URL parameters. Parameters are pieces of URL
-- paths and query parameters.
--
-- If you are a new user of the library, use 'rewriteWithQueries' or
-- 'rewritePureWithQueries' for middleware. For modifying 'Request's
-- directly, use 'rewriteRequest' or 'rewriteRequestPure'.

-- $semantics
--
-- Versions of this library in wai-extra ≤ 3.0.16.1 exported only
-- 'rewrite' and 'rewritePure' and both modified 'rawPathInfo' of the
-- underlying requests. Such modification has been proscribed. The
-- semantics of these functions have not changed; instead the recommended
-- approach is to use 'rewriteWithQueries' and 'rewritePureWithQueries'.
-- The new functions are slightly different, as described in the section
-- on upgrading; code for previous library versions can be upgraded with
-- a single change, and as the type of the new function is different the
-- compiler will indicate where this change must be made.
--
-- The 'rewriteRequest' and 'rewriteRequestPure' functions use the new
-- semantics, too.

-- $pathsandqueries
--
-- This library defines the type synonym `PathsAndQueries` to make code
-- handling paths and queries easier to read.
--
-- /e.g./ /\/foo\/bar/ would look like
--
-- > ["foo", "bar"] :: Text
--
-- /?bar=baz/ would look like
--
-- > [("bar", Just "baz")] :: QueryText
--
-- Together,
--
-- /\/foo?bar=baz/ would look like
--
-- > (["foo"],[("bar", Just "baz")]) :: PathsAndQueries

-- $takeover
-- Let’s say we want to replace a website written in PHP with one written
-- using WAI. We’ll use the
-- <https://hackage.haskell.org/package/http-reverse-proxy http-reverse-proxy>
-- package to serve the old
-- site from the new site, but there’s a problem. The old site uses pages like
--
-- @
-- index.php?page=/page/
-- @
--
-- whereas the new site would look like
--
-- @
-- index\//page/
-- @
--
-- In doing this, we want to separate the migration code from our new
-- website. So we’d like to handle links internally using the path
-- formulation, but externally have the old links still work.
--
-- Therefore, we will use middleware ('rewritePureWithQueries') from this
-- module to rewrite incoming requests from the query formulation to the
-- paths formulation.
--
-- > {-# LANGUAGE ViewPatterns #-}
-- >
-- > rewritePathFromPhp :: Middleware
-- > rewritePathFromPhp = rewritePureWithQueries pathFromPhp
-- >
-- > pathFromPhp :: PathsAndQueries -> H.RequestHeaders -> PathsAndQueries
-- > pathFromPhp (pieces, queries) _ = piecesConvert pieces queries
-- >     where
-- >         piecesConvert :: [Text] -> H.Query -> PathsAndQueries
-- >         piecesConvert ["index.php"] qs@(join . lookup "page" -> Just page) =
-- >             ( ["index", TE.decodeUtf8With TE.lenientDecode page]
-- >             , delete ("page", pure page) qs
-- >             )
-- >         piecesConvert ps qs = (ps, qs)
--
-- On the other side, we will use 'rewriteRequestPure' to rewrite outgoing
-- requests to the original website from the reverse proxy code (using the
-- 'Network.HTTP.ReverseProxy.WPRModifiedRequest' or
-- 'Network.HTTP.ReverseProxy.WPRModifiedRequestSecure' constructors. Note,
-- these links will only work if the haddock documentation for
-- <https://hackage.haskell.org/package/http-reverse-proxy http-reverse-proxy>
-- is installed).
--
-- > rewritePhpFromPath :: Request -> Request
-- > rewritePhpFromPath = rewriteRequestPure phpFromPath
-- >
-- > phpFromPath :: PathsAndQueries -> H.RequestHeaders -> PathsAndQueries
-- > phpFromPath (pieces, queries) _ = piecesConvert pieces queries
-- >     where
-- >         piecesConvert :: [Text] -> H.Query -> PathsAndQueries
-- >         piecesConvert ["index", page] qs = ( ["index.php"], ("page", pure . TE.encodeUtf8 $ page) : qs )
-- >         piecesConvert ps qs = (ps, qs)
--
-- For the whole example, see
-- <https://gist.github.com/dbaynard/c844d0df124f68ec8b6da152c581ce6d>.

-- $upgrading
-- It is quite simple to upgrade from 'rewrite' and 'rewritePure', to
-- 'rewriteWithQueries' and 'rewritePureWithQueries'.
-- Insert 'Data.Bifunctor.first', which specialises to
--
-- @
-- 'Data.Bifunctor.first' :: (['Text'] -> ['Text']) -> 'PathsAndQueries' -> 'PathsAndQueries'
-- @
--
-- as the following example demonstrates.
--
-- Old versions of the library could only handle path pieces, not queries.
-- This could have been supplied to 'rewritePure'.
--
-- @
-- staticConvert' :: [Text] -> H.RequestHeaders -> [Text]
-- staticConvert' pieces _ = piecesConvert pieces
--   where
--    piecesConvert [] = ["static", "html", "pages.html"]
--    piecesConvert route@("pages":_) = "static":"html":route
-- @
--
-- Instead, use this function, supplied to 'rewritePureWithQueries'.
--
-- @
-- staticConvert :: 'PathsAndQueries' -> H.RequestHeaders -> 'PathsAndQueries'
-- staticConvert pathsAndQueries _ = 'Data.Bifunctor.first' piecesConvert pathsAndQueries
--   where
--    piecesConvert [] = ["static", "html", "pages.html"]
--    piecesConvert route@("pages":_) = "static":"html":route
-- @
--
-- The former formulation is deprecated for two reasons:
--
--   1. The original formulation of 'rewrite' modified 'rawPathInfo', which
--   is deprecated behaviour.
--
--   2. The original formulation did not allow query parameters to
--   influence the path.
--
-- Concerning the first point, take care with semantics of your program when
-- upgrading as the upgraded functions no longer modify 'rawPathInfo'.

--------------------------------------------------

-- * Types

--------------------------------------------------

-- | A tuple of the path sections as ['Text'] and query parameters as
-- 'H.Query'. This makes writing type signatures for the conversion
-- function far more pleasant.
--
-- Note that this uses 'H.Query' not 'H.QueryText' to more accurately
-- reflect the paramaters that can be supplied in URLs. It may be safe to
-- treat parameters as text; use the 'H.queryToQueryText' and
-- 'H.queryTextToQuery' functions to interconvert.
type PathsAndQueries = ([Text], H.Query)

--------------------------------------------------

-- * Rewriting 'Middleware'

--------------------------------------------------

-- | Rewrite based on your own conversion function for paths only, to be
-- supplied by users of this library (with the conversion operating in 'IO').
--
-- For new code, use 'rewriteWithQueries' instead.
rewrite :: ([Text] -> H.RequestHeaders -> IO [Text]) -> Middleware
rewrite :: ([Text] -> RequestHeaders -> IO [Text]) -> Middleware
rewrite [Text] -> RequestHeaders -> IO [Text]
convert Application
app Request
req Response -> IO ResponseReceived
sendResponse = do
    let convertIO :: PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convertIO = ([Text] -> RequestHeaders -> IO [Text])
-> PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
forall (m :: * -> *).
(Applicative m, Monad m) =>
([Text] -> RequestHeaders -> m [Text])
-> PathsAndQueries -> RequestHeaders -> m PathsAndQueries
pathsOnly (([Text] -> RequestHeaders -> IO [Text])
 -> PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> ((([Text], RequestHeaders) -> IO [Text])
    -> [Text] -> RequestHeaders -> IO [Text])
-> (([Text], RequestHeaders) -> IO [Text])
-> PathsAndQueries
-> RequestHeaders
-> IO PathsAndQueries
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([Text], RequestHeaders) -> IO [Text])
-> [Text] -> RequestHeaders -> IO [Text]
forall a b c. ((a, b) -> c) -> a -> b -> c
curry ((([Text], RequestHeaders) -> IO [Text])
 -> PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> (([Text], RequestHeaders) -> IO [Text])
-> PathsAndQueries
-> RequestHeaders
-> IO PathsAndQueries
forall a b. (a -> b) -> a -> b
$ IO [Text] -> IO [Text]
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [Text] -> IO [Text])
-> (([Text], RequestHeaders) -> IO [Text])
-> ([Text], RequestHeaders)
-> IO [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> RequestHeaders -> IO [Text])
-> ([Text], RequestHeaders) -> IO [Text]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry [Text] -> RequestHeaders -> IO [Text]
convert
    Request
newReq <- (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> Request -> IO Request
forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestRawM PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convertIO Request
req
    Application
app Request
newReq Response -> IO ResponseReceived
sendResponse
{-# WARNING
    rewrite
    [ "This modifies the 'rawPathInfo' field of a 'Request'."
    , " This is not recommended behaviour; it is however how"
    , " this function has worked in the past."
    , " Use 'rewriteWithQueries' instead"
    ]
    #-}

-- | Rewrite based on pure conversion function for paths only, to be
-- supplied by users of this library.
--
-- For new code, use 'rewritePureWithQueries' instead.
rewritePure :: ([Text] -> H.RequestHeaders -> [Text]) -> Middleware
rewritePure :: ([Text] -> RequestHeaders -> [Text]) -> Middleware
rewritePure [Text] -> RequestHeaders -> [Text]
convert Application
app Request
req =
    let convertPure :: PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries
convertPure = ([Text] -> RequestHeaders -> Identity [Text])
-> PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries
forall (m :: * -> *).
(Applicative m, Monad m) =>
([Text] -> RequestHeaders -> m [Text])
-> PathsAndQueries -> RequestHeaders -> m PathsAndQueries
pathsOnly (([Text] -> RequestHeaders -> Identity [Text])
 -> PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries)
-> ((([Text], RequestHeaders) -> Identity [Text])
    -> [Text] -> RequestHeaders -> Identity [Text])
-> (([Text], RequestHeaders) -> Identity [Text])
-> PathsAndQueries
-> RequestHeaders
-> Identity PathsAndQueries
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([Text], RequestHeaders) -> Identity [Text])
-> [Text] -> RequestHeaders -> Identity [Text]
forall a b c. ((a, b) -> c) -> a -> b -> c
curry ((([Text], RequestHeaders) -> Identity [Text])
 -> PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries)
-> (([Text], RequestHeaders) -> Identity [Text])
-> PathsAndQueries
-> RequestHeaders
-> Identity PathsAndQueries
forall a b. (a -> b) -> a -> b
$ [Text] -> Identity [Text]
forall a. a -> Identity a
Identity ([Text] -> Identity [Text])
-> (([Text], RequestHeaders) -> [Text])
-> ([Text], RequestHeaders)
-> Identity [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> RequestHeaders -> [Text])
-> ([Text], RequestHeaders) -> [Text]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry [Text] -> RequestHeaders -> [Text]
convert
        newReq :: Request
newReq = Identity Request -> Request
forall a. Identity a -> a
runIdentity (Identity Request -> Request) -> Identity Request -> Request
forall a b. (a -> b) -> a -> b
$ (PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries)
-> Request -> Identity Request
forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestRawM PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries
convertPure Request
req
     in Application
app Request
newReq
{-# WARNING
    rewritePure
    [ "This modifies the 'rawPathInfo' field of a 'Request'."
    , " This is not recommended behaviour; it is however how"
    , " this function has worked in the past."
    , " Use 'rewritePureWithQueries' instead"
    ]
    #-}

-- | Rewrite based on your own conversion function for paths and queries.
-- This function is to be supplied by users of this library, and operates
-- in 'IO'.
rewriteWithQueries
    :: (PathsAndQueries -> H.RequestHeaders -> IO PathsAndQueries)
    -> Middleware
rewriteWithQueries :: (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> Middleware
rewriteWithQueries PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convert Application
app Request
req Response -> IO ResponseReceived
sendResponse = do
    Request
newReq <- (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> Request -> IO Request
forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestM PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convert Request
req
    Application
app Request
newReq Response -> IO ResponseReceived
sendResponse

-- | Rewrite based on pure conversion function for paths and queries. This
-- function is to be supplied by users of this library.
rewritePureWithQueries
    :: (PathsAndQueries -> H.RequestHeaders -> PathsAndQueries)
    -> Middleware
rewritePureWithQueries :: (PathsAndQueries -> RequestHeaders -> PathsAndQueries)
-> Middleware
rewritePureWithQueries PathsAndQueries -> RequestHeaders -> PathsAndQueries
convert Application
app Request
req = Application
app Middleware
forall a b. (a -> b) -> a -> b
$ (PathsAndQueries -> RequestHeaders -> PathsAndQueries)
-> Request -> Request
rewriteRequestPure PathsAndQueries -> RequestHeaders -> PathsAndQueries
convert Request
req

-- | Rewrite root requests (/) to a specified path
--
-- Note that /index.html/ in example below should already be a valid route.
--
-- @
--     rewriteRoot "index.html" :: Middleware
-- @
--
-- @since 3.0.23.0
rewriteRoot :: Text -> Middleware
rewriteRoot :: Text -> Middleware
rewriteRoot Text
root = (PathsAndQueries -> RequestHeaders -> PathsAndQueries)
-> Middleware
rewritePureWithQueries PathsAndQueries -> RequestHeaders -> PathsAndQueries
forall {b} {p}. ([Text], b) -> p -> ([Text], b)
onlyRoot
  where
    onlyRoot :: ([Text], b) -> p -> ([Text], b)
onlyRoot ([], b
q) p
_ = ([Text
root], b
q)
    onlyRoot ([Text], b)
paths p
_ = ([Text], b)
paths

--------------------------------------------------

-- * Modifying 'Request's directly

--------------------------------------------------

-- | Modify a 'Request' using the supplied function in 'IO'. This is suitable for
-- the reverse proxy example.
rewriteRequest
    :: (PathsAndQueries -> H.RequestHeaders -> IO PathsAndQueries)
    -> Request
    -> IO Request
rewriteRequest :: (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> Request -> IO Request
rewriteRequest PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convert Request
req =
    let convertIO :: PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convertIO = ((PathsAndQueries, RequestHeaders) -> IO PathsAndQueries)
-> PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
forall a b c. ((a, b) -> c) -> a -> b -> c
curry (((PathsAndQueries, RequestHeaders) -> IO PathsAndQueries)
 -> PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> ((PathsAndQueries, RequestHeaders) -> IO PathsAndQueries)
-> PathsAndQueries
-> RequestHeaders
-> IO PathsAndQueries
forall a b. (a -> b) -> a -> b
$ IO PathsAndQueries -> IO PathsAndQueries
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO PathsAndQueries -> IO PathsAndQueries)
-> ((PathsAndQueries, RequestHeaders) -> IO PathsAndQueries)
-> (PathsAndQueries, RequestHeaders)
-> IO PathsAndQueries
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> (PathsAndQueries, RequestHeaders) -> IO PathsAndQueries
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convert
     in (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries)
-> Request -> IO Request
forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestRawM PathsAndQueries -> RequestHeaders -> IO PathsAndQueries
convertIO Request
req

-- | Modify a 'Request' using the pure supplied function. This is suitable for
-- the reverse proxy example.
rewriteRequestPure
    :: (PathsAndQueries -> H.RequestHeaders -> PathsAndQueries)
    -> Request
    -> Request
rewriteRequestPure :: (PathsAndQueries -> RequestHeaders -> PathsAndQueries)
-> Request -> Request
rewriteRequestPure PathsAndQueries -> RequestHeaders -> PathsAndQueries
convert Request
req =
    let convertPure :: PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries
convertPure = ((PathsAndQueries, RequestHeaders) -> Identity PathsAndQueries)
-> PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries
forall a b c. ((a, b) -> c) -> a -> b -> c
curry (((PathsAndQueries, RequestHeaders) -> Identity PathsAndQueries)
 -> PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries)
-> ((PathsAndQueries, RequestHeaders) -> Identity PathsAndQueries)
-> PathsAndQueries
-> RequestHeaders
-> Identity PathsAndQueries
forall a b. (a -> b) -> a -> b
$ PathsAndQueries -> Identity PathsAndQueries
forall a. a -> Identity a
Identity (PathsAndQueries -> Identity PathsAndQueries)
-> ((PathsAndQueries, RequestHeaders) -> PathsAndQueries)
-> (PathsAndQueries, RequestHeaders)
-> Identity PathsAndQueries
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PathsAndQueries -> RequestHeaders -> PathsAndQueries)
-> (PathsAndQueries, RequestHeaders) -> PathsAndQueries
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry PathsAndQueries -> RequestHeaders -> PathsAndQueries
convert
     in Identity Request -> Request
forall a. Identity a -> a
runIdentity (Identity Request -> Request) -> Identity Request -> Request
forall a b. (a -> b) -> a -> b
$ (PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries)
-> Request -> Identity Request
forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestRawM PathsAndQueries -> RequestHeaders -> Identity PathsAndQueries
convertPure Request
req

--------------------------------------------------

-- * Helper functions

--------------------------------------------------

-- | This helper function factors out the common behaviour of rewriting requests.
rewriteRequestM
    :: (Applicative m, Monad m)
    => (PathsAndQueries -> H.RequestHeaders -> m PathsAndQueries)
    -> Request
    -> m Request
rewriteRequestM :: forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestM PathsAndQueries -> RequestHeaders -> m PathsAndQueries
convert Request
req = do
    ([Text]
pInfo, Query
qByteStrings) <-
        (PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> [Text] -> Query -> RequestHeaders -> m PathsAndQueries
forall a b c. ((a, b) -> c) -> a -> b -> c
curry PathsAndQueries -> RequestHeaders -> m PathsAndQueries
convert (Request -> [Text]
pathInfo Request
req) (Request -> Query
queryString Request
req) (Request -> RequestHeaders
requestHeaders Request
req)
    Request -> m Request
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Request
req{pathInfo = pInfo, queryString = qByteStrings}

-- | This helper function preserves the semantics of wai-extra ≤ 3.0, in
-- which the rewrite functions modify the 'rawPathInfo' parameter. Note
-- that this has not been extended to modify the 'rawQueryInfo' as
-- modifying either of these values has been deprecated.
rewriteRequestRawM
    :: (Applicative m, Monad m)
    => (PathsAndQueries -> H.RequestHeaders -> m PathsAndQueries)
    -> Request
    -> m Request
rewriteRequestRawM :: forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestRawM PathsAndQueries -> RequestHeaders -> m PathsAndQueries
convert Request
req = do
    Request
newReq <- (PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
forall (m :: * -> *).
(Applicative m, Monad m) =>
(PathsAndQueries -> RequestHeaders -> m PathsAndQueries)
-> Request -> m Request
rewriteRequestM PathsAndQueries -> RequestHeaders -> m PathsAndQueries
convert Request
req
    let rawPInfo :: ByteString
rawPInfo = Text -> ByteString
TE.encodeUtf8 (Text -> ByteString) -> (Request -> Text) -> Request -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text] -> Text
T.intercalate Text
"/" ([Text] -> Text) -> (Request -> [Text]) -> Request -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Request -> [Text]
pathInfo (Request -> ByteString) -> Request -> ByteString
forall a b. (a -> b) -> a -> b
$ Request
newReq
    Request -> m Request
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Request
newReq{rawPathInfo = rawPInfo}
{-# WARNING
    rewriteRequestRawM
    [ "This modifies the 'rawPathInfo' field of a 'Request'."
    , " This is not recommended behaviour; it is however how"
    , " this function has worked in the past."
    , " Use 'rewriteRequestM' instead"
    ]
    #-}

-- | Produce a function that works on 'PathsAndQueries' from one working
-- only on paths. This is not exported, as it is only needed to handle
-- code written for versions ≤ 3.0 of the library; see the
-- example above using 'Data.Bifunctor.first' to do something similar.
pathsOnly
    :: (Applicative m, Monad m)
    => ([Text] -> H.RequestHeaders -> m [Text])
    -> PathsAndQueries
    -> H.RequestHeaders
    -> m PathsAndQueries
pathsOnly :: forall (m :: * -> *).
(Applicative m, Monad m) =>
([Text] -> RequestHeaders -> m [Text])
-> PathsAndQueries -> RequestHeaders -> m PathsAndQueries
pathsOnly [Text] -> RequestHeaders -> m [Text]
convert PathsAndQueries
psAndQs RequestHeaders
headers = (,[]) ([Text] -> PathsAndQueries) -> m [Text] -> m PathsAndQueries
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text] -> RequestHeaders -> m [Text]
convert (PathsAndQueries -> [Text]
forall a b. (a, b) -> a
fst PathsAndQueries
psAndQs) RequestHeaders
headers
{-# INLINE pathsOnly #-}