Finish documenting Caddy 2.8.0 features (#419)

This commit is contained in:
Francis Lavoie 2024-09-29 05:44:26 -04:00 committed by GitHub
parent 6ac5539ef9
commit af347e9623
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 481 additions and 113 deletions

View file

@ -6,6 +6,12 @@ title: encode (Caddyfile directive)
window.$(function() {
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
addLinksToSubdirectives();
// Response matchers
window.$('pre.chroma .k:contains("status")')
.html('<a href="/docs/caddyfile/response-matchers#status" style="color: inherit;" title="Response matcher">status</a>')
window.$('pre.chroma .k:contains("header")')
.html('<a href="/docs/caddyfile/response-matchers#header" style="color: inherit;" title="Response matcher">header</a>')
});
</script>
@ -23,9 +29,6 @@ encode [<matcher>] <formats...> {
minimum_length <length>
# response matcher single line syntax
match [header <field> [<value>]] | [status <code...>]
# or response matcher block for multiple conditions
match {
status <code...>
header <field> [<value>]
@ -41,7 +44,7 @@ encode [<matcher>] <formats...> {
- **minimum_length** <span id="minimum_length"/> the minimum number of bytes a response should have to be encoded (default: 512).
- **match** <span id="match"/> is a [response matcher](#response-matcher). Only matching responses are encoded. The default looks like this:
- **match** <span id="match"/> is a [response matcher](/docs/caddyfile/response-matchers). Only matching responses are encoded. The default looks like this:
```caddy-d
match {
@ -82,27 +85,6 @@ encode [<matcher>] <formats...> {
```
## Response matcher
**Response matchers** can be used to filter (or classify) responses by specific criteria.
### status
```caddy-d
status <code...>
```
By HTTP status code.
- **&lt;code...&gt;** is a list of HTTP status codes. Special cases are `2xx`, `3xx`, ... which match against all status codes in the range of 200-299, 300-399, ... respectively
### header
See the [header](/docs/caddyfile/matchers#header) request matcher for the supported syntax.
## Examples
Enable Gzip compression:

View file

@ -24,6 +24,8 @@ Most often, the `file_server` directive is paired with the [`root`](root) direct
When errors occur (e.g. file not found `404`, permission denied `403`), the error routes will be invoked. Use the [`handle_errors`](handle_errors) directive to define error routes, and display custom error pages.
When using `browse`, the default output is produced by the the HTML template. Clients may request the directory listing as either JSON or plaintext, by using the `Accept: application/json` or `Accept: text/plain` headers respectively. The JSON output can be useful for scripting, and the plaintext output can be useful for human terminal usage.
## Syntax

View file

@ -56,13 +56,13 @@ header [<matcher>] [[+|-|?|>]<field> [<value>|<find>] [<replace>]] {
- **&lt;find&gt;** is the substring or regular expression to search for.
- **&lt;replace&gt;** is the replacement value; required if performing a search-and-replace.
- **&lt;replace&gt;** is the replacement value; required if performing a search-and-replace. Use `$1` or `$2` and so on to reference capture groups from the search pattern. If the replacement value is `""`, then the matching text is removed from the value. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details.
- **defer** will force the header operations to be deferred until the response is being written out to the client. This is automatically enabled if any of the header fields are being deleted with `-`, when setting a default value with `?`, or when having used the `>` prefix.
For multiple header manipulations, you can open a block and specify one manipulation per line in the same way.
When using the `?` prefix to set a default header value, it is automatically separated into its own `header` handler, if it was in a `header` block with multiple header operations. [Under the hood](/docs/modules/http.handlers.headers#response/require), using `?` configures a response matcher which applies to the directive's entire handler, which only applies the header operations (like `defer`), but only if the field is not yet set.
When using the `?` prefix to set a default header value, it is automatically separated into its own `header` handler, if it was in a `header` block with multiple header operations. [Under the hood](/docs/modules/http.handlers.headers#response/require), using `?` configures a [response matcher](/docs/caddyfile/response-matchers) which applies to the directive's entire handler, which only applies the header operations (like `defer`), but only if the field is not yet set.
## Examples

View file

@ -0,0 +1,93 @@
---
title: intercept (Caddyfile directive)
---
<script>
window.$(function() {
// Fix response matchers to render with the right color,
// and link to response matchers section
window.$('pre.chroma .k:contains("@")')
.map(function(k, item) {
let text = item.innerText.replace(/</g,'&lt;').replace(/>/g,'&gt;');
let url = '#' + item.innerText.replace(/_/g, "-");
window.$(item).addClass('nd').removeClass('k')
window.$(item).html(`<a href="#response-matcher" style="color: inherit;" title="Response matcher">${text}</a>`);
});
// Response matchers
window.$('pre.chroma .nd:contains("@name")').first().slice(0, 3)
.wrapAll('<span class="nd">').parent()
.html('<a href="/docs/caddyfile/response-matchers" style="color: inherit;">@name</a>')
window.$('pre.chroma .k:contains("replace_status")').first().next()
.html('<a href="/docs/caddyfile/response-matchers" style="color: inherit;" title="Response matcher">[&lt;matcher&gt;]</a>')
window.$('pre.chroma .k:contains("handle_response")').first().next()
.html('<a href="/docs/caddyfile/response-matchers" style="color: inherit;" title="Response matcher">[&lt;matcher&gt;]</a>')
window.$('pre.chroma .k')
.filter((i, el) => el.innerText === 'status')
.html('<a href="/docs/caddyfile/response-matchers#status" style="color: inherit;">status</a>')
window.$('pre.chroma .k:contains("header")').first()
.html('<a href="/docs/caddyfile/response-matchers#header" style="color: inherit;">header</a>')
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
addLinksToSubdirectives();
});
</script>
# intercept
A generalized abstraction of the [response interception](reverse_proxy#intercepting-responses) feature from the [`reverse_proxy` directive](reverse_proxy). This may be used with any handler that produces responses, including those from plugins like [FrankenPHP](https://frankenphp.dev/)'s `php_server`.
This directive allows you to [match responses](/docs/caddyfile/response-matchers), and the first matching `handle_response` route or `replace_status` will be invoked. When invoked, the original response body is held back, giving the opportunity to that route to write a different response body, with a new status code or with any necessary response header manipulations. If the route does _not_ write a new response body, then original response body is written instead.
## Syntax
```caddy-d
intercept [<matcher>] {
@name {
status <code...>
header <field> [<value>]
}
replace_status [<matcher>] <code>
handle_response [<matcher>] {
<directives...>
}
}
```
- **@name** is the name of a [response matcher](/docs/caddyfile/response-matchers). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
- **replace_status** <span id="replace_status"/> simply changes the status code of response when matched by the given matcher.
- **handle_response** <span id="handle_response"/> defines the route to execute when matched by the given matcher (or, if a matcher is omitted, all responses). The first matching block will be applied. Inside a `handle_response` block, any other [directives](/docs/caddyfile/directives) can be used.
Within `handle_response` routes, the following placeholders are available to pull information from the original response:
- `{resp.status_code}` The status code of the original response.
- `{resp.header.*}` The headers from the original response.
## Examples
When using [FrankenPHP](https://frankenphp.dev/)'s `php_server`, you can use `intercept` to implement `X-Accel-Redirect` support, serving static files as requested by the PHP app:
```caddy
localhost {
root * /srv
intercept {
@accel header X-Accel-Redirect *
handle_response @accel {
root * /path/to/private/files
rewrite {resp.header.X-Accel-Redirect}
method GET
file_server
}
}
php_server
}
```

View file

@ -59,7 +59,7 @@ To add custom fields to the log entries, use the [`log_append` directive](log_ap
- [append](#append)
- [Examples](#examples)
Since Caddy v2.5, by default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged with empty values. This behaviour can be disabled with the [`log_credentials`](/docs/caddyfile/options#log-credentials) global server option.
By default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged as `REDACTED` in access logs. This behaviour can be disabled with the [`log_credentials`](/docs/caddyfile/options#log-credentials) global server option.
## Syntax
@ -67,29 +67,34 @@ Since Caddy v2.5, by default, headers with potentially sensitive information (`C
```caddy-d
log [<logger_name>] {
hostnames <hostnames...>
no_hostname
output <writer_module> ...
format <encoder_module> ...
level <level>
}
```
- **logger_name** is an optional override of the logger name for this site.
- **logger_name** <span id="logger_name"/> is an optional override of the logger name for this site.
By default, a logger name is generated automatically, e.g. `log0`, `log1`, and so on depending on the order of the sites in the Caddyfile. This is only useful if you wish to reliably refer to the output of this logger from another logger defined in global options. See [an example](#multiple-outputs) below.
- **hostnames** is an optional override of the hostnames that this logger applies to.
- **hostnames** <span id="hostnames"/> is an optional override of the hostnames that this logger applies to.
By default, the logger applies to the hostnames of the site block it appears in, i.e. the site addresses. This is useful if you wish to define different loggers per subdomain in a [wildcard site block](/docs/caddyfile/patterns#wildcard-certificates). See [an example](#wildcard-logs) below.
- **output** configures where to write the logs. See [`output` modules](#output-modules) below.
- **no_hostname** <span id="no_hostname"/> prevents the logger from being associated with any of the site block's hostnames. By default, the logger is associated with the [site address](/docs/caddyfile/concepts#addresses) that the `log` directive appears in.
This is useful when you want to log requests to different files based on some condition, such as the request path or method, using the [`log_name` directive](/docs/caddyfile/directives/log_name).
- **output** <span id="output"/> configures where to write the logs. See [`output` modules](#output-modules) below.
Default: `stderr`.
- **format** describes how to encode, or format, the logs. See [`format` modules](#format-modules) below.
- **format** <span id="format"/> describes how to encode, or format, the logs. See [`format` modules](#format-modules) below.
Default: `console` if `stderr` is detected to be a terminal, `json` otherwise.
- **level** is the minimum entry level to log. Default: `INFO`.
- **level** <span id="level"/> is the minimum entry level to log. Default: `INFO`.
Note that access logs currently only emit `INFO` and `ERROR` level logs.
@ -251,8 +256,9 @@ format <encoder_module> {
Default: `seconds`.
May be one of:
- `seconds` Floating-point number of seconds elapsed.
- `nano` Integer number of nanoseconds elapsed.
- `s`, `second` or `seconds` Floating-point number of seconds elapsed.
- `ms`, `milli` or `millis` Floating-point number of milliseconds elapsed.
- `ns`, `nano` or `nanos` Integer number of nanoseconds elapsed.
- `string` Using Go's built-in string format, for example `1m32.05s` or `6.31ms`.
- **level_format** The format for levels.

View file

@ -0,0 +1,49 @@
---
title: log_name (Caddyfile directive)
---
# log_name
Overrides the logger name to use for a request when writing access logs with the [`log` directive](log).
This directive is useful when you want to log requests to different files based on some condition, such as the request path or method.
More than one logger name can be specified, such that the request's log gets pushed to more than one matching logger.
This is often paired with the `log` directive's [`no_hostname`](log#no_hostname) option, which prevents the logger from being associated with any of the site block's hostnames, so that only requests that set `log_name` will push logs to that logger.
## Syntax
```caddy-d
log_name [<matcher>] <names...>
```
## Examples
You may want to log requests to different files, for example you might want to log health checks to a separate file from the main access logs.
Using `no_hostname` in a `log` prevents the logger from being associated with any of the site block's hostnames (i.e. `localhost` here), so that only requests that have `log_name` set to that logger's name will receive logs.
```caddy
localhost {
log {
output file ./caddy.access.log
}
log health_check_log {
output file ./caddy.access.health.log
no_hostname
}
handle /healthz* {
log_name health_check_log
respond "Healthy"
}
handle {
respond "Hello World"
}
}
```

View file

@ -11,13 +11,18 @@ window.$(function() {
let text = item.innerText.replace(/</g,'&lt;').replace(/>/g,'&gt;');
let url = '#' + item.innerText.replace(/_/g, "-");
window.$(item).addClass('nd').removeClass('k')
window.$(item).html(`<a href="#response-matcher" style="color: inherit;" title="Response matcher">${text}</a>`);
window.$(item).html(`<a href="/docs/caddyfile/response-matchers" style="color: inherit;" title="Response matcher">${text}</a>`);
});
// Fix matcher placeholder
window.$('pre.chroma .k:contains("handle_response")').first().nextAll().slice(0, 3)
window.$('pre.chroma .nd:contains("@name")').first()
.html('<a href="/docs/caddyfile/response-matchers" style="color: inherit;" title="Response matcher">@name</a>')
window.$('pre.chroma .k:contains("replace_status")').first().next().slice(0, 3)
.wrapAll('<span class="nd">').parent()
.html('<a href="#response-matcher" style="color: inherit;" title="Response matcher">[&lt;matcher&gt;]</a>')
.html('<a href="/docs/caddyfile/response-matchers" style="color: inherit;" title="Response matcher">[&lt;matcher&gt;]</a>')
window.$('pre.chroma .k:contains("handle_response")').first().next().slice(0, 3)
.wrapAll('<span class="nd">').parent()
.html('<a href="/docs/caddyfile/response-matchers" style="color: inherit;" title="Response matcher">[&lt;matcher&gt;]</a>')
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
addLinksToSubdirectives();
@ -69,6 +74,8 @@ reverse_proxy [<matcher>] [<upstreams...>] {
health_uri <uri>
health_port <port>
health_interval <interval>
health_passes <num>
health_fails <num>
health_timeout <duration>
health_status <status>
health_body <regexp>
@ -126,14 +133,14 @@ reverse_proxy [<matcher>] [<upstreams...>] {
### Upstreams
## Upstreams
- **&lt;upstreams...&gt;** is a list of upstreams (backends) to which to proxy.
- **to** <span id="to"/> is an alternate way to specify the list of upstreams, one (or more) per line.
- **dynamic** <span id="dynamic"/> configures a _dynamic upstreams_ module. This allows getting the list of upstreams dynamically for every request. See [dynamic upstreams](#dynamic-upstreams) below for a description of standard dynamic upstream modules. Dynamic upstreams are retrieved at every proxy loop iteration (i.e. potentially multiple times per request if load balancing retries are enabled) and will be preferred over static upstreams. If an error occurs, the proxy will fall back to using any statically-configured upstreams.
#### Upstream addresses
### Upstream addresses
Static upstream addresses can take the form of a URL that contains only scheme and host/port, or a conventional [Caddy network address](/docs/conventions#network-addresses). Valid examples:
@ -169,12 +176,12 @@ Upstream addresses **cannot** contain paths or query strings, as that would impl
If the address is not a URL (i.e. does not have a scheme), then [placeholders](/docs/caddyfile/concepts#placeholders) can be used, but this makes the upstream _dynamically static_, meaning that potentially many different backends act as a single, static upstream in terms of health checks and load balancing. We recommend using a [dynamic upstreams](#dynamic-upstreams) module instead, if possible. When using placeholders, a port **must** be included (either by the placeholder replacement, or as a static suffix to the address).
#### Dynamic upstreams
### Dynamic upstreams
Caddy's reverse proxy comes standard with some dynamic upstream modules. Note that using dynamic upstreams has implications for load balancing and health checks, depending on specific policy configuration: active health checks do not run for dynamic upstreams; and load balancing and passive health checks are best served if the list of upstreams is relatively stable and consistent (especially with round-robin). Ideally, dynamic upstream modules only return healthy, usable backends.
##### SRV
#### SRV
Retrieves upstreams from SRV DNS records.
@ -201,7 +208,7 @@ Retrieves upstreams from SRV DNS records.
##### A/AAAA
#### A/AAAA
Retrieves upstreams from A/AAAA DNS records.
@ -226,7 +233,7 @@ Retrieves upstreams from A/AAAA DNS records.
- **versions** is the list of IP versions to resolve for. Default: `ipv4 ipv6` which correspond to both A and AAAA records respectively.
##### Multi
#### Multi
Append the results of multiple dynamic upstream modules. Useful if you want redundant sources of upstreams, for example: a primary cluster of SRVs backed up by a secondary cluster of SRVs.
@ -241,7 +248,7 @@ Append the results of multiple dynamic upstream modules. Useful if you want redu
### Load balancing
## Load balancing
Load balancing is typically used to split traffic between multiple upstreams. By enabling retries, it can also be used with one or more upstreams, to hold requests until a healthy upstream can be selected (e.g. to wait and mitigate errors while rebooting or redeploying an upstream).
@ -313,7 +320,7 @@ This is enabled by default, with the `random` policy. Retries are disabled by de
#### Active health checks
### Active health checks
Active health checks perform health checking in the background on a timer. To enable this, `health_uri` or `health_port` are required.
@ -323,19 +330,23 @@ Active health checks perform health checking in the background on a timer. To en
- **health_interval** <span id="health_interval"/> is a [duration value](/docs/conventions#durations) that defines how often to perform active health checks. Default: `30s`.
- **health_passes** <span id="health_passes"/> is the number of consecutive health checks required before marking the backend as healthy again. Default: `1`.
- **health_fails** <span id="health_fails"/> is the number of consecutive health checks required before marking the backend as unhealthy. Default: `1`.
- **health_timeout** <span id="health_timeout"/> is a [duration value](/docs/conventions#durations) that defines how long to wait for a reply before marking the backend as down. Default: `5s`.
- **health_status** <span id="health_status"/> is the HTTP status code to expect from a healthy backend. Can be a 3-digit status code, or a status code class ending in `xx`. For example: `200` (which is the default), or `2xx`.
- **health_body** <span id="health_body"/> is a substring or regular expression to match on the response body of an active health check. If the backend does not return a matching body, it will be marked as down.
- **health_follow_redirects** <span id="health_follow_redirects"/> will cause the health check to follow redirects provided by upstream. Without this setting, a redirect will cause the check to fail.
- **health_follow_redirects** <span id="health_follow_redirects"/> will cause the health check to follow redirects provided by upstream. By default, a redirect response would cause the health check to count as a fail.
- **health_headers** <span id="health_headers"/> allows specifying headers to set on the active health check requests. This is useful if you need to change the `Host` header, or if you need to provide some authentication to your backend as part of your health checks.
#### Passive health checks
### Passive health checks
Passive health checks happen inline with actual proxied requests. To enable this, `fail_duration` is required.
@ -352,7 +363,7 @@ Passive health checks happen inline with actual proxied requests. To enable this
This should be a reasonably large number; configuring this means that the proxy will have a limit of `unhealthy_request_count × upstreams_count` total simultaneous requests, and any requests after that point will result in an error due to no upstreams being available.
### Events
## Events
When an upstream transitions from being healthy to unhealthy or vice-versa, [an event](/docs/caddyfile/options#event-options) is emitted. These events can be used to trigger other actions, such as sending a notification or logging a message. The events are as follows:
@ -363,7 +374,7 @@ In both cases, the `host` is included as metadata in the event to identify the u
### Streaming
## Streaming
By default, the proxy partially buffers the response for wire efficiency.
@ -390,7 +401,7 @@ By default, WebSocket connections are forcibly closed (with a Close control mess
### Headers
## Headers
The proxy can **manipulate headers** between itself and the backend:
@ -438,7 +449,7 @@ header_up Some-Header "^prefix-([A-Za-z0-9]*)$" "replaced-$1-suffix"
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax). The replacement string is [expanded](https://pkg.go.dev/regexp#Regexp.Expand), allowing use of captured values, for example `$1` being the first capture group.
#### Defaults
### Defaults
By default, Caddy passes thru incoming headers&mdash;including `Host`&mdash;to the backend without modifications, with three exceptions:
@ -461,7 +472,7 @@ If you're using Cloudflare in front of Caddy, be aware that you may be vulnerabl
Additionally, when using the [`http` transport](#the-http-transport), the `Accept-Encoding: gzip` header will be set, if it is missing in the request from the client. This allows the upstream to serve compressed content if it can. This behavior can be disabled with [`compression off`](#compression) on the transport.
#### HTTPS
### HTTPS
Since (most) headers retain their original value when being proxied, it is often necessary to override the `Host` header with the configured upstream address when proxying to HTTPS, such that the `Host` header matches the TLS ServerName value:
@ -475,7 +486,7 @@ The `X-Forwarded-Host` header is still passed [by default](#defaults), so the up
### Rewrites
## Rewrites
By default, Caddy performs the upstream request with the same HTTP method and URI as the incoming request, unless a rewrite was performed in the middleware chain before it reaches `reverse_proxy`.
@ -493,14 +504,14 @@ For example, the request could be sent to an authentication gateway to decide wh
### Transports
## Transports
Caddy's proxy **transport** is pluggable:
- **transport** <span id="transport"/> defines how to communicate with the backend. Default is `http`.
#### The `http` transport
### The `http` transport
```caddy-d
transport http {
@ -588,20 +599,26 @@ transport http {
- **keepalive_idle_conns_per_host** <span id="keepalive_idle_conns_per_host"/> if non-zero, controls the maximum idle (keep-alive) connections to keep per-host. Default: `32`.
- **versions** <span id="versions"/> allows customizing which versions of HTTP to support. As a special case, "h2c" is a valid value which will enable cleartext HTTP/2 connections to the upstream (however, this is a non-standard feature that does not use Go's default HTTP transport, so it is exclusive of other features; subject to change or removal). Default: `1.1 2`, or if scheme is `h2c://`, `h2c 2`
- **versions** <span id="versions"/> allows customizing which versions of HTTP to support.
Valid options are: `1.1`, `2`, `h2c`, `3`.
Default: `1.1 2`, or if the [upstream's scheme](#upstream-addresses) is `h2c://`, then the default is `h2c 2`.
`h2c` enables cleartext HTTP/2 connections to the upstream. This is a non-standard feature that does not use Go's default HTTP transport, so it is exclusive of other features.
`3` enables HTTP/3 connections to the upstream. ⚠️ This is an experimental feature and is subject to change.
- **compression** <span id="compression"/> can be used to disable compression to the backend by setting it to `off`.
- **max_conns_per_host** <span id="max_conns_per_host"/> optionally limits the total number of connections per host, including connections in the dialing, active, and idle states. Default: No limit.
- **forward_proxy_url** <span id="forward_proxy_url"/> is a parameter that specifies the URL of a server that the HTTP transport will use to proxy requests to the upstream server. This parameter takes precedence over environment variables like HTTP_PROXY. When a value is provided for this parameter, requests will flow through the reverse proxy in the following order:
a. User Agent -> Reverse Proxy
b. Reverse Proxy -> Forward Proxy (specified by `forward_proxy_url`)
c. Forward Proxy -> Upstream Server
- **forward_proxy_url** <span id="forward_proxy_url"/> specifies the URL of a server that the HTTP transport will use to proxy requests to the upstream server. By default, Caddy respects proxy configured via environment variables as per the [Go stdlib](https://pkg.go.dev/golang.org/x/net/http/httpproxy#FromEnvironment) like `HTTP_PROXY`. When a value is provided for this parameter, requests will flow through the reverse proxy in the following order:
- Client (users) 🡒 `reverse_proxy` 🡒 `forward_proxy_url` 🡒 upstream
#### The `fastcgi` transport
### The `fastcgi` transport
```caddy-d
transport fastcgi {
@ -640,47 +657,33 @@ If you're trying to serve a modern PHP application, you may be looking for the [
### Intercepting responses
## Intercepting responses
The reverse proxy can be configured to intercept responses from the backend. To facilitate this, response matchers can be defined (similar to the syntax for request matchers) and the first matching `handle_response` route will be invoked.
The reverse proxy can be configured to intercept responses from the backend. To facilitate this, [response matchers](/docs/caddyfile/response-matchers) can be defined (similar to the syntax for request matchers) and the first matching `handle_response` route will be invoked.
When a response handler is invoked, the response from the backend is not written to the client, and the configured `handle_response` route will be executed instead, and it is up to that route to write a response. If the route does _not_ write a response, then request handling will continue with any handlers that are [ordered after](/docs/caddyfile/directives#directive-order) this `reverse_proxy`.
- **@name** is the name of a [response matcher](#response-matcher). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
- **@name** is the name of a [response matcher](/docs/caddyfile/response-matchers). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
- **replace_status** <span id="replace_status"/> simply changes the status code of response when matched by the given matcher.
- **handle_response** <span id="handle_response"/> defines the route to execute when matched by the given matcher (or, if a matcher is omitted, all responses). The first matching block will be applied. Inside a `handle_response` block, any other [directives](/docs/caddyfile/directives) can be used.
Additionally, inside `handle_response`, two special handler directives may be used:
- **copy_response** <span id="copy_response"/> copies the response body received from the backend back to the client. Optionally allows changing the status code of the response while doing so. This directive is [ordered before `respond`](/docs/caddyfile/directives#directive-order).
- **copy_response_headers** <span id="copy_response_headers"/> copies the response headers from the backend to the client, optionally including _OR_ excluding a list of headers fields (cannot specify both `include` and `exclude`). This directive is [ordered after `header`](/docs/caddyfile/directives#directive-order).
Three placeholders will be made available within the `handle_response` routes:
- `{rp.status_code}` The status code from the backend's response.
- `{rp.status_text}` The status text from the backend's response.
- `{rp.header.*}` The headers from the backend's response.
#### Response matcher
**Response matchers** can be used to filter (or classify) responses by specific criteria.
##### status
```caddy-d
status <code...>
```
By HTTP status code.
- **&lt;code...&gt;** is a list of HTTP status codes. Special cases are strings like `2xx` and `3xx`, which match against all status codes in the range of `200`-`299` and `300`-`399`, respectively.
##### header
See the [`header`](/docs/caddyfile/matchers#header) request matcher for the supported syntax.

View file

@ -18,23 +18,56 @@ uri [<matcher>] strip_prefix <target>
uri [<matcher>] strip_suffix <target>
uri [<matcher>] replace <target> <replacement> [<limit>]
uri [<matcher>] path_regexp <target> <replacement>
uri [<matcher>] query [-|+]<param> [<value>]
uri [<matcher>] query {
<param> [<value>] [<replacement>]
...
}
```
- The first (non-matcher) argument specifies the operation:
The first (non-matcher) argument specifies the operation:
- **strip_prefix** strips the prefix from the path.
- **strip_prefix** strips the prefix from the path.
- **strip_suffix** strips the suffix from the path.
- **strip_suffix** strips the suffix from the path.
- **replace** performs a substring replacement across the whole URI.
- **replace** performs a substring replacement across the whole URI.
- **path_regexp** performs a regular expression replacement on the path portion of the URI.
- **&lt;target&gt;** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
- **&lt;target&gt;** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
- **&lt;replacement&gt;** is the replacement string. Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details. If the replacement value is `""`, then the matching text is removed from the value.
- **&lt;replacement&gt;** is the replacement string (only valid with `replace` and `path_regexp`). Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details.
- **&lt;limit&gt;** is an optional limit to the maximum number of replacements.
- **&lt;limit&gt;** is an optional limit to the maximum number of replacements (only valid with `replace`).
- **path_regexp** performs a regular expression replacement on the path portion of the URI.
- **&lt;target&gt;** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
- **&lt;replacement&gt;** is the replacement string. Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details. If the replacement value is `""`, then the matching text is removed from the value.
- **query** performs manipulations on the URI query, with the mode depending on the prefix to the parameter name or the count of arguments. A block can be used to specify multiple operations at once, grouped and performed in this order: rename 🡒 set 🡒 append 🡒 replace 🡒 delete.
- With no prefix, the parameter is set with the given value in the query.
For example, `uri query foo bar` will set the value of the `foo` param to `bar`.
- Prefix with `-` to remove the parameter from the query.
For example, `uri query -foo` will delete the `foo` parameter from the query.
- Prefix with `+` to append a parameter to the query, with the given value. This will _not_ overwrite an existing parameter with the same name (omit the `+` to overwrite).
For example, `uri query +foo bar` will append `foo=bar` to the query.
- A param with `>` as an infix will rename the parameter to the value after the `>`.
For example, `uri query foo>bar` will rename the `foo` parameter to `bar`.
- With three arguments, query value regular expression replacement is performed, where the first arg is the query param name, the second is the search value, and the third is the replacement. The first arg (param name) may be `*` to perform the replacement on all query params.
Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details. If the replacement value is `""`, then the matching text is removed from the value.
For example, `uri query foo ^(ba)r $1z` would replace the value of the `foo` param, where the value began with `bar` resulting in the value becoming `baz`.
URI mutations occur on the normalized or unescaped form of the URI. However, escape sequences can be used in the prefix or suffix patterns to match only those literal escapes at those positions in the request path. For example, `uri strip_prefix /a/b` will rewrite both `/a/b/c` and `/a%2Fb/c` to `/c`; and `uri strip_prefix /a%2Fb` will rewrite `/a%2Fb/c` to `/c`, but won't match `/a/b/c`.
@ -74,3 +107,44 @@ Collapse all repeated slashes in the request path (but not the request query) to
```caddy-d
uri path_regexp /{2,} /
```
Set the value of the `foo` query parameter to `bar`:
```caddy-d
uri query foo bar
```
Remove the `foo` parameter from the query:
```caddy-d
uri query -foo
```
Rename the `foo` query parameter to `bar`:
```caddy-d
uri query foo>bar
```
Append the `bar` parameter to the query:
```caddy-d
uri query +foo bar
```
Replace the value of the `foo` query parameter where the value begins with `bar` with `baz`:
```caddy-d
uri query foo ^(ba)r $1z
```
Perform multiple query operations at once:
```caddy-d
uri query {
+foo bar
-baz
qux test
renamethis>renamed
}
```