Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
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 Request
s
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")] :: QueryText
Together,
/foo?bar=baz would look like
(["foo"],[("bar", Just "baz")]) :: PathsAndQueries
type 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 ->PathsAndQueries
staticConvert pathsAndQueries _ =first
piecesConvert 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
rewrite
modifiedrawPathInfo
, 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 Request
s
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.