ALOHA 7.0


HTTP rewriting

Note

In order to rewrite HTTP protocol in HAProxy, you need to know and understand regular expressions.

HTTP rewriting is the technic which allows HAProxy to change content on the fly while data is exchanged between a client and a server.
It is often used to keep compatibility between old and new URLs, to turn user friendly URLs into ones CMS friendly, etc…

In HAProxy, rewriting HTTP request or response relies on two types of configuration directives:

  • HTTP rules: http-request and http-response
  • legacy, but still useful, reqrep / reqirep and rsprep / rspirep

Note

It is recommended to use the http rules format version

Warning

Be careful and keep in mind that rewriting HTTP may have side impacts on web application

Rewriting HTTP requests

In this mode, HAProxy rewrites requests sent by the clients before they are forwarded to the server.

Rewriting HTTP headers

Set the request method

HAProxy can change the HTTP method of the request sent by the client using the following directive:

http-request set-method <fmt> [<condition>]

This directive expects the following parameters:

Examples:

  1. change GET to POST on the /login url of the website:

    acl url_login  path_beg -i /login
    http-request set-method POST if METH_GET url_login
    
  2. turn a GET method into a POST if there is data in the body of the request:

    acl request_data req.hdr_val(Content-Length) gt 0
    http-request set-method POST if METH_GET request_data
    

Add a header to the request

HAProxy can add a Header field into the request sent by the client using the following directive:

http-request add-header <name> <fmt> [<condition>]

This directive expects the following parameters:

Examples:

  1. Add a X-Forwarded-For containing the client IP address:

    http-request add-header X-Forwarded-For %[src]
    
  2. Add a X-Forwarded-For containing the client IP address if none were already present:

    acl h_xff_exists req.hdr(X-Forwarded-For) -m found
    http-request add-header X-Forwarded-For %[src] unless h_xff_exists
    

Set a header in the request

HAProxy can set a Header field into the request sent by the client using the following directive:

http-request set-header <name> <fmt> [<condition>]

Note

set-header removes first any header existing field matching <name>

This directive expects the following parameters:

Examples:

  1. Erase any existing X-Forwarded-For and creates a new one containing the client IP address:

    http-request set-header X-Forwarded-For %[src]
    
  2. Change the Host header field when traffic is redirected to the maintenance backend:

    backend maintenance
     http-request set-header Host maintenance.domain.com
    

Delete a header in the request

HAProxy can delete a Header field from the request sent by the client using the following directive:

http-request del-header <name> [<condition>]

This directive expects the following parameters:

  • <name> : the name of the header we want to delete
  • <condition> (optional) : a condition to apply this rule

Examples:

  1. Delete any existing X-Forwarded-For header field

    http-request del-header X-Forwarded-For
    
  2. Delete all cookies before sending a request to the cache (Varnish / nginx) servers:

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

Replace all the values of a header field

Note

HTTP RFC specifies that the comma ‘,’ character is a Header field delimiter.
It means that

X-Forwarded-For: 192.168.0.1, 10.0.0.1

is the equivalent to

X-Forwarded-For: 192.168.0.1
X-Forwarded-For: 10.0.0.1

HAProxy can update a Header field value while considering whole line, regardless of commas

http-request replace-header <name> <match-regex> <replace-fmt> [<condition>]

This directive expects the following parameters:

  • <name> : the name of the header we want to update
  • <match-regex> : a regex to match the content we want to update
  • <replace-fmt> : a log format variable for the new value
  • <condition> (optional) : a condition to apply this rule

Examples:

  1. Update a X-Forwarded-For header to add the client IP at the beginning of the list:

    acl h_xff_exists req.hdr(X-Forwarded-For) -m found
    http-request replace-header X-Forwarded-For (.*) %[src],1 if h_xff_exists
    

    The example above turn the following string:

    X-Forwarded-For: 192.168.100.1, 10.0.0.2
    

    into the following one, considering the client IP is 172.16.0.2:

    X-Forwarded-For: 172.16.0.2, 192.168.100.1, 10.0.0.2
    

Replace a particluar value of a header field

Note

HTTP RFC specifies that the comma ‘,’ character is a Header field delimiter.
It means that

X-Forwarded-For: 192.168.0.1, 10.0.0.1

is the equivalent to

X-Forwarded-For: 192.168.0.1
X-Forwarded-For: 10.0.0.1

HAProxy can update a Header field value while considering comma character as a separator. It means the update will be applied to each value, individually.

http-request replace-value <name> <match-regex> <replace-fmt> [<condition>]

This directive expects the following parameters:

  • <name> : the name of the header we want to update
  • <match-regex> : a regex to match the content we want to update
  • <replace-fmt> : a log format variable for the new value
  • <condition> (optional) : a condition to apply this rule

Examples:

  1. Update each Host header to remove the colon and port, if any:

    http-request replace-value Host (.*):.* 1
    

    The example above turn the following string:

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

    into the following one:

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

Rewriting HTTP URLs

Set the URL path

HAProxy can rewrite the path of the HTTP request:

http-request set-path <fmt> [<condition>]

This directive expects the following parameters:

Examples:

  1. change URL path for JPG images, to get them from a /images/ directory on the server, only if not already set:

    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
    

    The example above turn the following requests:

    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

HAProxy can rewrite the query string of the HTTP request:

http-request set-query <fmt> [<condition>]

This directive expects the following parameters:

Examples:

  1. replaces %3D with “=” in the query string

    http-request set-query %[query,regsub(%3D,=,g)]
    
  2. Reorder the parameters in the query string, to ensute the user parameter will be before the group one:

    http-request set-query user=%[urlp(user)]&group=%[urlp(group)]
    

    The example above turn the following request:

    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

HAProxy can rewrite the whole URI string of the HTTP request. This includes HTTP scheme, authority, path and query string:

http-request set-uri <fmt> [<condition>]

This directive expects the following parameters:

Examples:

  1. Create a full URL 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
    

    The example above turn the following request:

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

    into the following one if the user got connected over HTTP on HAProxy:

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

    or into the following one if the user got connected over HTTPs on HAProxy:

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

    Note

    in such case, you should turn GET into CONNECT as well.

Rewrite anywhere in the request using regexes

The legacy statements reqrep and reqirep are still usefull for the cases not yet covered by the http-request rules.

reqrep applies a regex to each line of the request buffer in a case sensitive manner. reqirep does the same, but is case insensitive:

reqrep  <search> <replace> [<cond>]
reqirep <search> <replace> [<cond>]
  • <search> : a regular expression to search the content to be replaced
  • <replace> : a regular expression to apply the modification
  • [<condition>] (optional) : a condition to apply this rule

Note

HAProxy uses PCRE compatible regular expressions.

The links below provide some quick introduction to the PCRE syntax:

Examples:

  1. replace jpg folder by images in the HTTP URL path:

    reqrep ^([^ ]*) /jpg/(.*)     1 /images/2
    
  2. rewrite the Host header from static.domain.com to www.domain.com

    acl h_static hdr(Host) -m beg static.domain.com
    reqirep ^Host: static.domain.com      Host: www.domain.com if h_static
    

Rewriting HTTP responses

Add a header in the response

HAProxy can add a Header field into the response answered by the server using the following directive:

http-response add-header <name> <fmt> [<condition>]

This directive expects the following parameters:

Examples:

  1. Add a header field X-Via containing the client name of the current HAProxy server processing the traffic:

    http-response add-header X-Via %[env(HOSTNAME)]
    
  2. Add a header field containing the backend and server name which processed the response:

    http-response add-header X-App-Server %b/%s
    

    This will insert the following header:

    X-App-Server: b_app/appsrv1
    

Set a header in the response

HAProxy can set a Header field into the response answered by the server using the following directive:

http-response set-header <name> <fmt> [<condition>]

Note

set-header removes first any existing header field matching <name>

This directive expects the following parameters:

Examples:

  1. Hide the header Server set by the server:

    http-response set-header Server webserver
    

Delete a header in the response

HAProxy can delete a Header field from the response sent by the server using the following directive:

http-response del-header <name> [<condition>]

This directive expects the following parameters:

  • <name> : the name of the header we want to delete
  • <condition> (optional) : a condition to apply this rule

Examples:

  1. Delete some headers set by Varnish:

    backend b_static
     http-response del-header X-Varnish
     http-response del-header X-Varnish-Cache
     http-response del-header X-Varnish-Server
     http-response del-header X-Cache
    

Replace all the values of a header field

Note

HTTP RFC specifies that the comma ‘,’ character is a Header field delimiter.
It means that

X-Forwarded-For: 192.168.0.1, 10.0.0.1

is the equivalent to

X-Forwarded-For: 192.168.0.1
X-Forwarded-For: 10.0.0.1

HAProxy can update a Header field value while considering whole line, regardless of commas:

http-response replace-header <name> <match-regex> <replace-fmt> [<condition>]

This directive expects the following parameters:

  • <name> : the name of the header we want to update
  • <match-regex> : a regex to match the content we want to update
  • <replace-fmt> : a log format variable for the new value
  • <condition> (optional) : a condition to apply this rule

Examples:

  1. Update the cookie JSESSIONID set by the server with the Secure flag if the client side connection is ciphered:

    acl https          ssl_fc
    acl secured_cookie res.cook(JSESSIONID),lower -m sub secure
    http-response replace-header Set-Cookie (.*) 1; Secure if https !secured_cookie
    

    Note

    we assume the server sets up a single cookie

Replace a particluar value of a header field

Note

HTTP RFC specifies that the comma ‘,’ character is a Header field delimiter.
It means that

X-Forwarded-For: 192.168.0.1, 10.0.0.1

is the equivalent to

X-Forwarded-For: 192.168.0.1
X-Forwarded-For: 10.0.0.1

HAProxy can update a Header field value while considering comma character as a separator. It means the update will be applied to each value, individually.

http-response replace-value <name> <match-regex> <replace-fmt> [<condition>]

This directive expects the following parameters:

  • <name> : the name of the header we want to update
  • <match-regex> : a regex to match the content we want to update
  • <replace-fmt> : a log format variable for the new value
  • <condition> (optional) : a condition to apply this rule

Examples:

  1. Insert a Secured flag on each cookie setup by the server

    http-response replace-value Set-Cookie (.*) 1; Secure
    

Rewrite anywhere in the response using regexes

The legacy statements rsprep and rspirep are still usefull for the cases not yet covered by the http-rspuest rules.

rsprep applies a regex to each line of the request buffer in a case sensitive manner. rspirep does the same, but is case insensitive:

rsprep  <search> <replace> [<cond>]
rspirep <search> <replace> [<cond>]
  • <search> : a regular expression to search the content to be replaced
  • <replace> : a regular expression to apply the modification
  • [<condition>] (optional) : a condition to apply this rule

Note

HAProxy uses PCRE compatible regular expressions.

The links below provide some quick introduction to the PCRE syntax:

Examples:

  1. rewrite the Location from static.domain.com to www.domain.com when required:

    acl h_static res.hdr(Location) -m sub static.domain.com
    rspirep ^Location: http://static.domain.com(.*)      Location: http://www.domain.com1