From 336f78e78f5765c3bd0f4260f926ddde3d4c4379 Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:59:32 -0500 Subject: [PATCH 1/7] elaborate on `header` directive --- .../markdown/caddyfile/directives/encode.md | 2 +- .../markdown/caddyfile/directives/header.md | 61 +++++++++++++++++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/docs/markdown/caddyfile/directives/encode.md b/src/docs/markdown/caddyfile/directives/encode.md index 29d283f3..9c2a4473 100644 --- a/src/docs/markdown/caddyfile/directives/encode.md +++ b/src/docs/markdown/caddyfile/directives/encode.md @@ -31,7 +31,7 @@ encode [] { match { status - header [] + header } } ``` diff --git a/src/docs/markdown/caddyfile/directives/header.md b/src/docs/markdown/caddyfile/directives/header.md index 0ea09425..a7166164 100644 --- a/src/docs/markdown/caddyfile/directives/header.md +++ b/src/docs/markdown/caddyfile/directives/header.md @@ -37,6 +37,15 @@ header [] [[+|-|?|>] [|] []] { ? [defer] + + # a match condition + match [status | header ] + + # or a match block + match { + status + header + } } ``` @@ -44,13 +53,13 @@ header [] [[+|-|?|>] [|] []] { 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. Prefix with `-` to delete the field. The field may use prefix or suffix `*` wildcards to delete all matching fields. Prefix with `?` to set a default value for the field. The field is only written if it doesn't yet exist. - Prefix with `>` to set the field, and enable `defer`, as a shortcut. + Prefix with `>` to replace the contents of an existing header value using a regular expression. Implies `defer`, see below. - **<value>** is the header field value, when adding or setting a field. @@ -58,7 +67,13 @@ header [] [[+|-|?|>] [|] []] { - **<replace>** 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 to replace within the header value. + - When one or more `match` conditions are present. + +- **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. @@ -67,7 +82,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" @@ -119,6 +134,44 @@ 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 +``` + +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 (prefixed with `>`), the `` 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 From 992e39fd0a5a8e36714aa27b3089269ac6882319 Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:31:26 -0500 Subject: [PATCH 2/7] header value is not present if field is prefixed with `!` --- src/docs/markdown/caddyfile/directives/encode.md | 2 +- src/docs/markdown/caddyfile/directives/header.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docs/markdown/caddyfile/directives/encode.md b/src/docs/markdown/caddyfile/directives/encode.md index 9c2a4473..29d283f3 100644 --- a/src/docs/markdown/caddyfile/directives/encode.md +++ b/src/docs/markdown/caddyfile/directives/encode.md @@ -31,7 +31,7 @@ encode [] { match { status - header + header [] } } ``` diff --git a/src/docs/markdown/caddyfile/directives/header.md b/src/docs/markdown/caddyfile/directives/header.md index a7166164..3c99c31d 100644 --- a/src/docs/markdown/caddyfile/directives/header.md +++ b/src/docs/markdown/caddyfile/directives/header.md @@ -44,7 +44,7 @@ header [] [[+|-|?|>] [|] []] { # or a match block match { status - header + header [] } } ``` From 4de1370b7a8a16b5670cd1ab5dab8ab3ead8e3dc Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:46:17 -0500 Subject: [PATCH 3/7] replacement syntax --- src/docs/markdown/caddyfile/directives/header.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/docs/markdown/caddyfile/directives/header.md b/src/docs/markdown/caddyfile/directives/header.md index 3c99c31d..93e5cc4e 100644 --- a/src/docs/markdown/caddyfile/directives/header.md +++ b/src/docs/markdown/caddyfile/directives/header.md @@ -59,7 +59,7 @@ header [] [[+|-|?|>] [|] []] { Prefix with `?` to set a default value for the field. The field is only written if it doesn't yet exist. - Prefix with `>` to replace the contents of an existing header value using a regular expression. Implies `defer`, see below. + Prefix with `>` to set the field, and enable `defer`, as a shortcut. - **<value>** is the header field value, when adding or setting a field. @@ -70,7 +70,7 @@ header [] [[+|-|?|>] [|] []] { - **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 to replace within the header value. + - When using the `>` prefix on a set or replace operation. - When one or more `match` conditions are present. - **match** is an inline [response matcher](/docs/caddyfile/response-matchers). Header operations are applied only to responses that satisfy the specified conditions. @@ -162,7 +162,7 @@ Prevent overly-permissive CORS headers by replacing wildcard values with a speci header >Access-Control-Allow-Origin "\*" "allowed-partner.com" reverse_proxy upstream:443 ``` -**Note**: In replacement operations (prefixed with `>`), the `` value is interpreted as a regular expression. To match the `*` character, it must be escaped with a backslash as shown in the above example. +**Note**: In replacement operations, the `` 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 From 0a84fcf49aef6d2013497e798b51e25f06691e13 Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:48:07 -0500 Subject: [PATCH 4/7] no-cache directive has to have the hyphen --- src/docs/markdown/caddyfile/directives/header.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/markdown/caddyfile/directives/header.md b/src/docs/markdown/caddyfile/directives/header.md index 93e5cc4e..ec470627 100644 --- a/src/docs/markdown/caddyfile/directives/header.md +++ b/src/docs/markdown/caddyfile/directives/header.md @@ -175,7 +175,7 @@ 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 ``` From d90b27681f9a02e3fb0ab72f1c1f6f900980088a Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:54:44 -0500 Subject: [PATCH 5/7] link directives to response matchers documentation --- .../markdown/caddyfile/directives/encode.md | 5 +--- .../markdown/caddyfile/directives/header.md | 9 +------ .../caddyfile/directives/intercept.md | 12 +++------ .../markdown/caddyfile/response-matchers.md | 25 +++++++++++++++++++ src/old/resources/js/docs.js | 13 ++++++++++ 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/docs/markdown/caddyfile/directives/encode.md b/src/docs/markdown/caddyfile/directives/encode.md index 29d283f3..d5edbfbd 100644 --- a/src/docs/markdown/caddyfile/directives/encode.md +++ b/src/docs/markdown/caddyfile/directives/encode.md @@ -29,10 +29,7 @@ encode [] { minimum_length - match { - status - header [] - } + match } ``` diff --git a/src/docs/markdown/caddyfile/directives/header.md b/src/docs/markdown/caddyfile/directives/header.md index ec470627..7c19912e 100644 --- a/src/docs/markdown/caddyfile/directives/header.md +++ b/src/docs/markdown/caddyfile/directives/header.md @@ -38,14 +38,7 @@ header [] [[+|-|?|>] [|] []] { [defer] - # a match condition - match [status | header ] - - # or a match block - match { - status - header [] - } + match } ``` diff --git a/src/docs/markdown/caddyfile/directives/intercept.md b/src/docs/markdown/caddyfile/directives/intercept.md index f472bfc3..a7765f2d 100644 --- a/src/docs/markdown/caddyfile/directives/intercept.md +++ b/src/docs/markdown/caddyfile/directives/intercept.md @@ -18,10 +18,6 @@ window.$(function() { window.$('pre.chroma .nd:contains("@name")').first().slice(0, 3) .wrapAll('').parent() .html('@name') - window.$('pre.chroma .k:contains("replace_status")').first().next() - .html('[<matcher>]') - window.$('pre.chroma .k:contains("handle_response")').first().next() - .html('[<matcher>]') window.$('pre.chroma .k') .filter((i, el) => el.innerText === 'status') .html('status') @@ -49,19 +45,19 @@ intercept [] { header [] } - replace_status [] + replace_status [] - handle_response [] { + handle_response [] { } } ``` -- **@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** simply changes the status code of response when matched by the given matcher. -- **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** 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: diff --git a/src/docs/markdown/caddyfile/response-matchers.md b/src/docs/markdown/caddyfile/response-matchers.md index be9e11fd..da8625e0 100644 --- a/src/docs/markdown/caddyfile/response-matchers.md +++ b/src/docs/markdown/caddyfile/response-matchers.md @@ -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 [] or [] in the syntax documentation. + +- The **** token can be the name of a previously declared named response matcher. For example: `@name`. +- The **** token can be the response criteria itself, without requiring prior declaration. For example: `status 200`. + +### Named + ```caddy-d @name { status header [] } ``` +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 +``` +### Inline + +```caddy-d +{ + status + header [] +} +``` +```caddy-d +status +``` +```caddy-d +header [] +``` ## Matchers diff --git a/src/old/resources/js/docs.js b/src/old/resources/js/docs.js index 0e6a7d1d..7e7de3a4 100644 --- a/src/old/resources/js/docs.js +++ b/src/old/resources/js/docs.js @@ -55,6 +55,19 @@ $(function() { let text = item.innerText.replace(//g,'>'); $(item).html('' + text + ''); }); + // Add links to [] 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("")') + .add('pre.chroma .s:contains("")') + .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('
'); From 6013d7f7ed3b00877d0a66761df3e649aea47c55 Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:01:43 -0500 Subject: [PATCH 6/7] quote tokens --- src/docs/markdown/caddyfile/response-matchers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/markdown/caddyfile/response-matchers.md b/src/docs/markdown/caddyfile/response-matchers.md index da8625e0..d47d2bcd 100644 --- a/src/docs/markdown/caddyfile/response-matchers.md +++ b/src/docs/markdown/caddyfile/response-matchers.md @@ -35,7 +35,7 @@ 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 [] or [] in the syntax documentation. +If a directive accepts response matchers, the usage is represented as either `[]` or `[]` in the syntax documentation. - The **** token can be the name of a previously declared named response matcher. For example: `@name`. - The **** token can be the response criteria itself, without requiring prior declaration. For example: `status 200`. From c71a3d7831f606681143d608a446cd71e802020a Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:18:16 -0500 Subject: [PATCH 7/7] add match block example --- src/docs/markdown/caddyfile/directives/header.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/docs/markdown/caddyfile/directives/header.md b/src/docs/markdown/caddyfile/directives/header.md index 7c19912e..b1d10dc4 100644 --- a/src/docs/markdown/caddyfile/directives/header.md +++ b/src/docs/markdown/caddyfile/directives/header.md @@ -150,6 +150,19 @@ header { 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"