The Response Body Injection (RBI) module provides a filter that can be used to manipulate an HTML document received in an HTTP response from a backend server. It can be used to insert content into any of the following HTML elements:

  • html

  • head

  • title

  • body

Install the Response Body Injection module

  1. Install the RBI module: apt install hapee-1.5r2-lb-htmldom (or yum install depending on your platform of choice).

  2. In the global section of your configuration, add the following line:

    module-load hapee-lb-htmldom.so
  3. Add a filter htmldom directive to a listen, frontend, or backend section to begin injecting content. Here is an example:

    filter htmldom mode strict head-append '<script type="text/javascript" defer="defer">window.addEventListener("load", function() {var alinks = document.getElementsByTagName("a");var acount = alinks.length;for (var i=0; i < acount; i++) {alinks[i].href = alinks[i].href.replace("http://","https://");}})</script>'

    It injects the following markup into the head of the HTML document, which replaces http:// with https:// in links:

    <script type="text/javascript" defer="defer">
        window.addEventListener("load", function() {
            var alinks = document.getElementsByTagName("a");
            var acount = alinks.length;
    
            for (var i=0; i < acount; i++) {
                alinks[i].href = alinks[i].href.replace("http://","https://");
            }
        })
    </script>

Filter Parameters

The filter htmldom directive instructs HAProxy to inject content into an HTML document. It can be declared only once per proxy section. Its syntax is:

filter htmldom [mode <mode>] <action> <content>

The following table describes each argument:

Directive

Description

mode <mode>

Sets the HTML parser. It can be set to:

relaxed (default)

Faster and intended for use cases in which it is known what to expect in the server response (the HTML document is simple).

strict

Uses libxml2 and performs more parsing checks. This is recommended in cases where the document may contain many Javascript declarations or if there may be broken tags.

<action> (required)

Identifies the HTML element into which new content will be injected. It is applied to the first matching element. Valid actions are:

html-prepend

Insert content at the beginning of the <html> element.

html-append

Insert content at the end of the <html> element.

head-prepend

Insert content at the beginning of the <head> element.

head-append

Insert content at the end of the <head> element.

title-prepend

Insert content at the beginning of the <title> element.

title-append

Insert content at the end of the <title> element.

body-prepend

Insert content at the beginning of the <body> element.

body-append

Insert content at the end of the <body> element.

<content> (required)

The HTML content to inject into the response from a server. It is a log-format string.

Caveats

The filter is automatically deactivated if various conditions are met. They include:

  • the request method is HEAD

  • both request and response are HTTP/1.1, but the Transfer-Encoding header value is not chunked and Content-Length is not known

  • the response contains compressed content (the Content-Encoding header is present)

  • the response contains the no-transform value in the Cache-Control header (no transformations or conversions should be made)

  • the Content-Type header value is other than text/html

The filter also modifies the response in the following ways:

  • To ensure that the response will not be compressed, all occurrences of the Accept-Encoding header are removed from the incoming request.

  • In order to modify the response, all occurrences of the Content-Length header are removed. If the message is HTTP/1.1 or above, the Transfer-Encoding header is set to chunked.

When inserting a large amount of content into a response, it is important to set tune.bufsize to the appropriate size.