Commit 9ab583f8 authored by Geoff Simmons's avatar Geoff Simmons

Add docs and examples for rewrites.

Closes #1
parent dfebd8fa
......@@ -489,3 +489,398 @@ VCL.
See the [docs](/docs/custom-vcl.md) for conventions and restrictions
that apply to custom VCL, and for links to more information about VCL.
## ``spec.rewrites``
The ``rewrites`` element is optional, and if present contains a
non-empty array of objects specifying rewrites for URL paths or HTTP
headers. Headers may also be specified for deletion. Rewrites or
deletes may be unconditional, or may be only executed when certain
conditions are met, such as regular expression or string equality
matches. For regex matches, contents of the rewritten string may
result in part from backreferences to captured substrings in the
matching portion of the string.
See the [examples folder](/examples/rewrite) for working examples of
rewrites.
Elements of the ``rewrites`` array may have these fields, of which
``target`` and ``method`` are required:
* ``target`` (required): the object to which the rewritten string is
assigned, or the object that is deleted. One of:
* ``req.url``: the client request URL path (not permitted for
deletes)
* ``bereq.url``: the backend request URL path (not permitted for
deletes)
* ``req.http.$HEADER``: the client request header ``$HEADER``. For
example ``req.http.Cookie`` for the Cookie request header
* ``resp.http.$HEADER``: the client response header ``$HEADER``
* ``bereq.http.$HEADER``: the backend request header ``$HEADER``
* ``beresp.http.$HEADER``: the backend response header ``$HEADER``
If the ``target`` specifies a header that is not present in the
request or response, then the header is added with the new value.
* ``source``: the object against which matching or equality
comparisons are executed, and from which strings may be extracted
(for example as backreferences after regex matches). ``source`` has
the same legal values as ``target``; that is, it may be the client
or backend request URL path, or a client or backend request or
response header, using the same notation shown above.
* If ``source`` is left out, then it is the same as the
``target``. In that case, the ``target`` object is edited in
place.
* ``target`` and ``source`` MUST specify either both client or
both backend context. In other words, both of them must begin
with either ``re`` or ``be``.
* ``rules``: an non-empty array of rules specifying conditions under
which a rewrite is executed, and strings used for the rewrites. If
the ``rules`` array is left out, then the rewrite is
unconditional. Each rule is an object with these two fields:
* ``value``: a string or pattern against which the ``source`` is
compared. If the comparison succeeds for a ``value`` in the
``rules`` array, then that element of the array represents the
rule to be applied, and the corresponding ``rewrite`` field is
the string to be used for the rewrite. If ``value`` is a regular
expression, then it has the syntax and semantics of
[RE2](https://github.com/google/re2/wiki/Syntax). Each pattern
or string in the ``value`` field MUST be unique in a ``rules``
array; in other words, the same ``value`` MAY NOT appear more
than once in ``rules``.
* ``rewrite``: a string to be used for the rewrite if the
corresponding ``value`` compares successfully with the
``source``. The value of ``rewrite`` may be a fixed string, or
it may contain backreferences to captured substrings after a
regex match, depending on the choices for ``method`` and
``compare``, as described below.
* If there is exactly one element of ``rules``, then the ``value``
field may be left out for that element. In that case, the
rewrite is applied unconditionally, and the value of the
``rewrite`` field is the string to be used. ``value`` is
required when the ``method`` field is ``sub``, ``suball`` or
``rewrite`` (see below).
* The ``rewrite`` field is required for each element of ``rules``,
unless the ``method`` field is set to ``delete`` (see below).
For ``delete``, the ``rewrite`` field is ignored and may be left
out.
* ``method`` (required): an enum specifying the process by which the
``target`` is modified. One of:
* ``replace``: a new string is assigned to the ``target``. Any
previous value of the ``target`` is overwritten.
* ``sub`` (only permitted with a regular expression match):
``target`` is assigned the result of substituting the first
matching substring of ``source`` with the value of ``rewrite``
for the matching element of the ``rules`` array. That is, if
the match succeeds for a ``value`` in ``rules``, then a
substitution is executed using the corresponding ``rewrite``.
The ``rewrite`` string may contain backreferences ``\1`` to
``\9``, referring to captured substrings in the match.
* ``suball`` (only regex matches): like ``sub``, but the
substitution is executed for each non-overlapping matching
substring in ``source``. As with ``sub``, the value of the
``rewrite`` field may contain backreferences.
* ``rewrite`` (only regex matches): for the matching element of
``rules`` (i.e. the element for which ``source`` matches
successfully with ``value``), assign the value of the
``rewrite`` field to the ``target``. The ``rewrite`` field may
contain backreferences to captured substrings. Non-matched and
non-captured portions of the ``source`` string are ignored.
* ``append``: concatenate a string after another string and write
the result to the ``target``. The rules for determining the
strings to be concatenated are described below.
* ``prepend``: concatenate a string before another string and
write the result to the ``target``, according to the rules
described below.
* ``delete``: delete the header specified in the ``target``. For
``delete``, the ``target`` MAY NOT be ``req.url`` or
``bereq.url`` (you cannot delete a URL). If there is a ``rules``
array, then the ``rewrite`` fields are ignored, but ``value``
fields can be used to specify patterns or strings to be matched
for conditional deletes.
* If ``method`` is any of ``sub``, ``suball`` or ``rewrite``, then:
* the ``rules`` array must be specified
* a ``value`` field is required for each element of ``rules``,
* each ``value`` is interpreted as a regular expression
* the value of ``compare`` must be ``match`` (see below)
This requirement can be summarized as: if the ``method``
permits backreferences for the rewrite, then regex matching
MUST be applied, and patterns for the match MUST be specified.
* If there is exactly one element of ``rules`` and its ``value``
field is left out, then the ``rewrite`` field of the rule is a
fixed string to be used unconditionally in the rewrite:
* For ``replace``, the string is written to the ``target``.
* For ``append``, the string is concatenated after the
``source``, and the result is written to the ``target``.
* For ``prepend``, the string is concatenated before the
``source``, and the result is written to the target.
* ``sub``, ``suball``, ``rewrite`` and ``delete`` are not
permitted (these require a ``value`` for each rule).
* If there is no ``rules`` array, then the rewrite is applied
unconditionally to the ``target`` and ``source``:
* For ``replace``, the value of the ``source`` is written to
the ``target`` (for example to copy one header to another).
* For ``delete``, the ``target`` is deleted (and ``source`` is
ignored).
* For ``append``, the ``source`` is concatenated after the
``target``, and the result is written to the ``target``.
* For ``prepend``, the ``source`` is concatenated before the
``target``.
* ``sub``, ``suball`` and ``rewrite`` are not permitted (these
require a ``rules`` array).
* ``compare``: an enum specifying the comparison operation used to
compare the ``source`` with the ``value`` fields in the ``rules``.
One of:
* ``match`` (default): regular expression match. The match has the
semantics of [RE2](https://github.com/google/re2/), and the
``value`` fields in the ``rules`` specify regular expressions.
* ``equal``: string equality. The ``value`` fields specify fixed
strings, and the corresponding rule applies if the ``source`` is
exactly equal to ``value``. Characters such as wildcards or
regex metacharacters are matched literally, and have no special
meaning.
* ``prefix``: fixed prefix match. The ``value`` fields specify
fixed strings, and the corresponding rule applies if the
``source`` has a prefix that is exactly equal to ``value``.
* ``select``: when ``compare`` is ``match`` or ``prefix`` (regex or
prefix match), this enum determines which rule is applied if more
than one of them compares successfully, or imposes restrictions
on multiple matches.
For example, if ``compare`` is ``prefix`` and the ``rules``
include ``/foo`` and ``/foo/bar`` in the ``value`` fields, then
the string ``/foo/bar`` and ``/foo/bar/baz`` matches both of
them. The ``select`` field specifies whether this is permitted,
and if so which rewrite rule applies.
Legal values of ``select`` depend on whether ``compare`` is set to
``match`` or ``prefix``. For both of them, ``select`` may be one
of:
* ``unique`` (default): only unique matches are permitted. If more
than one rule compares successfully, then VCL failure is invoked
(see below).
* ``first``: if more than one rule compares successfully, then
apply the rewrite for the first succeeding rule, in the order of
the ``rules`` array.
* ``last``: if more than one rule compares successfully, then
apply the rewrite for the last succeeding rule in the ``rules``
array.
If ``compare`` is set to ``prefix``, then ``select`` may also be
one of:
* ``exact``: if more than one rule compares successfully, but the
``value`` for one of the rules is exactly equal to the
``source``, then apply the rewrite for that rule. If no rule
matches exactly, then VCL failure is invoked (see below).
For example, if:
* ``compare`` is ``prefix``
* there are two rules, with ``/foo`` and ``/foo/bar`` in the
``value`` fields
* the ``source`` evaluates to ``/foo/bar``
... then the rule for ``/foo/bar`` is the exact match, and the
rewrite specified for that rule applies. But no rules match
exactly if ``source`` is ``/foo/bar/baz`` (although both of
the rules specify a prefix for that string).
* ``longest``: if more than one rule compares successfully, then
apply the rewrite for the successful rule with the longest
string in ``value``.
* ``shortest``: if more than one rule compares successfully, then
apply the rewrite for the successful rule with the shortest
string in ``value``.
If the conditions required by ``unique`` or ``exact`` are not met,
then
[VCL failure](https://varnish-cache.org/docs/6.1/users-guide/vcl-built-in-subs.html#common-return-keywords)
is invoked after the comparison attempt. This means in most cases
that a synthetic response with status 503 and the reason "VCL
failed" is returned for the request.
* ``match-flags`` is an object with configuration to control comparison
operations. If ``match-flags`` is absent, then comparisons are executed
with default options.
Only the ``case-sensitive`` field may be set if ``compare`` is
``equal`` or ``prefix``; all of the other fields are permitted
only if ``compare`` is ``match``. In other words, case
insensitivity can be specified for all comparison operations, but
the other fields apply only to regex matching. The fields are:
* ``case-sensitive`` (default ``true``): if ``false``, then regex
and fixed-string comparisons are case insensitive.
* ``anchor`` (default ``none``): sets anchoring at start-of-string
or end-of-string for every pattern in the ``rules`` array;
equivalent to using the ``^`` and ``$`` for start- and
end-of-string in the notation for each pattern. Possible values
are:
* ``start``: each pattern is anchored at the start
* ``both``: each pattern is anchored at both start and end.
* ``none`` (default): no implicit anchoring (but ``^`` and/or
``$`` may be used in individual patterns)
* ``literal`` (default ``false``): if ``true``, then the strings
in the ``value`` fields of the ``rules`` are matched literally,
with no special meaning for regex metacharacters.
* ``never-capture`` (default ``false``): if ``true``, then
substring capturing is not executed for regex matches. Consider
setting ``never-capture`` to ``true`` if your patterns have
round parentheses ``()`` for grouping only, and backreferences
are not used in rewrite strings, since regex matches are faster
without the captures.
* ``utf8`` (default ``false``): if ``true``, then characters in
each pattern match UTF8 code points; otherwise, the patterns and
the strings to be matched are interpreted as Latin-1
(ISO-8859-1). Note that characters in header values and URL
paths almost always fall in the ASCII range, so the default is
usually sufficient.
* ``longest-match`` (default ``false``): if ``true``, then the
matcher searches for the longest possible match where
alternatives are possible. For example with the pattern
``a(b|bb)`` and the string ``abb``, ``abb`` matches when
``longest-match`` is ``true``, and backref 1 is
``bb``. Otherwise, ``ab`` matches, and backref 1 is ``b``.
* ``posix-syntax`` (default ``false``): if ``true``, then patterns
are restricted to POSIX (egrep) syntax. Otherwise, the full
range of [RE2](https://github.com/google/re2/wiki/Syntax) is
available. The next two flags (``perl-classes`` and
``word-boundary``) are only consulted when ``posix-syntax`` is
``true``.
* ``perl-classes`` (default ``false``): if ``true`` and
``posix-syntax`` is also ``true``, then the perl character
classes ``\d``, ``\s``, ``\w``, ``\D``, ``\S`` and ``\W`` are
permitted in a pattern. When ``posix-syntax`` is ``false``, the
perl classes are always permitted.
* ``word-boundary`` (default ``false``): if ``true`` and
``posix-syntax`` is also ``true``, then the perl assertions
``\b`` and ``\B`` (word boundary and not a word boundary) are
permitted in a pattern. When ``posix-syntax`` is ``false``, the
word boundary assertions are always permitted.
* ``max-mem`` (integer, default 8MB): an upper bound (in bytes)
for the size of the compiled pattern. If ``max-mem`` is too
small, the matcher may fall back to less efficient algorithms,
or the pattern may fail to compile.
This field very rarely needs to be set; the default is the RE2
default, and is sufficient for typical patterns. Increasing
``max-mem`` is usually only necessary if VCL loads fail due to
failed regex compiles, and the error message (shown in Event
notifications and the controller log) indicates that the
pattern is too large.
* ``vcl-sub`` is an enum indicating the
[VCL subroutine](https://varnish-cache.org/docs/6.1/reference/states.html)
in which the rewrite is executed; that is, the phase of request
processing at which the rewrite is performed.
If ``vcl-sub`` is left out, then the VCL subroutine for the
rewrite is inferred from the values of ``target`` and ``source``:
* If both of ``target`` and ``source`` are in ``req.*``
(``req.url`` and/or ``req.http.$HEADER``), then the rewrite is
executed in ``vcl_recv``; that is, just after client request
headers are received.
* If both of ``target`` and ``source`` are in ``bereq.*``
(``bereq.url`` and/or ``bereq.http.$HEADER``), then the rewrite
is executed in ``vcl_backend_fetch``; that is, just before a
backend request is sent.
* If at least one of ``source`` or ``target`` is in
``resp.http.*``, then the rewrite is executed in
``vcl_deliver``; that is, just before the client response is
sent.
* If at least one of ``source`` or ``target`` is in
``beresp.http.*``, then the rewrite is executed in
``vcl_backend_response``; that is, just after backend response
headers are received.
``vcl-sub`` may be set explicitly with any of the following
values, corresponding to the VCL subroutine with the ``vcl_``
prefix (for example ``vcl_miss`` for ``vcl-sub:miss``):
* ``recv``
* ``pipe``
* ``pass``
* ``hash``
* ``purge``
* ``miss``
* ``hit``
* ``deliver``
* ``synth``
* ``backend_fetch``
* ``backend_response``
* ``backend_error``
See the
[VCL](https://varnish-cache.org/docs/6.1/reference/vcl.html)
[docs](https://varnish-cache.org/docs/6.1/reference/states.html)
for details.
If more than one rewrite in the ``rewrites`` array specifies the
same VCL subroutine, then they are executed in that subroutine in
the order in which they appear in the array.
......@@ -23,6 +23,9 @@ requirements.
* [Access control lists](/examples/acl) -- whitelisting or
blacklisting requests by IP address
* Specifying [rewrite rules](/examples/rewrite) for request headers,
response headers, and URL paths.
* The [BackendConfig](/examples/backend-config) Custom Resource, to
configure properties such as timeouts, health probes and
load-balancing for Services to which requests are routed according
......
# Sample rewrite rules for headers and URL paths
The sample manifest in this folder configures rewrite operations for
HTTP headers and URL paths, to be executed by a Varnish Service
implementing Ingress. The specifications take the form of objects in
the ``rewrites`` array of a VarnishConfig resource.
See the [docs](/docs/ref-varnish-cfg.md) for the technical reference
for specifying rewrites.
The examples apply to the Ingress and Services defined in the
["cafe" example](/examples/hello).
Apply the rewrite configuration with:
```
$ kubectl apply -f rewrite.yaml
```
The rewrites can then be verified with the sample commands shown in
the following.
## Rewriting URL prefixes
The first two examples in the sample configuration demonstrate different
ways to rewrite the prefix of a URL path. Since the
[Ingress](/examples/hello/cafe-ingress.yaml) defined in the
["cafe" example](/examples/hello) specifies routing rules based on the
URL prefix -- ``/coffee/*`` requests are forwarded to the coffee-svc,
and ``/tea/*`` requests to the tea-svc -- this is a way to allow
requests with additional URL prefixes to be forwarded to the two Services.
The first example defines alternative prefixes for the coffee-svc:
```
- target: req.url
compare: match
method: sub
rules:
- value: /espresso(/|$)
rewrite: /coffee\1
- value: /capuccino(/|$)
rewrite: /coffee\1
- value: /latte(/|$)
rewrite: /coffee\1
- value: /macchiato(/|$)
rewrite: /coffee\1
- value: /ristretto(/|$)
rewrite: /coffee\1
- value: /americano(/|$)
rewrite: /coffee\1
match-flags:
anchor: start
```
The overall purpose is to rewrite URLs with matching prefixes so that
they begin with ``/coffee``, and hence match the Ingress rule.
The ``target`` is ``req.url``, or the client request URL path. Since
``source`` is left out, it is implicitly the same as the ``target``,
so this configuration specifies an in-place rewrite of the URL.
Since the ``target`` and ``source`` are ``req.url``, the rewrite is
executed in the VCL subroutine ``vcl_recv``; that is, just after the
client request header (including the URL path) is received.
The ``compare:match`` setting means that regular expression matching
is executed for this rewrite; since ``match`` is the default value,
the ``compare`` field could have been left out. When ``compare:match``
is specfied, the ``source`` object (in this case ``req.url``) is
matched against the regexen that appear in the ``value`` fields of the
``rules`` array. For rewrites, regexen have the syntax and semantics
of [RE2](https://github.com/google/re2/wiki/Syntax).
The ``anchor:start`` match flag means that the regexen are anchored at
start-of-string, as if each of them begins with a ``^``. This
convenience ensures that anchoring is maintained if the patterns are
changed; you can't make the mistake of adding a new pattern and
forgetting the ``^``.
The ``select`` field is left out, and hence has the default value
``unique``, meaning that if any URL matches one of the patterns, it
must match exactly one of them (which in fact is the only possibility
with these patterns).
The ``method:sub`` setting means that, if the URL matches one of the
patterns, then the matching portion is substituted with the string in
the ``rewrite`` field that corresponds to the match. In this example,
the rewrite strings happen to be all the same, but of course they
could each be different. With the ``sub`` method (as also with
``suball`` and ``rewrite``), backreferences such as ``\1`` are
replaced with the corresponding capturing subgroup from the matching
pattern.
In the example, the end of the matching prefix must be either ``/`` or
end-of-string (``$``). This means that, for example, the URL
``/espresso`` (without the trailing slash) is rewritten as ``/coffee``
and ``/espresso/doppio`` as ``/coffee/doppio``; but a URL such as
``/espresso-grande`` does not match any pattern, and is not rewritten.
To verify the rewrite, we send requests with the alternative URL
prefixes, and check the response to ensure that it came from the
coffee-svc Service. As with other examples, we use curl with the
``-x`` (or ``--proxy``) option set to ``$IP:$PORT``, where ``$IP`` is
the public address of the cluster, and ``$PORT`` is the port at which
it receives requests that are directed to the Ingress:
```
# URL path /espresso (without the trailing slash) is rewritten as /coffee.
$ curl -x $IP:$PORT -v http://cafe.example.com/espresso
[...]
> GET http://cafe.example.com/espresso HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: coffee-6c47b9cb9c-q7xrl
[...]
URI: /coffee
[...]
# /capuccino/ (with the trailing slash) is rewritten as /coffee/.
$ curl -x $IP:$PORT -v http://cafe.example.com/capuccino/
[...]
> GET http://cafe.example.com/capuccino/ HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: coffee-6c47b9cb9c-q7xrl
[...]
URI: /coffee/
[...]
# /latte/grande is rewritten as /coffee/grande.
$ curl -x $IP:$PORT -v http://cafe.example.com/latte/grande/
[...]
> GET http://cafe.example.com/latte/grande/ HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: coffee-6c47b9cb9c-q7xrl
[...]
URI: /coffee/grande/
[...]
```
The next example performs a similar function to rewrite URL prefixes
for the tea-svc, but there are some differences from the previous
example worth considering in detail:
```
- target: req.url
compare: prefix
rules:
- value: /camomille
rewrite: /tea
- value: /earl-grey
rewrite: /tea
- value: /chai
rewrite: /tea
- value: /green
rewrite: /tea
- value: /hibiscus
rewrite: /tea
- value: /oolong
rewrite: /tea
method: sub
```
As with the previous example, the ``target`` and ``source`` is
``req.url``, so this is another in-place rewrite of the URL. The
``method`` is ``sub``, and this configuration specifies replacing the
matching portion of the URL with the string in the corresponding
``rewrite`` field.
``compare`` in this case is ``prefix``, meaning that the match is
against a fixed string prefix. That is, a URL matches if it has a
prefix that is one of the strings specified as a ``value`` in the
``rules``. With ``compare:prefix``, the strings in the ``value``
fields are not patterns; any regular expression metacharacter that may
appear in a ``value`` is matched literally, and has no special
meaning.
Verification with curl:
```
# /camomille (without the trailing slash) is rewritten as /tea.
$ curl -x $IP:$PORT -v http://cafe.example.com/camomille
[...]
> GET http://cafe.example.com/camomille HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: tea-58d4697745-6vcz9
[...]
URI: /tea
[...]
# /earl-grey/ (with the trailing slash) is rewritten as /tea/.
$ curl -x $IP:$PORT -v http://cafe.example.com/earl-grey/
[...]
> GET http://cafe.example.com/earl-grey/ HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: tea-58d4697745-9vl28
[...]
URI: /tea/
[...]
# /chai/link is rewritten as /tea/link.
$ curl -x $IP:$PORT -v http://cafe.example.com/chai/link
[...]
> GET http://cafe.example.com/chai/link HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: tea-58d4697745-5fgwr
[...]
URI: /tea/link
[...]
# /chain/link is rewritten as /tean/link, which may not be desired.
$ curl -x $IP:$PORT -v http://cafe.example.com/chain/link
[...]
> GET http://cafe.example.com/chain/link HTTP/1.1
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: tea-58d4697745-5fgwr
[...]
URI: /tean/link
[...]
```
The second configuration, which uses ``compare:prefix`` for
alternative ``/tea`` prefixes, is easier to read and write than the
first example with regular expressions. Depending on the complexity of
the match and the strings to be matched, prefix matches may run faster
than regex matches (but that depends on many factors).
But the last curl example shows that the ``prefix`` match may not
fulfill all requirements of the use case. The ``prefix`` match can
handle the cases with and without the trailing slash after the URL
prefix, but it cannot prevent a URL ``/chain/link`` from being
rewritten as ``/tean/link``.
Another way to use the ``prefix`` match to avoid that result would be
to specify the trailing slash in the ``value`` fields. In that case,
the rewrite cannot handle the case with no trailing slash, but if your
site does not use any such URLs, then the rewrite would be suitable.
## Fixed string equality and rewrites
The next example in the sample manifest rewrites the ``Host`` header
for certain values, so that the request can be handled by the Ingress
(which requires the Host ``cafe.example.com``):
```
- target: req.http.Host
compare: equal
rules:
- value: my-cafe.com
rewrite: cafe.example.com
- value: my-example.com
rewrite: cafe.example.com
- value: ingress.example.com
rewrite: cafe.example.com
- value: varnish.example.com
rewrite: cafe.example.com
- value: atomic-cafe.com
rewrite: cafe.example.com
method: replace
```
As with the previous examples, the ``source`` is implicitly the same
as the ``target``, so this is an in-place rewrite of
``req.http.Host``, or the client request header ``Host``.
``compare:equal`` means that the Host header is matched for fixed
string equality with the strings in the ``value`` fields of the
``rules``. As with the ``prefix`` match, all characters in a ``value``
are matched literally, with no special meanings. There is no need to
specify an ``anchor``; the string matches from start to end, or not at
all.
The effect is that any of the given strings for the Host header is
rewritten to ``cafe.example.com``, which happens to be the only Host
specified in the example Ingress. We verify with curl by checking that
requests with one of these Host values is forwarded to a Service, but
for other values of Host we get the 404 response:
```
# For Host values in the list, we get the coffee-svc or tea-svc.
$ curl -x $IP:$PORT -v http://my-cafe.com/coffee
[...]
> GET http://my-cafe.com/coffee HTTP/1.1
> Host: my-cafe.com
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: coffee-6c47b9cb9c-q7xrl
[...]
$ curl -x $IP:$PORT -v http://my-example.com/tea
[...]
> GET http://my-example.com/tea HTTP/1.1
> Host: my-example.com
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
Server name: tea-58d4697745-6vcz9
[...]
# Unknown Host values get the 404 response.
$ curl -x $IP:$PORT -v http://ricks.cafe.americain.com/coffee
[...]
> GET http://ricks.cafe.americain.com/coffee HTTP/1.1
> Host: ricks.cafe.americain.com
[...]
>
< HTTP/1.1 404 Not Found
[...]
```
## Extracting a Cookie value into a header
The next example demonstrates a way to extract the value of a cookie
into another header:
```
- target: resp.http.Session-Token
source: req.http.Cookie
rules:
- value: \bmysession\s*=\s*([^,;[:space:]]+)
rewrite: \1
method: rewrite
```
In this case, the ``source`` differs from the ``target``. Matches are
executed against the source object ``req.http.Cookie``, the client request
header Cookie. If the match succeeds, a string is extracted from
Cookie and written to the target object ``resp.http.Session-Token``, the
client response header ``Session-Token``.
The ``compare`` field has the default value ``match``, and the
``method`` is ``rewrite``, meaning that the string in the ``rewrite``
field is written to the target, using the backreference extracted from
the pattern in ``value``, and ignoring non-matched portions of the
``source``.
The capturing pattern that forms backref 1 expresses the cookie value
as a string of any characters that are none of comma, semicolon or
whitespace. If there are narrower restrictions on the lexical form of
your cookie values (say, all hex digits, or characters from a base64
encoding), you can use a narrower definition in the pattern.
Verification with curl:
```
$ curl -x $IP:$PORT -v -H 'Cookie: foo=bar; mysession=4711; baz=quux' http://cafe.example.com/coffee
[...]
> GET http://cafe.example.com/coffee HTTP/1.1
> Host: cafe.example.com
[...]
> Cookie: foo=bar; mysession=4711; baz=quux
>
< HTTP/1.1 200 OK
[...]
< Session-Token: 4711
[...]
$ curl -x $IP:$PORT -v -H 'Cookie: foo=bar; mysession=bazquux' http://cafe.example.com/coffee
[...]
> GET http://cafe.example.com/coffee HTTP/1.1
> Host: cafe.example.com
[...]
> Cookie: foo=bar; mysession=bazquux
>
< HTTP/1.1 200 OK
[...]
< Session-Token: bazquux
[...]
```
## Setting the cache disposition in the X-Cache header
The next sequence of rewrites implements a common use case for
Varnish: set the header X-Cache in both the client request and
response to one of the values "HIT", "MISS" or "PASS", to expose the
disposition of the request with respect to the cache. These examples
make use of the ``vcl-sub`` field to control execution of the rewrites
in specific VCL subroutines:
```
- target: req.http.X-Cache
vcl-sub: hit
rules:
- rewrite: HIT
method: replace
- target: req.http.X-Cache
vcl-sub: miss
rules:
- rewrite: MISS
method: replace
- target: req.http.X-Cache
vcl-sub: pass
rules:
- rewrite: PASS
method: replace
- target: resp.http.X-Cache
source: req.http.X-Cache
method: replace
```
In the first three of these, the ``vcl-sub`` field specifies execution
of the rewrite in the subroutines ``vcl_hit``, ``vcl_miss`` or
``vcl_pass``, so as to set the request header to the proper
value. Each of them specifies ``method:replace``, with exactly one
element of the ``rules`` array, and that element has only the
``rewrite`` field. That means that the string in ``rewrite`` is
written unconditionally to the ``target`` object (the client request
header).
The fourth rewrite specifies ``method:replace`` with no rules, which
means that the value of the ``source`` is unconditionally copied to
the ``target``. This has the effect of copying the value from the
request header to the response header. (If you don't want to expose
X-Cache in responses, then leave out the fourth rewrite stanza).
The rewrite can be verified with curl by checking the response header:
```
$ curl -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< X-Cache: MISS
[...]
# By the default caching rules, a request is set to pass if there is
# a Cookie header.
$ curl -H 'Cookie: foo=bar' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Cookie: foo=bar
>
< HTTP/1.1 200 OK
[...]
< X-Cache: PASS
[...]
```
## Rewriting the backend request URL
The next example is another in-place rewrite of a URL, in this case
the URL path in the backend request (``bereq.url``):
```
- target: bereq.url
rules:
- value: ^/coffee/([^/]+)/([^/]+)(.*)
rewrite: /coffee/\2/\1\3
method: rewrite
```
The effect is that, if the URL begins with ``/coffee/`` and has second
and third backslash-separated components, then those components are
swapped in the backend request.
Since the ``vcl-sub`` field is not specified, the rewrite is executed
in the VCL subroutine ``vcl_backend_fetch`` (just before the backend
request is sent), since the ``target`` and ``source`` are both
``bereq.url``. So the rewrite is executed in backend context, after
Ingress rules are evaluated, which happens in client context based on
the incoming request. Remember that if there is a cache hit, then
there is no backend request.
This rewrite can be verified with curl by checking the URI reflected
back in the response body, which shows the path as received by the
backend application:
```
$ curl -x $IP:$PORT -v http://cafe.example.com/coffee/foo/bar
[...]
> GET http://cafe.example.com/coffee/foo/bar HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
URI: /coffee/bar/foo
[...]
$ curl -x $IP:$PORT -v http://cafe.example.com/coffee/baz/quux
[...]
> GET http://cafe.example.com/coffee/baz/quux HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
<
[...]
URI: /coffee/quux/baz
[...]
```
## Deleting headers
The next example uses ``method:delete`` to specify a rewrite that
unconditionally deletes ``resp.http.Server``, the client response
header Server:
```
- target: resp.http.Server
method: delete
```
The rewrite can be verified with a client like curl by observing that
the Server response header, which is ordinarily forwarded from the
backend application, is never present in the response from Varnish.
The following rewrite specifies that the Via client response header is
deleted if the client request header Delete-Via has one of the given
values:
```
- target: resp.http.Via
method: delete
source: req.http.Delete-Via
compare: equal
rules:
- value: "true"
- value: "yes"
- value: "on"
- value: "1"
match-flags:
case-sensitive: false
```
In this case, the ``source`` object is matched for case-insensitive
equality with the strings that appear in the ``value`` fields. None of
the objects in the ``rules`` array has a ``rewrite`` field, since
rewrite strings are not relevant for deletion.
Verification:
```
$ curl -x $IP:$PORT -v http://cafe.example.com/coffee
[...]
> GET http://cafe.example.com/coffee HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Via: 1.1 varnish (Varnish/6.1)
[...]
# With an appropriate value for the Delete-Via request header, the Via
# header does not appear in the response.
$ curl -H 'Delete-Via: TRUE' -x $IP:$PORT -v http://cafe.example.com/coffee
[...]
> GET http://cafe.example.com/coffee HTTP/1.1
> Host: cafe.example.com
[...]
> Delete-Via: TRUE
>
< HTTP/1.1 200 OK
[...]
```
``method:delete`` may only be used with a header as the ``target``,
never with ``req.url`` or ``bereq.url`` -- you can't delete the URL.
## Rewriting a header from another header, and from a fixed string
This example shows the general form for copying one header to another:
specify the headers with ``source`` and ``target``, and set ``method``
to ``replace``:
```
- target: resp.http.Replace-Hdr-Target
source: req.http.Replace-Hdr-Src
method: replace
```
This unconditionally copies the value of the client request header
Replace-Hdr-Src to the client response header Replace-Hdr-Target:
```
$ curl -x $IP:$PORT -v -H 'Replace-Hdr-Src: the replacements' http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Replace-Hdr-Src: the replacements
>
< HTTP/1.1 200 OK
[...]
< Replace-Hdr-Target: the replacements
[...]
```
To unconditionally set the value of a header to a fixed string, use
``method:replace`` and one element in the ``rules`` array. The one
rule has the ``rewrite`` field set to the string, and no ``value``
field:
```
- target: resp.http.Replace-String-Target
rules:
- rewrite: ReplaceString
method: replace
```
This sets the client response header Replace-String-Target to the
string "ReplaceString":
```
$ curl -x $IP:$PORT -v http://cafe.example.com/coffee
[...]
> GET http://cafe.example.com/coffee HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Replace-String-Target: ReplaceString
[...]
```
## Appending and prepending strings
The next group of examples illustrates the use of ``method:append``
and ``method:prepend`` to concatenate strings. In this example, the
fixed string "AppendString" is unconditionally appended to the value
of the ``source`` (the client request header Append-String-Src), and
the result is written to the ``target`` (the client response header
Append-String-Target):
```
- target: resp.http.Append-String-Target
source: req.http.Append-String-Src
rules:
- rewrite: AppendString
method: append
```
Since the rule has no ``value``, the string is appended
unconditionally, even if there is no request header
Append-String-Src. The result in that case is that just the string
("AppendString") is written to the ``target`` (the response header):
```
# Append the string from the rewrite specification to the request header.
$ curl -H 'Append-String-Src: foobar' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Append-String-Src: foobar
>
< HTTP/1.1 200 OK
[...]
< Append-String-Target: foobarAppendString
[...]
# If the request header does not exist, just write the string to the response
# header.
$ curl -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Append-String-Target: AppendString
[...]
```
To append the string conditionally (for example, only if the request
header exists), set a value for the ``value`` field; then the append
is only executed if the ``source`` passes a comparison with the
``value``. When ``compare`` has the default value ``match`` for a
regex match, and ``value`` is set to the pattern ``.`` for "match any
character", the append is only executed if the request header exists
and is non-empty:
```
- target: resp.http.Append-Rule-Target
source: req.http.Append-Rule-Src
rules:
- value: .
rewrite: AppendString
method: append
```
Verification:
```
$ curl -H 'Append-Rule-Src: bazquux' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Append-Rule-Src: bazquux
>
< HTTP/1.1 200 OK
[...]
< Append-Rule-Target: bazquuxAppendString
[...]
```
To append the value of a header ``source`` to another header
``target``, specify the ``source`` and ``target`` with no rules:
```
- target: req.http.Append-Hdr-Target
source: req.http.Append-Hdr-Src
method: append
```
This example has only request headers as the source and target, so we need
to verify its effect by reading the Varnish log (since rewritten request
headers cannot be seen in the curl response):
```
# Send the curl request
$ curl -H 'Append-Hdr-Target: foo' -H 'Append-Hdr-Src: bar' -x $IP:$PORT -v http://cafe.example.com/tea
# Check the result with varnishlog
* << Request >> 101540
- Begin req 101539 rxreq
[...]
- ReqMethod GET
- ReqURL /tea
- ReqProtocol HTTP/1.1
[...]
- ReqHeader Append-Hdr-Target: foo
- ReqHeader Append-Hdr-Src: bar
- ReqHeader Host: cafe.example.com
[...]
- ReqUnset Append-Hdr-Target: foo
- ReqHeader Append-Hdr-Target: foobar
[...]
```
With ``method:prepend``, the order of concatenation is reversed -- a
string is prepended before the value of the target. The means for
specifying the string to prepend are the same as shown above for
append.
To prepend a fixed string -- here "PrependString" is unconditionally
prepended to the request header Prepend-String-Src:
```
- target: resp.http.Prepend-String-Target
source: req.http.Prepend-String-Src
rules:
- rewrite: PrependString
method: prepend
```
To conditionally prepend the string (only if Prepend-Rule-Src exists
and is non-empty):
```
- target: resp.http.Prepend-String-Target
source: req.http.Prepend-String-Src
rules:
- rewrite: PrependString
method: prepend
```
To prepend a header to another header:
```
- target: req.http.Prepend-Hdr-Target
source: req.http.Prepend-Hdr-Src
method: prepend
```
Verification:
```
# Prepend "PrependString" to the value of the request header
# Prepend-String-Src, and write the result to the response header
# Prepend-String-Target:
$ curl -H 'Prepend-String-Src: foobar' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Prepend-String-Src: foobar
>
< HTTP/1.1 200 OK
[...]
< Prepend-String-Target: PrependStringfoobar
[...]
# If the request header Prepend-Rule-Src exists, prepend "PrependString" to
# its value, and write the result to the response header Prepend-Rule-Target:
$ curl -H 'Prepend-Rule-Src: bazquux' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Prepend-Rule-Src: bazquux
>
< HTTP/1.1 200 OK
[...]
< Prepend-Rule-Target: PrependStringbazquux
[...]
# Prepend the value of the request header Prepend-Hdr-Src to the request
# header Prepend-Hdr-Target:
$ curl -H 'Prepend-Hdr-Target: foo' -H 'Prepend-Hdr-Src: bar' -x $IP:$PORT -v http://cafe.example.com/tea
# Check the result in the Varnish log:
* << Request >> 5460
- Begin req 5459 rxreq
[...]
- ReqMethod GET
- ReqURL /tea
- ReqProtocol HTTP/1.1
[...]
- ReqHeader Prepend-Hdr-Target: foo
- ReqHeader Prepend-Hdr-Src: bar
[...]
- ReqUnset Prepend-Hdr-Target: foo
- ReqHeader Prepend-Hdr-Target: barfoo
[...]
```
## Select a rewrite from multiple matching rules
If the ``compare`` field is set to ``equal`` to specify string
equality matches, then if any string in a ``value`` field in the
``rules`` matches, it always matches exactly one of them (since the
same value for ``value`` may not appear more than once in a ``rules``
array). So the ``rewrite`` is always uniquely selected when an
``equal`` comparison succeeds.
But for the comparisons specified by ``compare:match`` (regex match)
or ``compare:prefix`` (fixed prefix match), it is possible that more
than one ``value`` matches, depending on the patterns used for the
values. For example, for either of regex or prefix matches, the string
``/tea/foo/bar/baz/quux`` matches all four values in the following
``rules``:
```
rules:
- value: /tea/foo/bar/baz/quux
rewrite: Quux
- value: /tea/foo/bar/baz
rewrite: Baz
- value: /tea/foo/bar
rewrite: Bar
- value: /tea/foo
rewrite: Foo
```
The ``select`` field is used to specify the rule to be applied in such
a situation. The default value of ``select`` is ``unique``, which
means that the rule identified by a comparison must be uniquely
determined, or else the rewrite fails. In all of the examples
considered above, ``select`` has defaulted to ``unique``, and in fact
only unique matches have been possible in those examples (because the
rules did not overlap in this way).
Other possible values for ``select`` depend on whether ``compare`` is
set to ``match`` or ``prefix``:
* ``unique`` (default for both ``compare:match`` and
``compare:prefix``): select the unique matching rule. The rewrite
fails if the match is not unique.
* ``first`` (permitted for both ``match`` and ``prefix``): select the
first matching rule, in the order given by the ``rules`` array
* ``last`` (permitted for both ``match`` and ``prefix``): select the
last matching rule in the ``rules`` array
* ``exact`` (only ``prefix``): select the rule for which the ``value``
is exactly equal to the string to be matched. The rewrite fails if
there is no exact match.
* For example, if the ``rules`` include ``/foo/`` and ``/foo/bar``
for a prefix match, and the string to be matched is exactly
``/foo/bar``, select the rule corresponding to ``/foo/bar``.
* ``shortest`` (only ``prefix``): select the rule with the shortest
matching prefix
* ``longest`` (only ``prefix``): select the rule with the longest
matching prefix
"Failure" in the case of ``select:unique`` and ``select:exact`` means
that VCL failure is invoked if there is more than one matching rule
for the comparison. In most cases, this means that a response with
status 503 and the reason ``VCL failed`` is returned for the
request. This is a "fail fast" measure taken to ensure that the unique
or exact match is satisfied -- test your data and rules to make sure
that the requirement is satisfied, to avoid the failures.
The first example in this group uses ``select:first`` to pick the
rewrite rule from the rules shown above:
```
- target: resp.http.Select-First
source: req.url
rules:
- value: /tea/foo/bar/baz/quux
rewrite: Quux
- value: /tea/foo/bar/baz
rewrite: Baz
- value: /tea/foo/bar
rewrite: Bar
- value: /tea/foo
rewrite: Foo
compare: prefix
method: replace
select: first
```
This tests the client request URL for a prefix that is specified by one
of the rules, and if one is found, select the first one that matches.
The string in the ``rewrite`` field for the corresponding rule is then
written to the client response header Select-First:
```
$ curl -x $IP:$PORT -v http://cafe.example.com/tea/foo/bar/baz/quux/4711
[...]
> GET http://cafe.example.com/tea/foo/bar/baz/quux/4711 HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Select-First: Quux
[...]
$ curl -x $IP:$PORT -v http://cafe.example.com/tea/foo/bar
[...]
> GET http://cafe.example.com/tea/foo/bar HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Select-First: Bar
[...]
```
The next example is very similar to the previous one, except that it
uses ``select:longest`` to specify the rewrite for the longest
matching prefix. This has the same effects of the previous example,
but does not depend on the order of elements of the ``rules`` array:
```
- target: resp.http.Select-Longest
source: req.url
rules:
- value: /tea/foo
rewrite: Foo
- value: /tea/foo/bar/baz
rewrite: Baz
- value: /tea/foo/bar
rewrite: Bar
- value: /tea/foo/bar/baz/quux
rewrite: Quux
compare: prefix
method: replace
select: longest
```
```
$ curl -x $IP:$PORT -v http://cafe.example.com/tea/foo/4711/0815
[...]
> GET http://cafe.example.com/tea/foo/4711/0815 HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Select-Longest: Foo
[...]
$ curl -x $IP:$PORT -v http://cafe.example.com/tea/foo/bar/a/b/
[...]
> GET http://cafe.example.com/tea/foo/bar/a/b/ HTTP/1.1
> Host: cafe.example.com
[...]
>
< HTTP/1.1 200 OK
[...]
< Select-Longest: Bar
[...]
```
In the final example, consider a number of cookies that may appear in
the cookie header in any order. The requirement is to extract the
value from one of them, and write the cookie name and value as a
key:value pair to a header (the client response header Cookie-Select
in the example).
If an order of preference can be specified for the cookies of
interest, then the ``rules`` array can be used to order the matching
rules, and ``select`` can be used to pick the preferred value. In this
case, we pick the last matching rule in the array:
```
- target: resp.http.Cookie-Select
source: req.http.Cookie
rules:
- value: \bcookie1\s*=\s*([^,;[:space:]]+)
rewrite: cookie1:\1
- value: \bcookie2\s*=\s*([^,;[:space:]]+)
rewrite: cookie2:\1
- value: \bcookie3\s*=\s*([^,;[:space:]]+)
rewrite: cookie3:\1
- value: \bcookie4\s*=\s*([^,;[:space:]]+)
rewrite: cookie4:\1
- value: \bcookie5\s*=\s*([^,;[:space:]]+)
rewrite: cookie5:\1
method: rewrite
select: last
```
Verification with curl shows that the last matching rule is chosen for
the rewrite, regardless of the order of cookies in the Cookie header:
```
$ curl -H 'Cookie: cookie2=val2; cookie3=val3; cookie1=val1' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Cookie: cookie2=val2; cookie3=val3; cookie1=val1
>
< HTTP/1.1 200 OK
[...]
< Cookie-Select: cookie3:val3
[...]
$ curl -H 'Cookie: cookie3=val3; cookie4=val4' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Cookie: cookie3=val3; cookie4=val4
>
< HTTP/1.1 200 OK
[...]
< Cookie-Select: cookie4:val4
[...]
$ curl -H 'Cookie: cookie5=val5; cookie4=val4; cookie3=val3' -x $IP:$PORT -v http://cafe.example.com/tea
[...]
> GET http://cafe.example.com/tea HTTP/1.1
> Host: cafe.example.com
[...]
> Cookie: cookie5=val5; cookie4=val4; cookie3=val3
>
< HTTP/1.1 200 OK
[...]
< Cookie-Select: cookie5:val5
[...]
```
Effective use of ``select`` involves knowledge of the patterns to be
matched, the data against which they are matched, and possibly an
ordering of preferences as reflected in the order of the ``rules``
array. With appropriate choices, some sophisticated use cases can be
solved efficiently with a relatively simple configuration.
......@@ -11,7 +11,39 @@ spec:
services:
- varnish-ingress
# rewrites is a non-empty array of rewrite specifications. Each
# element specifies a rewrite that is executed by the Varnish Service
# implementing Ingress.
#
# Each rewrite is executed in the VCL subroutine specified in the
# field vcl-sub; if vcl-sub is left out, the subroutine is inferred
# from the objects named in the target and source fields.
#
# If more than one rewrite is specified for the the same VCL subroutine,
# they are executed in the order in which they appear in this array.
rewrites:
# Rewrite the URL path of the client request, so that other URL
# prefixes are used to route requests to the coffee-svc backend.
#
# When the source field is left out, it is implicitly equal to
# the target, so the rewrite is based on a match against the URL.
#
# compare:match specifies regex matching -- the source (implicitly
# req.url) is matched against the value fields in rules.
#
# method:sub specifies rewrite by substituting the first matching
# substring.
#
# anchor:start means that each regex is implicitly anchored at
# start-of-string, equivalent to prefixing each regex with ^.
#
# The vcl-sub field is left out, so this rewrite is executed in
# vcl_recv, since it applies only to req.url.
#
# When the URL matches a regex in one of the value fields of the
# rules, then substitute using the corresponding rewrite string,
# with \1 used to replace backreference 1.
- target: req.url
compare: match
method: sub
......@@ -31,6 +63,17 @@ spec:
match-flags:
anchor: start
# Similar to the previous rewrite, this one rewrites URL prefixes
# so that the requests are routed to the tea-svc backend.
#
# In this case, compare:prefix is used to indicate fixed prefix
# matching -- req.url matches if it has a prefix equal to one of
# the values in the rules. With prefix, matches are always fixed
# at start-of-string.
#
# This configuration is simpler than the one above. But note that
# it does not prevent rewrites for matches that do end in / or
# end-of-string; for example, /chain/link is rewritten as /tean/link.
- target: req.url
compare: prefix
rules:
......@@ -48,6 +91,20 @@ spec:
rewrite: /tea
method: sub
# Replace certain values of the client request header Host so that
# they may be routed by the Ingress (which specifies cafe.example.com).
#
# The source field is again left out, and is hence implicitly equal
# to the target -- the client request header Host is rewritten.
#
# Since vcl-sub is again left out, the rewrite is executed in vcl_recv,
# since it applies only to a client request header.
#
# compare:equal specifies fixed string equality -- a Host header matches
# if it is exactly equal to one of the values in the rules.
#
# method:replace means that the headers value is overwritten by the
# string in rewrite that corresponds to the match.
- target: req.http.Host
compare: equal
rules:
......@@ -63,6 +120,24 @@ spec:
rewrite: cafe.example.com
method: replace
# Extract the value of a cookie into a client response header.
#
# The compare field is left out, and hence implicitly specifies
# regex matching.
#
# source:req.http.Cookie means that the regex in the value field
# is match against the client request header Cookie, and the
# backreference refers to the captured portion of the match.
#
# target:resp.http.Session-Token means that the result of the
# rewrite is written to the client response header Session-Token.
#
# Since vcl-sub is left out, the rewrite is executed in vcl_deliver,
# since the target is a client response header.
#
# method:rewrite means that backref \1, specified in the rewrite
# field, is written to the Session-Token header, and unmatched
# portions of the Cookie header are ignored.
- target: resp.http.Session-Token
source: req.http.Cookie
rules:
......@@ -70,6 +145,23 @@ spec:
rewrite: \1
method: rewrite
# The next sequence implements a common use case for Varnish: write
# a value to the client request and response headers X-Cache to
# reflect the cache disposition of the request -- hit, miss or pass.
#
# The vcl-sub fields specify the VCL subroutines in which the
# rewrites are executed. Since the target in the fourth rewrite is
# the client response header, it is executed in vcl_deliver.
#
# method:replace means that the value of the target is overwritten.
#
# The first three rewrites specify exactly one rule, each with no
# value field. This means that the string in the corresponding
# rewrite field is written as the new value of the header.
#
# The fourth rewrite specifies replace with the request header as
# source and the response header as target, meaning that the value
# of the response header is set to the value of the request header.
- target: req.http.X-Cache
vcl-sub: hit
rules:
......@@ -92,24 +184,25 @@ spec:
source: req.http.X-Cache
method: replace
# Rewrite the backend request URL path by exchanging the next two path
# components after /coffee/, if the URL begins with /coffee/.
# For example, /coffee/cream/sugar is rewritten as /coffee/sugar/cream.
#
# method:rewrite means that the URL is rewritten as given in the rewrite
# field of the rule, and non-matching parts of the URL are ignored.
- target: bereq.url
rules:
- value: /coffee/([^/]+)/([^/]+)(.*)
- value: ^/coffee/([^/]+)/([^/]+)(.*)
rewrite: /coffee/\2/\1\3
method: rewrite
- target: resp.http.Replace-Hdr-Target
source: req.http.Replace-Hdr-Src
method: replace
- target: resp.http.Replace-String-Target
rules:
- rewrite: ReplaceString
method: replace
# Unconditionally delete the client response header Server.
- target: resp.http.Server
method: delete
# Delete the client response header Via if the client request header
# Delete-Via matches (case-insensitively) one of the strings given
# as a value in the rules.
- target: resp.http.Via
method: delete
source: req.http.Delete-Via
......@@ -122,12 +215,54 @@ spec:
match-flags:
case-sensitive: false
# To unconditionally write the value of one header to another, specify
# method:replace with no rules, and specify the headers as source and
# target.
#
# In other words: set Replace-Hdr-Target = Replace-Hdr-Src
- target: resp.http.Replace-Hdr-Target
source: req.http.Replace-Hdr-Src
method: replace
# To write a fixed string to a header, specify method:replace with no
# source, and exactly one rule with no value field, and the fixed
# string in the rewrite field.
#
# That is: set Replace-String-Target = "ReplaceString"
- target: resp.http.Replace-String-Target
rules:
- rewrite: ReplaceString
method: replace
# method:append concatenates a string after another one, and writes the
# result to the target.
#
# This specification appends the fixed string "AppendString" after the
# value of the client request header Append-String-Src, and assigns
# the result to the client response header Append-String-Target.
#
# That is: set Append-String-Target = Append-String-Src + "AppendString"
#
# Since the rule has no value field, the append is executed
# unconditionally, even if there is no client request header
# Append-String-Src. In that case, just the string "AppendString"
# is assigned to the response header.
- target: resp.http.Append-String-Target
source: req.http.Append-String-Src
rules:
- rewrite: AppendString
method: append
# Like the rule above, but the append is only executed if the source
# (the client request header) matches the regex in value.
#
# Since the regex is just . (match any character), this has the effect
# of only executing the append if the request header exists and is
# non-empty.
#
# In other words:
# if (request header Append-Rule-Src exists),
# then set Append-Rule-Target = Append-Rule-Src + "AppendString"
- target: resp.http.Append-Rule-Target
source: req.http.Append-Rule-Src
rules:
......@@ -135,16 +270,36 @@ spec:
rewrite: AppendString
method: append
# If no rules are specified with method:append, then the value of the
# the source is appended to the value of target, and the result is
# assigned to the target. In other words:
#
# set Append-Hdr-Target = Append-Hdr-Target + Append-Hdr-Src
- target: req.http.Append-Hdr-Target
source: req.http.Append-Hdr-Src
method: append
# method:prepend reverses the order of concatentation. So this
# specification is similar to the unconditional append shown above:
#
# set Prepend-String-Target = "PrependString" + Prepend-String-Src
#
# If there is no client request header Prepend-String-Src, then just
# assign the string "PrependString" to the client response header
# Prepend-String-Target.
- target: resp.http.Prepend-String-Target
source: req.http.Prepend-String-Src
rules:
- rewrite: PrependString
method: prepend
# Like the conditional append shown above: execute the prepend, but
# only if the header specified as source matches the value in the
# rule; or in other words, only if the source header exists and is
# non-empty:
#
# if (Prepend-Rule-Src exists and is non-empty),
# then: set Prepend-Rule-Target = "PrependString" + Prepend-Rule-Src
- target: resp.http.Prepend-Rule-Target
source: req.http.Prepend-Rule-Src
rules:
......@@ -152,10 +307,28 @@ spec:
rewrite: PrependString
method: prepend
# Prepend the source header to the target:
#
# set Prepend-Hdr-Target = Prepend-Hdr-Src + Prepend-Hdr-Target
- target: req.http.Prepend-Hdr-Target
source: req.http.Prepend-Hdr-Src
method: prepend
# The remaining examples illustrate the use of the select field to
# specify the rewrite rule when more than one value in a rule may
# match the source.
#
# This example sets the client response header Select-First to one
# of the fixed strings in a rewrite field, depending on which prefix
# matches the client request URL path.
#
# If the URL has a matching prefix, then select:first means that the
# the first matching value in the rules array is chosen, and the
# string from the corresponding rewrite field is assigned.
#
# For example, the URL /tea/foo/bar/4711 matches the regexen in the
# last two rules. Since select:first is specified, assign the string
# "Bar" to the header.
- target: resp.http.Select-First
source: req.url
rules:
......@@ -171,6 +344,13 @@ spec:
method: replace
select: first
# This example is similar to the previous one, but select:longest
# means that the longest prefix that matches the URL in one of the
# rules is chosen, and the corresponding value of rewrite is
# assigned to the header.
#
# The effects are the same, but do not depend on the order of rules
# in the rules array.
- target: resp.http.Select-Longest
source: req.url
rules:
......@@ -186,6 +366,22 @@ spec:
method: replace
select: longest
# In this example, the value of a cookie is extracted from the
# Cookie request header, and a string with the extracted value
# is assigned to the client response header Cookie-Select.
#
# select:last means that if more than one pattern in the rules
# array matches the Cookie header, then choose the matching pattern
# that appears last in the rules array. The value assigned to
# Cookie-Select is formed from the corresponding rewrite pattern.
#
# Examples: if the Cookie header has this value:
# Cookie: cookie2=val2; cookie3=val3; cookie1=val1
# then "cookie3:val3" is assigned to Cookie-Select.
#
# If the Cookie header has this value:
# Cookie: cookie3=val3; cookie4=val4
# then "cookie4:val4" is assigned to Cookie-Select.
- target: resp.http.Cookie-Select
source: req.http.Cookie
rules:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment