1.. Licensed to the Apache Software Foundation (ASF) under one or more contributor license
2   agreements.  See the NOTICE file distributed with this work for additional information regarding
3   copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0
4   (the "License"); you may not use this file except in compliance with the License.  You may obtain
5   a copy of the License at
6
7   http://www.apache.org/licenses/LICENSE-2.0
8
9   Unless required by applicable law or agreed to in writing, software distributed under the License
10   is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   or implied.  See the License for the specific language governing permissions and limitations
12   under the License.
13
14.. include:: ../../common.defs
15.. highlight:: none
16
17.. _admin-plugins-header-rewrite:
18
19Header Rewrite Plugin
20*********************
21
22This plugin allows you to modify arbitrary headers based on defined rules, for
23both requests and responses.
24
25Purpose
26=======
27
28Remapping an incoming client request to an origin server is at the heart of
29what we use |TS| for, but often we need to do more to requests than just change
30their destination according to simple rewriting rules against the URL.
31
32We may need to direct requests to different origins based on a client cookie.
33
34Our origins might return error response codes which are a little too customized
35and we want to condense the possible values to just the official codes.
36
37We might want to strip a set of internal-use or debugging related HTTP headers
38from responses before sending them to clients, unless the original request had
39its own special header indicating that they should be retained.
40
41Or perhaps we want to redirect certain requests differently when they come from
42a known group of IP addresses (say, our developers' office network) and we have
43a file on our proxy caching servers called ``/var/developertesting``. (Stranger
44QA methods exist.)
45
46Maybe we want to deny access to a resource with an HTTP 403 if the client
47connected to |TS| over a particular port, used ``HEAD`` instead of ``GET``,
48doesn't list Spanish (Paraguay dialect) in their ``Accept-Language`` header,
49and either the origin server replied with 304 or we randomly generate an
50integer between 0 and 500 and get back anything greater than 290.
51
52These more complicated transformations of requests and responses (even that
53last one) are made possible by this plugin.
54
55Installation
56============
57
58This plugin is considered stable and is included with |TS| by default. There
59are no special steps necessary for its installation.
60
61Configuration
62=============
63
64Header rewrite configurations, the actual conditions and operations that make
65up the activity performed by the plugin, are specified in external files and
66not in-line with the various mapping (and remapping) rules you may have
67configured for your proxy. The location of this file is arbitrary, as long as
68the |TS| processes have permissions to read it, though you may find it useful
69to keep it in the same location as your other proxy configuration files.
70
71The paths given to the configuration file(s) may be absolute (leading with a
72``/`` character), or they may be relative to the |TS| configuration directory.
73
74There are two methods for enabling this plugin, based on whether you wish it to
75operate globally on every request that passes through your proxy, or only on
76some subset of the requests by enabling it only for specific mapping rules.
77
78Enabling Globally
79-----------------
80
81This plugin may be enabled globally, so that the conditions and header
82rewriting rules are evaluated for every request made to your |TS| instance.
83This is done by adding the following line to your :file:`plugin.config`::
84
85  header_rewrite.so [--geo-db-path=path/to/geoip.db] config_file_1.conf config_file_2.conf ...
86
87You may specify multiple configuration files. Their rules will be evaluated in
88the order the files are listed.
89
90The plugin takes an optional switch ``--geo-db-path``. If MaxMindDB support has
91been compiled in, use this switch to point at your .mmdb file. This also applies to
92the remap context.
93
94
95Enabling Per-Mapping
96--------------------
97
98Alternatively, the plugin can be enabled for specific mapping rules, by
99modifying the relevant entries in your :file:`remap.config`::
100
101  map http://a http://b @plugin=header_rewrite.so @pparam=rules1.conf ...
102
103As with the global method above, multiple configuration files may be listed,
104each with its own ``@pparam=<file>`` and their contents will be evaluated in
105the order the files were specified.
106
107Each ruleset that is configured per-mapping should have a special
108`Hook Conditions`_ defined. Without a defined hook, these rulesets will use the
109``REMAP_PSEUDO_HOOK``.
110
111Rewriting Rules
112===============
113
114Header rewriting rules consist of zero or more `Conditions`_ followed by one or
115more `Operators`_. Conditions are used to limit the requests which will be
116affected by the operator(s). Additionally, both conditions and operators may
117have flags which modify their behavior.
118
119A complete rule, consisting of two conditions and a single operator might look
120like the following::
121
122    cond %{STATUS} >399 [AND]
123    cond %{STATUS} <500
124    set-status 404
125
126Which converts any 4xx HTTP status code from the origin server to a 404. A
127response from the origin with a status of 200 would be unaffected by this rule.
128
129Conditions
130----------
131
132Conditions are used as qualifiers, causing the associated operators to only be
133evaluated if the condition(s) are met. Conditions all take the following form::
134
135    cond %{<condition name>[:<argument>]} <operand> [<flags>]
136
137Every condition begins with the literal string ``cond`` to indicate that this
138line is a condition, not an operator. This is followed by the condition name,
139inside curly braces and preceded by a percent sign (e.g. ``%{TRUE}`` for the
140condition named ``TRUE``). Some condition names take an argument. Header
141conditions, for example, take the name of the header in question, and cookie
142conditions take the name of the cookie. For these, the condition name is
143followed by a colon and the argument value (e.g. ``%{HEADER:User-Agent}`` for a
144header condition against the ``User-Agent`` header).
145
146The operand of a condition provides a value, pattern, or range against which to
147match. The format is described in `Condition Operands`_ below.
148
149Finally, a condition may optionally have various flags associated with it.
150These are described in `Condition Flags`_ below.
151
152The following sections list all of the condition types currently supported. For
153increased clarity in their usage, the optional ``[<flags>]`` portion of the
154condition is omitted from all of the examples.
155
156ACCESS
157~~~~~~
158::
159
160    cond %{ACCESS:<path>}
161
162Returns true if |TS| was able to successfully update the access time on the
163file at ``<path>``. This condition will return false if the file does not exist
164or |TS| cannot access it for any other reason.
165
166CLIENT-HEADER
167~~~~~~~~~~~~~
168::
169
170    cond %{CLIENT-HEADER:<name>} <operand>
171
172Value of the header ``<name>`` from the original client request (regardless of
173the hook context in which the rule is being evaluated). Note that some headers
174may appear in an HTTP message more than once. In these cases, the value of the
175header operated on by this condition will be a comma separated string of the
176values from every occurrence of the header. More details are provided in
177`Repeated Headers`_ below.
178
179CLIENT-URL
180~~~~~~~~~~
181::
182
183    cond %{CLIENT-URL:<part>} <operand>
184
185The URL of the original request. Regardless of the hook context in which the
186rule is evaluated, this condition will always operate on the original, unmapped
187URL supplied by the client. The ``<part>`` may be specified according to the
188options documented in `URL Parts`_.
189
190Note that the HOST ``<part>`` of the CLIENT-URL might not be set until the remap
191phase of the transaction.  This happens when there is no host in the incoming URL
192and only set as a host header.  During the remap phase the host header is copied
193to the CLIENT-URL.  Use CLIENT-HEADER:Host if you are going to match the host.
194
195COOKIE
196~~~~~~
197::
198
199    cond %{COOKIE:<name>} <operand>
200
201Value of the cookie ``<name>``. This does not expose or match against a
202cookie's expiration, the domain(s) on which it is valid, whether it is protocol
203restricted, or any of the other metadata; simply the current value of the
204cookie as presented by the client.
205
206FROM-URL
207~~~~~~~~
208::
209
210    cond %{FROM-URL:<part>} <operand>
211
212In a remapping context, this condition matches against the source URL from
213which the remapping was generated. This condition is valid only within
214configurations provided through :file:`remap.config` as described in `Enabling
215Per-Mapping`_ above.
216
217The ``<part>`` allows the operand to match against just a component of the URL,
218as documented in `URL Parts`_ below.
219
220GEO
221~~~
222::
223
224    cond %{GEO:<part>} <operand>
225
226Perform a GeoIP lookup of the client-IP, using a 3rd party library and
227DB. Currently the MaxMind GeoIP and MaxMindDB APIs are supported. The default is to
228do a Country lookup, but the following qualifiers are supported::
229
230    %{GEO:COUNTRY}      The country code (e.g. "US")
231    %{GEO:COUNTRY-ISO}  The country ISO code (e.g. 225)
232    %{GEO:ASN}          The AS number for the provider network (e.g. 7922)
233    %{GEO:ASN-NAME}     A descriptive string of the AS provider
234
235These operators can be used both as conditionals, as well as values for
236setting headers. For example::
237
238    cond %{SEND_RESPONSE_HDR_HOOK} [AND]
239    cond %${GEO:COUNTRY} =US
240        set-header ATS-Geo-Country %{GEO:COUNTRY}
241        set-header ATS-Geo-Country-ISO %{GEO:COUNTRY-ISO}
242        set-header ATS-Geo-ASN %{GEO:ASN}
243        set-header ATS-Geo-ASN-NAME %{GEO:ASN-NAME}
244
245
246HEADER
247~~~~~~
248::
249
250    cond %{HEADER:<name>} <operand>
251
252Value of the header ``<name>`` from either the original client request or the
253origin server's response, depending upon the hook context in which the rule is
254being evaluated. Consult `Requests vs. Responses`_ for more information on how
255to distinguish the two, as well as enforce that a rule is always evaluated in
256the desired context.
257
258Note that some headers may appear in an HTTP message more than once. In these
259cases, the value of the header operated on by this condition will be a comma
260separated string of the values from every occurrence of the header. Refer to
261`Repeated Headers`_ for more information.
262
263If you wish to use a client request header, regardless of hook context, you may
264consider using the `CLIENT-HEADER`_ condition instead.
265
266ID
267~~
268::
269
270   cond %{ID:REQUEST} >100
271
272This condition provides access to three identifier values that ATS uses
273internally for things like logging and debugging. Since these are IDs, they
274are mostly useful as a value (operand) to other operators. The three types of
275IDs are ::
276
277    %{ID:REQUEST}    A unique, sequence number for the transaction
278    %{ID:PROCESS}    A UUID string, generated every time ATS restarts
279    %{ID:UNIQUE}     The combination of the previous two IDs
280
281Now, even though these are conditionals, their primary use are as value
282arguments to another operator. For example::
283
284    set-header ATS-Req-UUID %{ID:UNIQUE}
285
286CIDR
287~~~~
288::
289
290   set-header @Client-CIDR %{CIDR:24,48}
291
292This condition takes the client IP, and applies the provided CIDR style masks
293to the IP, before producing a string. The typical use of this conditions is as
294above, producing a header that contains a IP representation which has some
295privacy properties. It can of course also be used as a regular condition, and
296the output is a string that can be compared against. The two optional
297arguments are as follows::
298
299    IPv4-Mask    Length, in bits, of the IPv4 address to preserve. Default: 24
300    IPv6-Mask    Length, in bits, of the IPv6 address to preserve. Default: 48
301
302The two arguments, if provided, are comma separated. Valid syntax includes::
303
304    %{CIDR}         Defaults to 24,48 (as above)
305    %{CIDR:16}      IPv4 CIDR mask is 16 bits, IPv6 mask is 48
306    %{CIDR:18,42}   IPv4 CIDR mask is 18 bits, IPv6 mask is 42 bits
307
308A typical use case is to insert the @-prefixed header as above, and then use
309this header in a custom log format, rather than logging the full client
310IP. Another use case could be to make a special condition on a sub-net,
311e.g.::
312
313    cond %{CIDR:8} ="8.0.0.0"
314        set-header X-Is-Eight "Yes"
315    cond %{CIDR:,8} ="fd00::" #note the IPv6 Mask is in the second position
316        set-header IPv6Internal "true"
317
318This condition has no requirements other than access to the Client IP, hence,
319it should work in any and all hooks.
320
321INBOUND
322~~~~~~~
323::
324
325   cond %{INBOUND:TLS} /./
326
327This condition provides access to information about the inbound (client, user agent) connection to ATS.
328The data that can be checked is ::
329
330   %{INBOUND:LOCAL-ADDR}      The local (ATS) address for the connection. Equivalent to %{IP:INBOUND}.
331   %{INBOUND:LOCAL-PORT}      The local (ATS) port for the connection.
332   %{INBOUND:REMOTE-ADDR}     The client address for the connection. Equivalent to %{IP:CLIENT}.
333   %{INBOUND:REMOTE-PORT}     The client port for the connection.
334   %{INBOUND:TLS}             The TLS protocol if the connection is over TLS, otherwise the empty string.
335   %{INBOUND:H2}              The string "h2" if the connection is HTTP/2, otherwise the empty string.
336   %{INBOUND:IPV4}            The string "ipv4" if the connection is IPv4, otherwise the empty string.
337   %{INBOUND:IPV6}            The string "ipv6" if the connection is IPv6, otherwise the empty string.
338   %{INBOUND:IP-FAMILY}       The IP family, either "ipv4" or "ipv6".
339   %{INBOUND:STACK}           The full protocol stack separated by ','.
340
341All of the tags generated by this condition are from the :ref:`protocol stack tags <protocol_tags>`.
342
343Because of the implicit match rules, using these as conditions is a bit unexpected. The condition
344listed above will be true if the inbound connection is over TLS because ``%{INBOUND:TLS}`` will only
345return a non-empty string for TLS connections. In contrast ::
346
347   cond %{INBOUND:TLS}
348
349will be true for *non*-TLS connections because it will be true when ``%{INBOUND:TLS}`` is the empty
350string. This happens because the default matching is equality and the default value the empty
351string. Therefore the condition is treated as if it were ::
352
353  cond %{INBOUND:TLS}=""
354
355which is true when the connection is not TLS. The arguments ``H2``, ``IPV4``, and ``IPV6`` work the
356same way.
357
358
359IP
360~~
361::
362
363    cond %{IP:<part>} <operand>
364
365This is one of four possible IPs associated with the transaction, with the
366possible parts being
367::
368
369    %{IP:CLIENT}     Client's IP address. Equivalent to %{INBOUND:REMOTE-ADDR}.
370    %{IP:INBOUND}    ATS's IP address to which the client connected. Equivalent to %{INBOUND:LOCAL-ADDR}
371    %{IP:SERVER}     Upstream (next-hop) server IP address (typically origin, or parent)
372    %{IP:OUTBOUND}   ATS's outbound IP address, that was used to connect upstream (next-hop)
373
374Note that both `%{IP:SERVER}` and `%{IP:OUTBOUND}` can be unset, in which case the
375empty string is returned. The common use for this condition is
376actually as a value to an operator, e.g. ::
377
378   cond %{SEND_RESPONSE_HDR_HOOK}
379     set-header X-Client-IP %{IP:CLIENT}
380     set-header X-Inbound-IP %{IP:INBOUND}
381     set-header X-Server-IP %{IP:SERVER}
382     set-header X-Outbound-IP %{IP:OUTBOUND}
383
384
385INTERNAL-TRANSACTION
386~~~~~~~~~~~~~~~~~~~~
387::
388
389    cond %{INTERNAL-TRANSACTION}
390
391Returns true if the current transaction was internally-generated by |TS| (using
392:c:func:`TSHttpTxnIsInternal`). These transactions are not initiated by
393external client requests, but are triggered (often by plugins) entirely within
394the |TS| process.
395
396METHOD
397~~~~~~~
398::
399
400    cond %{METHOD} <operand>
401
402The HTTP method (e.g. ``GET``, ``HEAD``, ``POST``, and so on) used by the
403client for this transaction.
404
405NOW
406~~~
407::
408
409    cond %{NOW:<part>} <operand>
410
411This is the current time, in the local timezone as set on the machine,
412typically GMC. Without any further qualifiers, this is the time in seconds
413since EPOCH aka Unix time. Qualifiers can be used to give various other
414values, such as year, month etc.
415::
416
417    %{NOW:YEAR}      Current year (e.g. 2016)
418    %{NOW:MONTH}     Current month (0-11, 0 == January)
419    %{NOW:DAY}       Current day of the month (1-31)
420    %{NOW:HOUR}      Current hour (0-23, in the 24h system)
421    %{NOW:MINUTE}    Current minute (0-59}
422    %{NOW:WEEKDAY}   Current weekday (0-6, 0 == Sunday)
423    %{NOW:YEARDAY}   Current day of the year (0-365, 0 == Jan 1st)
424
425
426RANDOM
427~~~~~~
428::
429
430    cond %{RANDOM:<n>} <operand>
431
432Generates a random integer from ``0`` up to (but not including) ``<n>``. Mathematically, ``[0,n)`` or ``0 <= r < n``.
433
434STATUS
435~~~~~~
436::
437
438    cond %{STATUS} <operand>
439
440Numeric HTTP status code of the response.
441
442TO-URL
443~~~~~~
444::
445
446    cond %{TO-URL:<part>} <operand>
447
448In a remapping context, this condition matches against the target URL to which
449the remapping is directed. This condition is valid only within configurations
450provided through :file:`remap.config` as described in `Enabling Per-Mapping`_
451above.
452
453The ``<part>`` allows the operand to match against just a component of the URL,
454as documented in `URL Parts`_ below.
455
456TRUE / FALSE
457~~~~~~~~~~~~
458::
459
460    cond %{TRUE}
461    cond %{FALSE}
462
463These conditions always return a true value and a false value, respectively.
464The true condition is implicit in any rules which specify no conditions (only
465operators).
466
467TXN-COUNT
468~~~~~~~~~
469::
470
471    cond %{TXN-COUNT} <operand>
472
473Returns the number of transactions (including the current one) that have been sent on the current
474client connection. This can be used to detect if the current transaction is the first transaction.
475
476URL
477~~~
478::
479
480    cond %{URL:<part>} <operand>
481
482The complete URL of the current transaction. This will automatically choose the
483most relevant URL depending upon the hook context in which the condition is
484being evaluated.
485
486Refer to `Requests vs. Responses`_ for more information on determining the
487context in which the transaction's URL is evaluated.  The ``<part>`` may be
488specified according to the options documented in `URL Parts`_.
489
490SSN-TXN-COUNT
491~~~~~~~~~~~~~
492::
493
494    cond %{SSN-TXN-COUNT} <operand>
495
496Returns the number of transactions between the Traffic Server proxy and the origin server from a single session.
497Any value greater than zero indicates connection reuse.
498
499TCP-INFO
500~~~~~~~~
501::
502
503    cond %{<name>}
504        add-header @PropertyName "%{TCP-INFO}"
505
506This operation records TCP Info struct field values as an Internal remap as well as global header at the event hook specified by the condition. Supported hook conditions include TXN_START_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Global plugin and REMAP_PSEUDO_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Remap plugin. Conditions supported as request headers include TXN_START_HOOK and REMAP_PSEUDO_HOOK. The other conditions are supported as response headers. TCP Info fields currently recorded include rtt, rto, snd_cwnd and all_retrans. This operation is not supported on transactions originated within Traffic Server (for e.g using the |TS| :c:func:`TSHttpTxnIsInternal`)
507
508Condition Operands
509------------------
510
511Operands provide the means to restrict the values, provided by a condition,
512which will lead to that condition evaluating as true. There are currently four
513types supported:
514
515=========== ===================================================================
516Operand     Description
517=========== ===================================================================
518/regex/     Matches the condition's provided value against the regular
519            expression.
520<string     Matches if the value from the condition is lexically less than
521            *string*.
522>string     Matches if the value from the condition is lexically greater than
523            *string*.
524=string     Matches if the value from the condition is lexically equal to
525            *string*.
526=========== ===================================================================
527
528The absence of an operand for conditions which accept them simply requires that
529a value exists (e.g. the content of the header is not an empty string) for the
530condition to be considered true.
531
532Condition Flags
533---------------
534
535The condition flags are optional, and you can combine more than one into
536a comma-separated list of flags. Note that whitespaces are not allowed inside
537the brackets:
538
539====== ========================================================================
540Flag   Description
541====== ========================================================================
542AND    Indicates that both the current condition and the next must be true.
543       This is the default behavior for all conditions when no flags are
544       provided.
545NOT    Inverts the condition.
546OR     Indicates that either the current condition or the next one must be
547       true, as contrasted with the default behavior from ``[AND]``.
548====== ========================================================================
549
550Operators
551---------
552
553Operators are the part of your header rewriting rules which actually modify the
554header content of your requests and responses. They are always the final part
555of a rule, following any of the conditions which whittled down the requests and
556responses to which they will be applied.
557
558Multiple operators may be specified for a single rule, and they will be
559executed in the order listed. The end of the rule is marked either by the end
560of the configuration file or the next appearance of a condition (whichever
561occurs first).
562
563The following operators are available:
564
565add-cookie
566~~~~~~~~~~
567::
568
569  add-cookie <name> <value>
570
571Adds a new ``<name>`` cookie line with the contents ``<value>``. Note that this
572operator will do nothing if a cookie pair with ``<name>`` already exists.
573
574add-header
575~~~~~~~~~~
576::
577
578  add-header <name> <value>
579
580Adds a new ``<name>`` header line with the contents ``<value>``. Note that this
581operator can produce duplicate headers if one of ``<name>`` already exists, or
582your configuration supplies multiple instances of this operator in different
583rules which are all invoked. This is not an issue for headers which may safely
584be specified multiple times, such as ``Set-Cookie``, but for headers which may
585only be specified once you may prefer to use `set-header`_ instead.
586
587The header's ``<value>`` may be specified as a literal string, or it may take
588advantage of `String concatenations`_ to calculate a dynamic value
589for the header.
590
591counter
592~~~~~~~
593::
594
595  counter <name>
596
597Increments an integer counter called ``<name>`` every time the rule is invoked.
598The counter is initialized at ``0`` if it does not already exist. The name you
599give your counter is arbitrary, though it is strongly advisable to avoid
600conflicts with existing |TS| statistics.
601
602This counter can be viewed at any time through the standard statistics APIs,
603including the :ref:`Stats Over HTTP plugin <admin-plugins-stats-over-http>`.
604
605Counters can only increment by 1 each time this operator is invoked. There is
606no facility to increment by other amounts, nor is it possible to initialize the
607counter with any value other than ``0``. Additionally, the counter will reset
608whenever |TS| is restarted.
609
610no-op
611~~~~~
612::
613
614  no-op
615
616This operator does nothing, takes no arguments, and has no side effects.
617
618rm-header
619~~~~~~~~~
620::
621
622  rm-header <name>
623
624Removes the header ``<name>``.
625
626rm-cookie
627~~~~~~~~~
628::
629
630  rm-cookie <name>
631
632Removes the cookie ``<name>``.
633
634set-config
635~~~~~~~~~~
636::
637
638  set-config <name> <value>
639
640Allows you to override the value of a |TS| configuration variable for the
641current connection. The variables specified by ``<name>`` must be overridable.
642For details on available |TS| configuration variables, consult the
643documentation for :file:`records.config`. You can read more about overridable
644configuration variables in the developer's documentation for
645:ref:`ts-overridable-config`.
646
647set-conn-dscp
648~~~~~~~~~~~~~
649::
650
651  set-conn-dscp <value>
652
653When invoked, sets the client side `DSCP
654<https://en.wikipedia.org/wiki/Differentiated_services>`_ value for the current
655transaction.  The ``<value>`` should be specified as a decimal integer.
656
657set-conn-mark
658~~~~~~~~~~~~~
659::
660
661  set-conn-mark <value>
662
663When invoked, sets the client side MARK value for the current
664transaction.  The ``<value>`` should be specified as a decimal integer.
665Requires at least Linux 2.6.25.
666
667set-debug
668~~~~~~~~~
669::
670
671  set-debug
672
673When invoked, this operator enables the internal transaction debugging flag
674(via :c:func:`TSHttpTxnDebugSet`), which causes debug messages to be printed to
675the appropriate logs even when the debug tag has not been enabled. For
676additional information on |TS| debugging statements, refer to
677:ref:`developer-debug-tags` in the developer's documentation.
678
679set-destination
680~~~~~~~~~~~~~~~
681::
682
683  set-destination <part> <value>
684
685Modifies individual components of the remapped destination's address. When
686changing the remapped destination, ``<part>`` should be used to indicate the
687component that is being modified (see `URL Parts`_), and ``<value>`` will be
688used as its replacement. You must supply a non-zero length value, otherwise
689this operator will be an effective no-op (though a warning will be emitted to
690the logs if debugging is enabled).
691
692set-header
693~~~~~~~~~~
694::
695
696  set-header <name> <value>
697
698Replaces the value of header ``<name>`` with ``<value>``, creating the header
699if necessary.
700
701The header's ``<value>`` may be a literal string, or take advantage of
702`String concatenations`_ to calculate a dynamic value for the header.
703
704set-redirect
705~~~~~~~~~~~~
706::
707
708  set-redirect <code> <destination>
709
710When invoked, sends a redirect response to the client, with HTTP status
711``<code>``, and a new location of ``<destination>``. If the ``QSA`` flag is
712enabled, the original query string will be preserved and added to the new
713location automatically. This operator supports
714`String concatenations`_ for ``<destination>``.
715
716set-status
717~~~~~~~~~~
718::
719
720  set-status <code>
721
722Modifies the :ref:`HTTP status code <appendix-http-status-codes>` used for the
723response. ``<code>`` must be a valid status code. This operator will also
724update the reason in the HTTP response, based on the code you have chosen. If
725you wish to override that with your own text, you will need to invoke the
726`set-status-reason`_ operator after this one.
727
728set-status-reason
729~~~~~~~~~~~~~~~~~
730::
731
732  set-status-reason <reason>
733
734Modifies the HTTP response to use ``<reason>`` as the HTTP status reason,
735instead of the standard string (which depends on the :ref:`HTTP status code
736<appendix-http-status-codes>` used).
737
738set-timeout-out
739~~~~~~~~~~~~~~~
740::
741
742  set-timeout-out <type> <value>
743
744Modifies the timeout values for the current transaction to ``<value>``
745(specified in milliseconds). The ``<type>`` must be one of the following:
746``active``, ``inactive``, ``connect``, or ``dns``.
747
748skip-remap
749~~~~~~~~~~
750::
751
752  skip-remap <value>
753
754When invoked, and when ``<value>`` is any of ``1``, ``true``, or ``TRUE``, this
755operator causes |TS| to abort further request remapping. Any other value and
756the operator will effectively be a no-op.
757
758set-cookie
759~~~~~~~~~~
760::
761
762  set-cookie <name> <value>
763
764Replaces the value of cookie ``<name>`` with ``<value>``, creating the cookie
765if necessary.
766
767Operator Flags
768--------------
769
770Operator flags are optional, are separated by commas when using more than one
771for a single operator, and must not contain whitespace inside the brackets. For
772example, an operator with the ``L`` flag would be written in this manner::
773
774    set-destination HOST foo.bar.com [L]
775
776The flags currently supported are:
777
778====== ========================================================================
779Flag   Description
780====== ========================================================================
781L      Last rule, do not continue.
782QSA    Append the results of the rule to the query string.
783====== ========================================================================
784
785String concatenations
786---------------------
787
788You can concatenate values using strings, condition values and variable expansions on the same line.
789
790    add-header CustomHeader "Hello from %{IP:SERVER}:%{INBOUND:LOCAL-PORT}"
791
792This is the new, generic form of setting header values. Unfortunately, string
793concatenation is not yet supported in conditionals.
794
795Note: In versions prior to ATS v9.0.0, an alternative string expansion was available. those
796expansions are no longer available, but the following table can help migrations:
797
798======================== ==========================================================================
799Old expansion variable   Condition variable to use with concatenations
800======================== ==========================================================================
801%<proto>                 %{CLIENT-URL:SCHEME}
802%<port>                  %{CLIENT-URL:PORT}
803%<chi>                   %{IP:CLIENT}, %{INBOUND:REMOTE-ADDR} or e.g. %{CIDR:24,48}
804%<cqhl>                  %{CLIENT-HEADER:Content-Length}
805%<cqhm>                  %{METHOD}
806%<cque>                  %[CLIENT-URL}
807%<cquup>                 %{CLIENT-URL:PATH}
808======================== ==========================================================================
809
810URL Parts
811---------
812
813Some of the conditions and operators which use a request or response URL as
814their target allow for matching against specific components of the URL. For
815example, the `CLIENT-URL`_ condition can be used to test just against the query
816parameters by writing it as::
817
818    cond %{CLIENT-URL:QUERY} <operand>
819
820The URL part names which may be used for these conditions and actions are:
821
822======== ======================================================================
823Part     Description
824======== ======================================================================
825HOST     Full hostname.
826
827PATH     URL substring beginning with (but not including) the first ``/`` after
828         the hostname up to, but not including, the query string. **Note**: previous
829         versions of ATS had a `%{PATH}` directive, this will no longer work. Instead,
830         you want to use `%{CLIENT-URL:PATH}`.
831
832PORT     Port number.
833
834QUERY    URL substring from the ``?``, signifying the beginning of the query
835         parameters, until the end of the URL. Empty string if there were no
836         query parameters.
837
838SCHEME   URL scheme in use (e.g. ``http`` and ``https``).
839
840URL      The complete URL.
841======== ======================================================================
842
843As another example, a remap rule might use the `set-destination`_ operator to
844change just the hostname via::
845
846  cond %{HEADER:X-Mobile} = "foo"
847  set-destination HOST foo.mobile.bar.com [L]
848
849Requests vs. Responses
850======================
851
852Both HTTP requests and responses have headers, a good number of them with the
853same names. When writing a rule against, for example, the ``Connection`` or
854``Via`` headers which are both valid in a request and a response, how can you
855tell which is which, and how do you indicate to |TS| that the condition is
856specifically and exclusively for a request header or just for a response
857header? And how do you ensure that a header rewrite occurs against a request
858before it is proxied?
859
860Hook Conditions
861---------------
862
863In addition to the conditions already described above, there are a set of
864special hook conditions. Only one of these conditions may be specified per
865ruleset, and they must be the first condition listed. Which hook condition is
866used determines the context in which the ruleset is evaluated, and whether the
867other conditions will default to operating on the client request headers or the
868origin response (or cache response) headers.
869
870Hook conditions are written just like the other conditions, except that none of
871them take any operands::
872
873    cond %{<name>}
874
875Because hook conditions must be the first condition in a ruleset, the use of
876one forces the beginning of a new ruleset.
877
878.. graphviz::
879   :alt: header rewrite hooks
880
881   digraph header_rewrite_hooks {
882     graph [rankdir = LR];
883     node[shape=record];
884
885     Client[height=4, label="{ Client|{<p1>|<p2>} }"];
886     ATS[height=4, fontsize=10,label="{ {{<clientside0>Global:\nREAD_REQUEST_HDR_HOOK\nREAD_REQUEST_PRE_REMAP_HOOK|<clientside01>Remap rule:\nREMAP_PSEUDO_HOOK}|<clientside1>SEND_RESPONSE_HDR_HOOK}|ATS |{<originside0>SEND_REQUEST_HDR_HOOK|<originside1>READ_RESPONSE_HDR_HOOK} }",xlabel="ATS"];
887     Origin[height=4, label="{ {<request>|<response>}|Origin }"];
888
889     Client:p1 -> ATS:clientside0 [ label = "Request" ];
890     ATS:originside0 -> Origin:request [ label="proxied request" ];
891
892     Origin:response -> ATS:originside1 [ label="origin response" ];
893     ATS:clientside1 -> Client:p2 [ label = "Response" ];
894   }
895
896READ_REQUEST_HDR_HOOK
897~~~~~~~~~~~~~~~~~~~~~
898
899Evaluates as soon as the client request has been read, but prior to any further
900processing (including contacting origin servers or fetching objects from cache).
901Conditions and operators which adapt to matching or manipulating request or
902response entities (e.g. headers) depending on their context will all operate on
903the request variants when using this hook, as there is no response data yet.
904
905This hook is not available to remap rules.
906
907READ_REQUEST_PRE_REMAP_HOOK
908~~~~~~~~~~~~~~~~~~~~~~~~~~~
909
910For ruleset configurations provided via :file:`remap.config`, this forces their
911evaluation as soon as the request has been read, but prior to the remapping.
912For all context-adapting conditions and operators, matching will occur against
913the request, as there is no response data available yet.
914
915This hook is not available to remap rules.
916
917REMAP_PSEUDO_HOOK
918~~~~~~~~~~~~~~~~~
919
920Similar to `READ_REQUEST_HDR_HOOK`_, but only available when used in a remap
921context, evaluates prior to `SEND_REQUEST_HDR_HOOK`_ and allows the rewrite to
922evaluate as part of the remapping.
923
924Because this hook is valid only within a remapping context, for configuration
925files shared by both the global :file:`plugin.config` and individual remapping
926entries in :file:`remap.config`, this hook condition will force the subsequent
927ruleset(s) to be valid only for remapped transactions.
928
929SEND_REQUEST_HDR_HOOK
930~~~~~~~~~~~~~~~~~~~~~
931
932Forces evaluation of the ruleset just prior to contacting origin servers (or
933fetching the object from cache), but after any remapping may have occurred.
934
935READ_RESPONSE_HDR_HOOK
936~~~~~~~~~~~~~~~~~~~~~~
937
938Rulesets evaluated within this context will process only once the origin server
939response has been read, but prior to |TS| sending that
940response to the client.
941
942This is the default hook condition for all globally-configured rulesets.
943
944SEND_RESPONSE_HDR_HOOK
945~~~~~~~~~~~~~~~~~~~~~~
946
947Evaluates rulesets just prior to sending the client response, but after any
948cache updates may have been performed. This hook context provides a means to
949modify aspects of the response sent to a client, while still caching the
950original versions of those attributes delivered by the origin server.
951
952TXN_START_HOOK
953~~~~~~~~~~~~~~
954Rulesets are evaluated when |TS| receives a request and accepts it. This hook context indicates that a HTTP transaction is initiated and therefore, can only be enabled as a global plugin.
955
956TXN_CLOSE_HOOK
957~~~~~~~~~~~~~~
958
959Rulesets are evaluated when |TS| completes a transaction, i.e., after a response has been sent to the client. Therefore, header modifications at this hook condition only makes sense for internal headers.
960
961Affected Conditions
962-------------------
963
964The following conditions are affected by the hook context in which they are
965evaluated and will adjust using request or response entities automatically:
966
967- `HEADER`_
968
969- `METHOD`_
970
971- `URL`_
972
973Affected Operators
974------------------
975
976The following operators are affected by the hook context in which they are
977evaluated and will adjust modifying request or response entities automatically:
978
979- `add-header`_
980
981- `rm-header`_
982
983- `set-header`_
984
985Caveats
986=======
987
988Repeated Headers
989----------------
990
991Some headers may appear more than once in a request or a response. When this
992occurs, all values will be collapsed into a single comma-delimited string
993before the conditions see them. This avoids the problem of determining which
994header instance out of several a condition's rule will be applied to, but it
995may introduce unexpected behavior in your operands.
996
997For example, let us assume an origin response includes a header named ``X-Foo``
998which specifies a keyword of some sort. This header may appear zero or more
999times and we wish to construct a `HEADER`_ condition that can handle this.
1000
1001Condition A
1002~~~~~~~~~~~
1003
1004This condition will match using a direct equality operand::
1005
1006   cond %{HEADER:X-Foo} =bar
1007
1008Condition B
1009~~~~~~~~~~~
1010
1011This condition will match using an unanchored regular expression::
1012
1013   cond %{HEADER:X-Foo} /bar/
1014
1015Sample Headers
1016~~~~~~~~~~~~~~
1017
1018Both conditions A and B will match this response::
1019
1020   HTTP/1.1 200 OK
1021   Date: Mon, 08 Feb 2016 18:11:30 GMT
1022   Content-Length: 1234
1023   Content-Type: text/html
1024   X-Foo: bar
1025
1026Only condition B will match this response::
1027
1028   HTTP/1.1 200 OK
1029   Date: Mon, 08 Feb 2016 18:11:30 GMT
1030   Content-Length: 1234
1031   Content-Type: text/html
1032   X-Foo: bar
1033   X-Foo: baz
1034
1035That is because the `HEADER`_ condition will see the value of ``X-Foo`` as
1036``bar,baz``. Condition B will still match this because the regular expression,
1037being unanchored, finds the substring ``bar``. But condition A fails, as it is
1038expecting the value to be the exact string ``bar``, nothing more and nothing
1039less.
1040
1041Examples
1042========
1043
1044Remove Origin Authentication Headers
1045------------------------------------
1046
1047The following ruleset removes any authentication headers from the origin
1048response before caching it or returning it to the client. This is accomplished
1049by setting the hook context and then removing the cookie and basic
1050authentication headers.::
1051
1052   cond %{READ_RESPONSE_HDR_HOOK}
1053   rm-header Set-Cookie
1054   rm-header WWW-Authenticate
1055
1056Count Teapots
1057-------------
1058
1059Maintains a counter statistic, which is incremented every time an origin server
1060has decided to be funny by returning HTTP 418::
1061
1062   cond %{STATUS} =418
1063   counter plugin.header_rewrite.teapots
1064
1065Normalize Statuses
1066------------------
1067
1068For client-facing purposes only (because we set the hook context to just prior
1069to delivering the response back to the client, but after all processing and
1070possible cache updates have occurred), replaces all 4xx HTTP status codes from
1071the origin server with ``404``::
1072
1073   cond %{SEND_RESPONSE_HDR_HOOK}
1074   cond %{STATUS} >399
1075   cond %{STATUS} <500
1076   set-status 404
1077
1078Remove Cache Control to Origins
1079-------------------------------
1080
1081Removes cache control related headers from requests before sending them to an
1082origin server::
1083
1084   cond %{SEND_REQUEST_HDR_HOOK}
1085   rm-header Cache-Control
1086   rm-header Pragma
1087
1088Enable Debugging Per-Request
1089----------------------------
1090
1091Turns on |TS| debugging statements for a transaction, but only when a special
1092header is present in the client request::
1093
1094   cond %{READ_REQUEST_HDR_HOOK}
1095   cond %{CLIENT-HEADER:X-Debug} =supersekret
1096   set-debug
1097
1098Remove Internal Headers
1099-----------------------
1100
1101Removes special internal/development headers from origin responses, unless the
1102client request included a special debug header::
1103
1104   cond %{CLIENT-HEADER:X-Debug} =keep [NOT]
1105   rm-header X-Debug-Foo
1106   rm-header X-Debug-Bar
1107
1108Return Original Method in Response Header
1109-----------------------------------------
1110
1111This rule copies the original HTTP method that was used by the client into a
1112custom response header::
1113
1114   cond %{SEND_RESPONSE_HDR_HOOK}
1115   set-header X-Original-Method %{METHOD}
1116
1117Useless Example From Purpose
1118----------------------------
1119
1120Even that useless example from `Purpose`_ in the beginning of this document is
1121possible to accomplish::
1122
1123   cond %{INBOUND:LOCAL-PORT} =8090
1124   cond %{METHOD} =HEAD
1125   cond %{CLIENT-HEADER:Accept-Language} /es-py/ [NOT]
1126   cond %{STATUS} =304 [OR]
1127   cond %{RANDOM:500} >290
1128   set-status 403
1129
1130Add Cache Control Headers Based on Origin Path
1131----------------------------------------------
1132
1133This rule adds cache control headers to CDN responses based matching the origin
1134path.  One provides a max age and the other provides a "no-cache" statement to
1135two different file paths. ::
1136
1137   cond %{SEND_RESPONSE_HDR_HOOK}
1138   cond %{CLIENT-URL:PATH} /examplepath1/
1139   add-header Cache-Control "max-age=3600" [L]
1140   cond %{SEND_RESPONSE_HDR_HOOK}
1141   cond %{CLIENT-URL:PATH} /examplepath2\/examplepath3\/.*/
1142   add-header Cache-Control "no-cache" [L]
1143
1144Redirect when the Origin Server Times Out
1145-----------------------------------------
1146
1147This rule sends a 302 redirect to the client with the requested URI's Path and
1148Query string when the Origin server times out or the connection is refused::
1149
1150   cond %{SEND_RESPONSE_HDR_HOOK}
1151   cond %{STATUS} =502 [OR]
1152   cond %{STATUS} =504
1153   set-redirect 302 http://different_origin.example.com/%{CLIENT-URL:PATH} [QSA]
1154
1155Check for existence of a header
1156-------------------------------
1157
1158This rule will modify the ``Cache-Control`` header, but only if it is not
1159already set to some value, and the status code is a 2xx::
1160
1161   cond %{READ_RESPONSE_HDR_HOOK} [AND]
1162   cond %{HEADER:Cache-Control} ="" [AND]
1163   cond %{STATUS} >199 [AND]
1164   cond %{STATUS} <300
1165   set-header Cache-Control "max-age=600, public"
1166
1167Add HSTS
1168--------
1169
1170Add the HTTP Strict Transport Security (HSTS) header if it does not exist and the inbound connection is TLS::
1171
1172   cond %{READ_RESPONSE_HDR_HOOK} [AND]
1173   cond %{HEADER:Strict-Transport-Security} ="" [AND]
1174   cond %{INBOUND:TLS} /./
1175   set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
1176
1177This is mostly used by being attached to a remap rule that maps to a host known to support TLS. If
1178the parallel `OUTBOUND` supported is added then this could be done by checking for inbound TLS both
1179outbound TLS in the `SEND_REQUEST_HDR_HOOK`. However this technique may be used for a non-TLS
1180upstream if the goal is to require the user agent to connect to |TS| over TLS.
1181
1182Close Connections for draining
1183------------------------------
1184
1185When a healthcheck file is missing (in this example, ``/path/to/the/healthcheck/file.txt``),
1186add a ``Connection: close`` header to have clients drop their connection,
1187allowing the server to drain. Although Connection header is only available on
1188HTTP/1.1 in terms of protocols, but this also works for HTTP/2 connections
1189because the header triggers HTTP/2 graceful shutdown. This should be a global
1190configuration.::
1191
1192   cond %{SEND_RESPONSE_HDR_HOOK}
1193   cond %{ACCESS:/path/to/the/healthcheck/file.txt}    [NOT,OR]
1194   set-header Connection "close"
1195
1196Use Internal header to pass data
1197--------------------------------
1198
1199In |TS|, a header that begins with ``@`` does not leave |TS|. Thus, you can use
1200this to pass data to different |TS| systems. For instance, a series of remap rules
1201could each be tagged with a consistent name to make finding logs easier.::
1202
1203   cond %{REMAP_PSEUDO_HOOK}
1204   set-header @PropertyName "someproperty"
1205
1206(Then in :file:`logging.yaml`, log ``%<{@PropertyName}cqh>``)
1207