HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulewai-extra-3.1.16Haskell2010

Network.Wai.Middleware.Rewrite

  • 1 type
  • 7 values

How to use this module

0 declarations

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")] :: QueryText

Together,

/foo?bar=baz would look like

(["foo"],[("bar", Just "baz")]) :: PathsAndQueries
typetype PathsAndQueries = ([Text], Query)
#

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 Network.HTTP.ReverseProxy.WPRModifiedRequest or Network.HTTP.ReverseProxy.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:

  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.

Middleware

0 declarations

Recommended functions

valuerewriteRoot :: Text -> Middleware
#

Rewrite root requests (/) to a specified path

Note that index.html in example below should already be a valid route.

    rewriteRoot "index.html" :: Middleware

Deprecated

Operating on Requests

2 declarations