Associating a content rewrite profile with an HTTP(S) virtual service enables modification of HTML content within the body of a server response. A content rewrite policy can be created and attached to a virtual service through the VMware Avi Load Balancer CLI or using an API.
A content rewrite profile specifies one or more strings to be searched for within the body of the server response. The profile modifies neither the client requests nor the server headers. Headers can be modified using other features such as DataScripts or policies. For more information about rewriting response headers, see HTTP Response Policy under Virtual Service Policies.
In VMware Avi Load Balancer, the only way to modify the server response is through the content rewrite profile. The content rewrite profile can be configured as a sub-field in the virtual service. The profile contains a list of key-value pairs to match and replace strings in the response body. Content-rewrite allows you to configure literal strings or variables that are either:
Defined in the DataScript using
avi.http.set_reqvar()
.Defined internally for common virtual service or HTTP request parameters like
$vs_name
,$vs_ip
,$http_host
,$req_id
, and so on.Defined as capture groups of the regex that matched some data in the response
Best Practices for Searching
Content rewriting can be computationally expensive. Therefore, it is recommended limiting the search-replace to specific content types that must be modified. The rewritable_content_ref argument is used to specify a string group, which contains a list of eligible content types. By default, the VMware Avi Load Balancer configurations include the System-Rewritable-Content-Types string group, a list containing common text-based HTML MIME types such as text/html, text/plain, and so on. This ensures that base64-encoded content, such as images are not inspected when performing search-replace operations.
Search is conducted throughout the entire body of the eligible server response, with no length limit.
If a search string is found in multiple locations within a single HTTP response body, it will be replaced in all those locations.
Multiple search-replace pairs can be specified in a single content rewrite profile. All are actively and independently applied. The content replacement is not recursive. For example, consider a profile having a search-replace of “a” with “b”, and a second search-replace of “b” with “c”. Only pre-existing instances of “b” in the server response will be replaced with “c". Instances of “a” that are replaced with “b” are not recursively checked and replaced with “c”. So, with both pairs applied, a server response body of
abca
would be rewritten tobccb
.Searches are not case sensitive.
Search String Types
There are four types of search strings within the response body:
- Literal String
-
Exactly matches the string value to search and replace
- Avi Variable
-
There are predefined variables that can be used that contain the values of HTTP headers (like Host, User-Agent, or Cookie) or specific parameters of the request or Virtual Service (like VS IP, VS name, request ID, etc.).
The value of the variable will be the string used for searching.
If the variable does not exist, then there is no data to search for and the associated replacement string will not be seen in the rewritten response.
Set the type to SEARCH_AVI_VAR, and then input the name of the variable to use.
- DataScript Variable
-
DataScript can be used to generate a search string.
Create and attach a new DataScript to the virtual service.
It must use the function to specify the new value. For example, a call to
avi.http.set_reqvar(“key1”, “value1”)
creates a variable named key1 and sets it to value1.In the content rewrite profile, set the type to
SEARCH_DATASCRIPT_VAR
and the variable to key1.With each HTTP request, the DataScript can uniquely set the DataScript variable to key1 and assign it a new value (e.g., value1, value2, and so on), based on the script logic.
The value set for this DataScript variable will be the string used to search for.
- Regular Expression
-
Configure a PCRE compatible regular expression as a search string.
This will allow you to search for all matches to this regular expression in the response body.
The regular expression may contain capture groups that could be used in the corresponding replacement string.
Replacement String Types
The found strings can be replaced with new strings through one of three methods used to specify the new string.
- Literal String
-
Basic text strings to be used for replacing data found in response bodies.
- Avi Variable
-
Set the type to AVI_VAR, and then input the name of the variable to use.
The value of the variable will be used to replace the found string.
If the variable does not exist, then the value used in the replacement string will be empty, effectively removing the search string from the response.
The list of variables are as follows:
Name |
Description |
---|---|
client_ip |
The source (client’s) IP address (V4 or V6) |
client_port |
The client port from which the request was sent |
client_userid |
The username sent in the client request |
host |
The server header value |
http_cookie |
The cookie header values |
http_host |
The host header value |
http_referer |
The referer header value |
http_user_agent |
The user-Agent header value |
http_via |
The via header value |
http_x_forwarded_for |
The X-Forwarded-For header values |
horizon_blast_port |
he Horizon server port for Blast protocol traffic |
horizon_l7_port |
The Horizon server port for primary protocol traffic |
horizon_pcoip_port |
The Horizon server port for PCOIP protocol traffic |
poolname |
The Name of the pool in use |
request_id |
The request ID |
- DataScript Variable
-
DataScript variables can also be used as the replacement string. The content rewrite profile will replace the searched string with null data, effectively removing the searched string from the response if:
No DataScript has been assigned to the virtual service
The variable is set to a different name
No variable has been set.
- Combination String
-
Allows for crafting a string that can be a mix of literal strings and variables.
This allows for adding text along with variable names that can be parsed into their respective value.For instance, the virtual service IP and port are
${vs_ip}:${vs_port}
.Here the variables are
vs_ip
andvs_port
and will be replaced with the virtual service’s IP address and port respectively.The variables are determined by the variable name within ${}.
If the variable is not defined, you can use the empty string in its place.
Combination Strings can also access regex captures groups using the variables ${1} ,${2} ,…, ${n}.
Search and Replace Pairs
1. Replace all instances of the user-agent in the response with “Avi”.
+----------------------+-----------------+ | Field | Value | +----------------------+-----------------+ | pairs[1] | | | search_string | | | type | SEARCH_AVI_VAR | | val | http_user_agent | | replacement_string | | | type | LITERAL_STRING | | val | Avi | +----------------------+-----------------+
2. Replace the address and port in the server response with the VS IP and VS port.
+----------------------+------------------------------------------------+ | Field | Value | +----------------------+------------------------------------------------+ | pairs[1] | | | search_string | | | type | SEARCH_REGEX | | val | (address:)[\s]*(?:[0-9]{1,3}\.) | | | {3}[0-9]{1,3}[\s]* | | replacement_string | | | type | COMBINATION_STRING | | val | ${1}${vs_ip} | | pairs[2] | | | search_string | | | type | SEARCH_REGEX | | val | (port:)[\s]*\d{1,5}[\s]* | | replacement_string | | | type | COMBINATION_STRING | | val | ${1}${vs_port} | +----------------------+------------------------------------------------+
Configuring Content Rewrite
In the following terminal, notice these operative fields within the virtual service object named VS3:
content_rewrite.rewritable_content_ref
content_rewrite.request_rewrite_enabled
content_rewrite.response_rewrite_enabled
content_rewrite.rsp_match_replace_pair.match_string
content_rewrite.rsp_match_replace_pair.replacement_string.type
content_rewrite.rsp_match_replace_pair.replacement_string.val
We have inserted [TAB][TAB] in the below terminal to indicate the user’s typing of 2 tabs, causing the shell to reveal command-line syntax.
[admin:1234]: > configure virtualservice vs-1 Updating an existing object. Currently, the object is: +------------------------------------+----------------------------------+ | Field | Value | +------------------------------------+----------------------------------+ | uuid | virtualservice-eac16467-fca-4e31-| | |bc0a-5fb3e6bdef19 | | name | vs-1 | | enabled | False | | services[1] | | | port | 80 | | enable_ssl | False | | port_range_end | 80 | | enable_http2 | False | | horizon_internal_ports | False | | is_active_ftp_data_port | False | |----------------------------Truncated Output---------------------------| | content_rewrite | | | rewritable_content_ref | System-Rewritable-Content-Types | | sideband_profile | | | sideband_max_request_body_size | 1024 bytes | | vsvip_ref | vs-1-VsVip | | use_vip_as_snat | False | | error_page_profile_ref | Custom-Error-Page-Profile | | traffic_enabled | True | | allow_invalid_client_cert | False | | vh_type | VS_TYPE_VH_SNI | +------------------------------------+----------------------------------+ [admin:1234]: virtualservice> content_rewrite [admin:1234]: virtualservice:content_rewrite> where Tenant: admin Cloud: Default-Cloud +------------------------+---------------------------------+ | Field | Value | +------------------------+---------------------------------+ | rewritable_content_ref | System-Rewritable-Content-Types | +------------------------+---------------------------------+ [admin:1234]: virtualservice:content_rewrite> rsp_rewrite_rules New object being created [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> enable [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> index 1 [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> name "rewrite-rule-1" [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> where Tenant: admin Cloud: Default-Cloud +--------+----------------+ | Field | Value | +--------+----------------+ | name | rewrite-rule-1 | | enable | True | | index | 1 | +--------+----------------+ [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> pairs New object being created [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> search_string type search_literal_string val ABC [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:search_string> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> replacement_string type literal_string val XYZ [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:replacement_string> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> where Tenant: admin Cloud: Default-Cloud +--------------------+-----------------------+ | Field | Value | +--------------------+-----------------------+ | search_string | | | type | SEARCH_LITERAL_STRING | | val | ABC | | replacement_string | | | type | LITERAL_STRING | | val | XYZ | +--------------------+-----------------------+ [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> pairs New object being created [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> search_string type search_literal_string val httpvar [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:search_string> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> replacement_string type avi_var val http_host [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:replacement_string> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> where Tenant: admin Cloud: Default-Cloud +--------------------+-----------------------+ | Field | Value | +--------------------+-----------------------+ | search_string | | | type | SEARCH_LITERAL_STRING | | val | httpvar | | replacement_string | | | type | AVI_VAR | | val | http_host | +--------------------+-----------------------+ [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> pairs New object being created [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> search_string [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:search_string> type search_regex [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:search_string> val "()[\s]*(?:https://)?[\w\.-]*:443[\s]*()" [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:search_string> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> replacement_string [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:replacement_string> type combination_string val[admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:replacement_string> val "${1}https://${uag_fqdn}:${horizon_l7_port}${2}" [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs:replacement_string> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> where Tenant: admin Cloud: Default-Cloud +--------------------+--------------------------------------------------+ | Field | Value | +--------------------+--------------------------------------------------+ | search_string | | | type | SEARCH_REGEX | | val | (UAG:)[\s]*(?:https://)?[\w\.-]*:443[\s]* | | replacement_string | | | type | COMBINATION_STRING | | val | ${1}https://${uag_fqdn}:${vs_port} | +--------------------+--------------------------------------------------+ [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules:pairs> save [admin:1234]: virtualservice:content_rewrite:rsp_rewrite_rules> save [admin:1234]: virtualservice:content_rewrite> where Tenant: admin Cloud: Default-Cloud +------------------------+----------------------------------------------+ | Field | Value | +------------------------+----------------------------------------------+ | rewritable_content_ref | System-Rewritable-Content-Types | | rsp_rewrite_rules[1] | | | name | rewrite-rule-1 | | enable | True | | index | 1 | | pairs[1] | | | search_string | | | type | SEARCH_LITERAL_STRING | | val | ABC | | replacement_string | | | type | LITERAL_STRING | | val | XYZ | | pairs[2] | | | search_string | | | type | SEARCH_LITERAL_STRING | | val | httpvar | | replacement_string | | | type | AVI_VAR | | val | http_host | | pairs[3] | | | search_string | | | type | SEARCH_REGEX | | val | (UAG:)[\s]*(?:https://)?[\w\.-]*:443[\s]* | | replacement_string | | | type | COMBINATION_STRING | | val | ${1}https://${uag_fqdn}:${vs_port} | +------------------------+----------------------------------------------+ [admin:1234]: virtualservice:content_rewrite> save [admin:1234]: virtualservice> save +------------------------------------+----------------------------------+ | Field | Value | +------------------------------------+----------------------------------+ | uuid | virtualservice-eac16467-fca-4e31-| | |bc0a-5fb3e6bdef19 | | name | vs-1 | | enabled | False | | services[1] | | | port | 80 | | enable_ssl | False | | port_range_end | 80 | | enable_http2 | False | | horizon_internal_ports | False | | is_active_ftp_data_port | False | |-----------------------------Truncated Output--------------------------| | content_rewrite | | | rewritable_content_ref | System-Rewritable-Content-Types | | rsp_rewrite_rules[1] | | | name | rewrite-rule-1 | | enable | True | | index | 1 | | pairs[1] | | | search_string | | | type | SEARCH_LITERAL_STRING | | val | ABC | | replacement_string | | | type | LITERAL_STRING | | val | XYZ | | pairs[2] | | | search_string | | | type | SEARCH_LITERAL_STRING | | val | httpvar | | replacement_string | | | type | AVI_VAR | | val | http_host | | pairs[3] | | | search_string | | | type | SEARCH_REGEX | | val | (UAG:)[\s]*(?:https://)? | | |[\w\.-]*:443[\s]* | | replacement_string | | | type | COMBINATION_STRING | | val |${1}https://${uag_fqdn}:${vs_port}| |-----------------------------Truncated Output--------------------------|