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