Content Rewrite Profile
Overview
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 via the 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 neither modifies client requests nor server headers. Headers may be modified using other features such as DataScripts or policies. For information about rewriting response headers, read this article.
In NSX Advanced Load Balancer (previously Avi Vantage), the only way to modify the server response is through the content rewrite profile. The content rewrite profile can be configured in the virtual service. The profile contains a list of key-value pairs to match and replace strings in the response body. The content rewrite allows you to configure either literal strings or variables that are:
-
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 to limit the search-replace to specific content types that should be modified. The
rewritable_content_ref
argument is used to specify a string group, which contains a list of eligible content types. By default, NSX Advanced Load Balancer configurations include the System-Rewritable-Content-Types string group, a list containing common text-based HTML MIME types such astext/html
,text/plain
, etc. 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.” Thus, with both pairs applied, a server response body of “abca” would be rewritten to “bccb.”
- 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 is 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 toSEARCH_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 may be replaced with new strings via 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 | The 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 arevs_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}.
Examples of Search & Replace Pairs
Example 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 |
+----------------------+-----------------+
Example 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} |
+----------------------+----------------------------------------------------------------+
CLI Configuration
In the CLI configuration shown below, notice these operative fields within the VirtualService
object named VS3:
content_rewrite.rewritable_content_ref
content_rewrite.rsp_rewrite_rules.enable
content_rewrite.rsp_rewrite_rules.index
content_rewrite.rsp_rewrite_rules.name
content_rewrite.rsp_rewrite_rules.pairs.search_string.type
content_rewrite.rsp_rewrite_rules.pairs.search_string.val
content_rewrite.rsp_rewrite_rules.pairs.replacement_string.type
content_rewrite.rsp_rewrite_rules.pairs.replacement_string.val
Note: [TAB][TAB]
in the configuration indicates pressing the tab key twice. By doing so the Avi shell
reveals the command-line syntax.
To configure the Content Rewrite Profile for vs-1
[admin:1234]: > configure virtualservice vs-1
Updating an existing object. Currently, the object is:
+------------------------------------+-----------------------------------------------------+
| Field | Value |
+------------------------------------+-----------------------------------------------------+
| uuid | virtualservice-eac16467-fcaa-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-fcaa-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----------------------------------------------------|