PingGateway 2024.11

UriPathRewriteFilter

Rewrite a URL path, using a bidirectional mapping:

  • In the request flow, fromPath is mapped to toPath.

  • In the response flow, toPath is mapped to fromPath.

PingGateway overwrites a response header only when all of the following conditions are true:

  • The response includes a header such as Location or Content-Location

  • The URI of the response header matches the mapping

  • The value of response header is a relative path or its scheme://host:port value matches the base URI.

Usage

{
  "name": string,
  "type": "UriPathRewriteFilter",
  "config": {
    "mappings": object,
    "failureHandler": Handler reference
  }
}

Properties

"mappings": object, required

One or more bidirectional mappings between URL paths. You can find example mappings, request scenarios, and an example route in Examples.

{
  "mappings": {
    "/fromPath1": "/toPath1",
    "/fromPath2": "/toPath2",
    ...
  }
}

Paths are given by a configuration expression<string>. Consider the following points when you define paths:

  • The incoming URL must start with the mapping path.

  • When more than one mapping applies to a URL, the most specific mapping is used.

  • Duplicate fromPath values are removed without warning.

  • Trailing slashes / are removed from path values.

  • If the response includes a Location or Content-Location header with a toPath in its URL, the response is rewritten with fromPath.

"failureHandler": handler reference, optional

Failure handler to be invoked if an invalid URL is produced when the request path is mapped, or when the response Location or Content-Location header URI path is reverse-mapped.

Provide an inline handler declaration, or the name of a handler object defined in the heap. See also Handlers.

Default: HTTP 500

Examples

Valid and invalid mapping examples

The following mapping examples are valid:

  • Single fromPath and toPath

    "mappings": {
      "/fromPath1": "/toPath1",
      "/fromPath2": "/toPath2"
    }
  • Expressions in the fromPath and toPath

    "mappings": {
      "/${join(array(`fromPath`, 'path1'), `/`)}": "/${join(array(`toPath`, 'path2'), `/`)}"
    }
  • Expressions in the fromPath and toPath that use predefined heap properties

    "mappings": {
      "${fromPath}": "${toPath}"
    }
  • No mappings—the configuration is valid, but has no effect

    "mappings": { }
  • Duplicate toPath

    "mappings": {
      "/fromPath1": "/toPath",
      "/fromPath2": "/toPath"
    }
  • Duplicate fromPath—the configuration is overwritten without warning

    "mappings": {
      "/fromPath": "/toPath1",
      "/fromPath": "/toPath2"
    }

The following mapping examples aren’t valid

  • No toPath

    "mappings": {
      "/fromPath": ""
    }
    "mappings": {
      "/fromPath": "${unknown}"
    }
  • Invalid toPath

    "mappings": {
      "/fromPath": "${invalidExpression}"
    }
  • No fromPath

    "mappings": {
      "": "/toPath"
    }
    "mappings": {
        "${unknown}": "/toPath"
    }
  • Invalid fromPath

    "mappings": {
        "${invalidExpression}": "/toPath"
    }

Example request scenarios

Description Mapping Inbound URI Rewritten URI

Basic path

"mappings": {
  "/fromPath": "/toPath"
}

https://example.com/fromPath/remainder

https://example.com/toPath/remainder

Root context, where the inbound request URI has a / path segment

"mappings": {
  "/": "/rootcontext"
}

https://example.com/

https://example.com/rootcontext/

Root context, where the inbound URI has a / path segment

"mappings": {
  "/rootcontext": "/"
}

https://example.com/rootcontext/

https://example.com/

Root context, where the inbound request URI has an empty path

"mappings": {
  "/": "/rootcontext"
}

https://example.com

https://example.com/rootcontext

Root context, where the rewritten URI has an empty path

"mappings": {
  "/rootcontext": "/"
}

https://example.com/rootcontext

https://example.com

Root context, with path remainder

"mappings": {
  "/": "/rootcontext"
}

https://example.com/remainder

https://example.com/rootcontext/remainder

Root context, with path remainder

"mappings": {
  "/rootcontext": "/"
}

https://example.com/rootcontext/remainder

https://example.com/remainder

Root context, where the trailing / on toPath is ignored

"mappings": {
  "/": "/rootcontext/"
}

https://example.com/remainder

https://example.com/rootcontext/remainder

Path with dot-segments:

"mappings": {
  "/fromPath": "/toPath1/../toPath2"
}

https://example.com/fromPath

https://example.com/toPath1/../toPath2

Path with syntax:

"mappings": {
  "/fromPath;v=1.1": "/toPath,1.1"
}

https://example.com/fromPath;v=1.1

https://example.com/toPath,1.1

Path with syntax:

"mappings": {
  "/$fromPath": "/$toPath"
}

https://example.com/$fromPath

https://example.com/$toPath

Path with query parameters

"mappings": {
  "/fromPath": "/toPath"
}

https://example.com/fromPath?param1&param2=2

https://example.com/toPath?param1&param2=2

Path with fragment

"mappings": {
  "/fromPath": "/toPath"
}

https://example.com/fromPath#fragment

https://example.com/toPath#fragment

Example route

The example route changes a request URL as follows:

  • The baseURI overrides the scheme, host, and port of a request URL.

  • The UriPathRewriteFilter remaps the path of a request URL.

    Requests to https://ig.example.com:8443/mylogin are mapped to https://app.example.com:8444/login.

    Requests to https://ig.example.com:8443/welcome are mapped to https://app.example.com:8444/home.

    Requests to https://ig.example.com:8443/other are mapped to https://app.example.com:8444/not-found, and result in an HTTP 404.

    Requests to https://ig.example.com:8443/badurl are mapped to the invalid URL https://app.example.com:8444[, and invoke the failure handler.

{
  "name": "UriPathRewriteFilter",
  "baseURI": "https://app.example.com:8444",
  "handler": {
    "type": "Chain",
    "config": {
      "filters": [
        {
          "type": "UriPathRewriteFilter",
          "config": {
            "mappings": {
              "/mylogin": "/login",
              "/welcome": "/home",
              "/other": "/not-found",
              "/badurl": "["
            },
            "failureHandler": {
              "type": "StaticResponseHandler",
              "config": {
                "status": 500,
                "headers": {
                  "Content-Type": [
                    "text/plain"
                  ]
                },
                "entity": "Invalid URL produced"
              }
            }
          }
        }
      ],
      "handler": {
        "type": "ClientHandler",
        "config": {
          "tls": {
            "type": "ClientTlsOptions",
            "comment": "Blindly trust the gateway certificate",
            "config": {
              "trustManager": {
                "type": "TrustAllManager"
              },
              "hostnameVerifier": "ALLOW_ALL"
            }
          }
        }
      }
    }
  }
}