HAProxy Enterprise Documentation 1.8r2

Rewrite Requests

Use the http-request configuration directives to rewrite HTTP requests. You can place it into a frontend, listen or backend section. Use them to rewrite requests sent from clients before HAProxy Enterprise forwards them to a backend server. The server will see something different than what the client sent.

Change the HTTP request method

Use http-request set-method to change the method (e.g. GET, POST, PUT) on a request before relaying it to a backend server. In the example below, we change GET requests made to the /login URL path to be POST requests:

frontend www
   bind :80
   acl url_login  path_beg -i /login
   http-request set-method POST if METH_GET url_login
   use_backend webservers

As another example, turn a GET into a POST if there is data in the body of the request by checking the Content-Length header:

frontend www
   bind :80
   acl body_has_data req.hdr_val(Content-Length) gt 0
   http-request set-method POST if METH_GET body_has_data
   use_backend webservers

Add a header

Use http-request add-header to add a new HTTP header to the a request before relaying it to a backend server. In the example below, we add an X-Forwarded-For header containing the client IP address:

frontend www
   bind :80
   http-request add-header X-Forwarded-For %[src]
   use_backend webservers

Going further, you can add a condition that first checks whether the X-Forwarded-For header eixsts and only add it if it does not:

frontend www
   bind :80
   acl h_xff_exists req.hdr(X-Forwarded-For) -m found
   http-request add-header X-Forwarded-For %[src] unless h_xff_exists
   use_backend webservers

Set a header

Use http-request set-header to add a new header or overwrite it if it already exists. In the example below, we overwrite any existing X-Forwarded-For header with one containing the client's IP address by referencing the src fetch method:

frontend www
   bind :80
   http-request set-header X-Forwarded-For %[src]
   use_backend webservers

In the next example, we change the Host header when traffic is sent to the maintenance backend:

backend maintenance
   http-request set-header Host maintenance.domain.com
   # server lines...

Delete a header

Use http-request del-header to remove an HTTP header from a request before relaying it to a backend server. In the example below, we delete any existing X-Forwarded-For header:

frontend www
   bind :80
   http-request del-header X-Forwarded-For
   use_backend webservers

In the next example, we delete all Cookie headers before sending the request to the backend servers, which in this case is a pool of cache (Varnish) servers:

backend b_caches
   acl at_least_one_cookie req.cook_cnt() gt 0
   http-request del-header Cookie if at_least_one_cookie
   # server lines...

Replace a header by using a regular expression

Use http-request replace-header to capture the entire value of a header by using a regular expression and then replace that value with a new one. You can use this technique to add data to a header, as in the example below, where we add a new IP address to the X-Forwarded-For header before relaying it to a backend server:

frontend www
   bind :80
   acl h_xff_exists req.hdr(X-Forwarded-For) -m found
   http-request replace-header X-Forwarded-For (.*) %[src],1 if h_xff_exists
   use_backend webservers

We use a regular expression capture group to capture the whole, existing value. Then, we add the new IP address to the beginning. We get the IP address with the src fetch method. This updates the string below:

X-Forwarded-For: 192.168.100.1, 10.0.0.2

... to become this one (considering the client's IP is 172.16.0.2):

X-Forwarded-For: 172.16.0.2, 192.168.100.1, 10.0.0.2

Replace part of a header by using a regular expression

Use http-request replace-value to capture part of a header's value by using a regular expression and then replace that part with a new one. In the example below, we capture the Host header's value up to the first colon. We then strip off the colon and port, if any:

frontend www
   bind :80
   http-request replace-value Host (.*):.* 1
   use_backend webservers

This updates the string below:

Host: www.domain.com:80, static.domain.com:8080

... into the following one:

Host: www.domain.com, static.domain.com

In cases where a header has multiple values, they are expected to be separated by a comma. HAProxy Enterprise looks for commas and applies the replacement to each value it finds.

Set the URL path

Use http-request set-path to change the requested URL path before relaying it to a backend server. Below, we change the URL path for JPG images so that it begins with /images/, but only if not already set:

frontend www
   bind :80
   acl p_ext_jpg path_end -i .jpg
   acl p_folder_images path_beg -i /images/
   http-request set-path /images/%[path] if !p_folder_images p_ext_jpg
   use_backend webservers

This changes the requests below:

GET /images/flower.jpg HTTP/1.1
GET /daisy.jpg HTTP/1.1

... into the following ones, respectively:

GET /images/flower.jpg HTTP/1.1
GET /images/daisy.jpg HTTP/1.1

Set the query string

Use http-request set-query to change the requested URL's query string. You can use the query fetch method to get the current query string value. Then use the regsub function to replace the first occurrence of a given substring. In the example below, we replace the string %3D with = in the query string. The third parameter is set to g, which applies the replacement to all occurences within the string:

frontend www
   bind :80
   http-request set-query %[query,regsub(%3D,=,g)]
   use_backend webservers

Youc an also use the urlp fetch method to get one of the query string's parameters. Below, we reorder the parameters in the query string to ensure that the user parameter comes before the group parameter:

frontend www
   bind :80
   http-request set-query user=%[urlp(user)]&group=%[urlp(group)]
   use_backend webservers

This changes the request below:

GET /test.php?group=admin&user=foo HTTP/1.1

...into the following one:

GET /test.php?user=foo&group=admin HTTP/1.1

Set the URI

Use http-request set-uri to rewrite the entire URI string of an HTTP request, including its HTTP scheme, authority, path, and query string. In the example below, we create one URL for HTTP and another for HTTPS when forwarding traffic to a proxy server:

backend b_squid
   acl https ssl_fc
   http-request set-uri https://%[req.hdr(Host)]%[path]?%[query] if https
   http-request set-uri http://%[req.hdr(Host)]%[path]?%[query] unless https
   # servers list...

This changes the request below:

GET /test.php?group=admin&user=foo HTTP/1.1
Host: www.domain.com

...into this one if the user connected over HTTP:

GET http://www.domain.com/test.php?group=admin&user=foo HTTP/1.1

...or into this one if the user connected over HTTPS:

GET https://www.domain.com/test.php?group=admin&user=foo HTTP/1.1

Rewriting anywhere in the request using regexes

The legacy statements reqrep and reqirep are still useful in cases not yet covered by the http-request directives.

  • reqrep applies a regex to each line of the request buffer in a case-sensitive manner.

  • reqirep is case insensitive.

reqrep  <search> <replace> [<cond>] reqirep <search> <replace> [<cond>]
reqirep  <search> <replace> [<cond>] reqirep <search> <replace> [<cond>]

This directive needs a regular expression to <search> the content to replace, a regular expression <replace> to apply the modification , and an optional <condition> to apply to this rule.

Note

HAProxy Enterprise uses PCRE compatible regular expressions.

Below, we replace /jpg/ with /images/ in the URL path:

frontend www
   bind :80
   reqrep ^([^ ]*) /jpg/(.*)     1 /images/2
   use_backend webservers

Next, we rewrite the Host header from static.domain.com to www.domain.com:

frontend www
   bind :80
   acl h_static hdr(Host) -m beg static.domain.com
   reqirep ^Host: static.domain.com      Host: www.domain.com if h_static
   use_backend webservers