Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: document more of header directive behavior #442

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/docs/markdown/caddyfile/directives/encode.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ encode [<matcher>] <formats...> {

minimum_length <length>

match {
status <code...>
header <field> [<value>]
}
match <inline_response_matcher>
}
```

Expand Down
67 changes: 63 additions & 4 deletions src/docs/markdown/caddyfile/directives/header.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ header [<matcher>] [[+|-|?|>]<field> [<value>|<find>] [<replace>]] {
?<field> <value>

[defer]

match <inline_response_matcher>
}
```

- **&lt;field&gt;** is the name of the header field.

With no prefix, the field is set (overwritten).

Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request.
Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a response.
francislavoie marked this conversation as resolved.
Show resolved Hide resolved

Prefix with `-` to delete the field. The field may use prefix or suffix `*` wildcards to delete all matching fields.

Expand All @@ -58,7 +60,13 @@ header [<matcher>] [[+|-|?|>]<field> [<value>|<find>] [<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.
- **defer** defers the execution of header operations until the response is being sent to the client. This option is automatically enabled under the following conditions:
- When any header fields are deleted using `-`.
- When setting a default value with `?`.
- When using the `>` prefix on a set or replace operation.
- When one or more `match` conditions are present.

- **match** <span id="match"/> is an inline [response matcher](/docs/caddyfile/response-matchers). Header operations are applied only to responses that satisfy the specified conditions.

For multiple header manipulations, you can open a block and specify one manipulation per line in the same way.

Expand All @@ -67,7 +75,7 @@ When using the `?` prefix to set a default header value, it is automatically sep

## Examples

Set a custom header field on all requests:
Set a custom header field on all responses:

```caddy-d
header Custom-Header "My value"
Expand Down Expand Up @@ -119,10 +127,61 @@ header ?Cache-Control "max-age=3600"
reverse_proxy upstream:443
```

Mark all successful responses to GET requests as cacheable for upto an hour:

```caddy-d
@GET {
method GET
}
header @GET Cache-Control "max-age=3600" {
match status 2xx
}
reverse_proxy upstream:443
```

Prevent caching of error responses in the event of an exception in the upstream server:

```caddy-d
header {
-Cache-Control
-CDN-Cache-Control
match status 500
}
reverse_proxy upstream:443
```

Mark light mode responses as separately cacheable from dark mode responses if the upstream server supports client hints:
```caddy-d
header {
Cache-Control "max-age=3600"
Vary "Sec-CH-Prefers-Color-Scheme"
match {
header Accept-CH "*Sec-CH-Prefers-Color-Scheme*"
header Critical-CH "Sec-CH-Prefers-Color-Scheme"
}
}
reverse_proxy upstream:443
```

Prevent overly-permissive CORS headers by replacing wildcard values with a specific domain:
```caddy-d
header >Access-Control-Allow-Origin "\*" "allowed-partner.com"
reverse_proxy upstream:443
```
**Note**: In replacement operations, the `<find>` value is interpreted as a regular expression. To match the `*` character, it must be escaped with a backslash as shown in the above example.

Alternatively, you may use a [response matcher](/docs/caddyfile/response-matchers) to match a header value verbatim:
```caddy-d
header Access-Control-Allow-Origin "allowed-partner.com" {
match header Access-Control-Allow-Origin *
}
reverse_proxy upstream:443
```

To override the cache expiration that a proxy upstream had set for paths starting with `/no-cache`; enabling `defer` is necessary to ensure the header is set _after_ the proxy writes its headers:

```caddy-d
header /no-cache* >Cache-Control nocache
header /no-cache* >Cache-Control no-cache
reverse_proxy upstream:443
```

Expand Down
12 changes: 4 additions & 8 deletions src/docs/markdown/caddyfile/directives/intercept.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ window.$(function() {
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>')
Expand Down Expand Up @@ -49,19 +45,19 @@ intercept [<matcher>] {
header <field> [<value>]
}

replace_status [<matcher>] <code>
replace_status [<response_matcher>] <code>

handle_response [<matcher>] {
handle_response [<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.
- **@name** is a named [response matcher](/docs/caddyfile/response-matchers) block. 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.
- **handle_response** <span id="handle_response"/> defines the route to execute when the original response is matched by the given response matcher. If a matcher is omitted, all responses are intercepted. When multiple `handle_response` blocks are defined, the first matching block will be applied. Inside the block, all other [directives](/docs/caddyfile/directives) can be used.

Within `handle_response` routes, the following placeholders are available to pull information from the original response:

Expand Down
25 changes: 25 additions & 0 deletions src/docs/markdown/caddyfile/response-matchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,39 @@ These typically only appear as config inside of certain other directives, to mak

## Syntax

If a directive accepts response matchers, the usage is represented as either `[<response_matcher>]` or `[<inline_response_matcher>]` in the syntax documentation.

- The **<response_matcher>** token can be the name of a previously declared named response matcher. For example: `@name`.
- The **<inline_response_matcher>** token can be the response criteria itself, without requiring prior declaration. For example: `status 200`.

### Named

```caddy-d
@name {
status <code...>
header <field> [<value>]
}
```
If only one aspect of the response is relevant to the directive, you can put the name and the criteria on the same line:

```caddy-d
@name status <code...>
```

### Inline

```caddy-d
{
status <code...>
header <field> [<value>]
}
```
```caddy-d
status <code...>
```
```caddy-d
header <field> [<value>]
```

## Matchers

Expand Down
13 changes: 13 additions & 0 deletions src/old/resources/js/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ $(function() {
let text = item.innerText.replace(/</g,'&lt;').replace(/>/g,'&gt;');
$(item).html('<a href="/docs/caddyfile/matchers#syntax" style="color: inherit;" title="Matcher token">' + text + '</a>');
});
// Add links to [<matcher>] or named matcher tokens in code blocks.
// The matcher text includes <> characters which are parsed as HTML,
// so we must use text() to change the link text.
$('pre.chroma .s:contains("<response_matcher>")')
.add('pre.chroma .s:contains("<inline_response_matcher>")')
.map(function(k, /** @type { HTMLElement } */ item) {
const anchor = document.createElement("a");
anchor.href = "/docs/caddyfile/response-matchers#syntax";
anchor.style.color = "inherit";
anchor.title = "Response matcher token";
item.replaceWith(anchor);
anchor.appendChild(item);
});

// Wrap all tables in a div so we can apply overflow-x: scroll
$('table').wrap('<div class="table-wrapper"></div>');
Expand Down