| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Network.Wai.Middleware.Rewrite
Contents
Synopsis
- type PathsAndQueries = ([Text], Query)
- rewriteWithQueries :: (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries) -> Middleware
- rewritePureWithQueries :: (PathsAndQueries -> RequestHeaders -> PathsAndQueries) -> Middleware
- rewriteRoot :: Text -> Middleware
- rewrite :: ([Text] -> RequestHeaders -> IO [Text]) -> Middleware
- rewritePure :: ([Text] -> RequestHeaders -> [Text]) -> Middleware
- rewriteRequest :: (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries) -> Request -> IO Request
- rewriteRequestPure :: (PathsAndQueries -> RequestHeaders -> PathsAndQueries) -> Request -> Request
How to use this module
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 Requests
directly, use rewriteRequest or rewriteRequestPure.
A note on 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.
Paths and Queries
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")] :: QueryTextTogether,
/foo?bar=baz would look like
(["foo"],[("bar", Just "baz")]) :: PathsAndQueriestype PathsAndQueries = ([Text], Query) Source #
A tuple of the path sections as [Text] and query parameters as
Query. This makes writing type signatures for the conversion
function far more pleasant.
Note that this uses Query not QueryText to more accurately
reflect the paramaters that can be supplied in URLs. It may be safe to
treat parameters as text; use the queryToQueryText and
queryTextToQuery functions to interconvert.
An example rewriting paths with queries
Let’s say we want to replace a website written in PHP with one written using WAI. We’ll use the 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
WPRModifiedRequest or
WPRModifiedRequestSecure constructors. Note,
these links will only work if the haddock documentation for
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 from wai-extra ≤ 3.0.16.1
It is quite simple to upgrade from rewrite and rewritePure, to
rewriteWithQueries and rewritePureWithQueries.
Insert first, which specialises to
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 ->PathsAndQueriesstaticConvert pathsAndQueries _ =firstpiecesConvert pathsAndQueries where piecesConvert [] = ["static", "html", "pages.html"] piecesConvert route@("pages":_) = "static":"html":route
The former formulation is deprecated for two reasons:
- The original formulation of
rewritemodifiedrawPathInfo, which is deprecated behaviour. - 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.
Middleware
Recommended functions
rewriteWithQueries :: (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries) -> Middleware Source #
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.
rewritePureWithQueries :: (PathsAndQueries -> RequestHeaders -> PathsAndQueries) -> Middleware Source #
Rewrite based on pure conversion function for paths and queries. This function is to be supplied by users of this library.
rewriteRoot :: Text -> Middleware Source #
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
Deprecated
rewrite :: ([Text] -> RequestHeaders -> IO [Text]) -> Middleware Source #
Warning: 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 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.
rewritePure :: ([Text] -> RequestHeaders -> [Text]) -> Middleware Source #
Warning: 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 pure conversion function for paths only, to be supplied by users of this library.
For new code, use rewritePureWithQueries instead.
Operating on Requests
rewriteRequest :: (PathsAndQueries -> RequestHeaders -> IO PathsAndQueries) -> Request -> IO Request Source #
rewriteRequestPure :: (PathsAndQueries -> RequestHeaders -> PathsAndQueries) -> Request -> Request Source #
Modify a Request using the pure supplied function. This is suitable for
the reverse proxy example.