Caddy replace-response Module

repository·master·Indexed 41 days ago

https://github.com/caddyserver/replace-response

A Caddy handler (http.handlers.replace_response) that modifies response bodies on the fly using substring or regular expression replacements. It supports buffer and streaming modes, response matching via the match block, and provides the replace directive for Caddyfile configurations. Useful for injecting scripts, modifying content, or masking sensitive data in proxied responses.

Tokens
1.9K
Snippets
7
Records
8
Agent score
98%

What's inside replace-response

  1. How replace_response works

    master

    The replace_response module (module name: http.handlers.replace_response) performs substring or regular expression replacements on response bodies.

    It operates in two modes:

    1. Buffer mode (Default): Buffers the entire output to calculate the correct Content-Length header. This is less memory-efficient but ensures header accuracy.
    2. Streaming mode: Enabled via the stream option. This is more memory-efficient but may result in the Content-Length header being removed, as the resulting length is unknown when headers are written to the client.

    Important Constraints:

    • Compression: The handler cannot perform replacements on compressed content. If your backend (e.g., a reverse proxy) sends compressed responses, you must either decompress them before this handler runs or instruct the backend not to compress by setting the Accept-Encoding header to identity (e.g., header_up Accept-Encoding identity).
    • Regex Limits: Regular expression matches longer than 2kb will not be replaced.
  2. Handle compressed upstream responses

    master

    Because replace_response cannot process compressed content, you must ensure the upstream backend sends uncompressed data. The most effective way to do this when using reverse_proxy is to set the Accept-Encoding header to identity for upstream requests.

    reverse_proxy localhost:8080 {
        header_up Accept-Encoding identity
    }
  3. Configure replace_response via Caddyfile

    master

    The module provides the replace directive in the Caddyfile. By default, it is ordered to run after the encode directive, but you may need to adjust the global order if your setup requires a different sequence.

    Syntax: replace [<matcher>] [stream | [re] <search> <replace>] { ... }

    Options:

    • re: Indicates that the <search> argument is a regular expression rather than a substring.
    • stream: Enables streaming mode for higher efficiency.
    • match: Defines a response matcher to limit replacements to specific responses.
    • Block Syntax: You can define multiple replacements within a block {}.
    # Simple substring substitution
    replace Foo Bar
    
    # Regex replacement
    replace re "\s+foo(bar|baz)\s+" " foo $1 "
    
    # Streaming mode with a block
    replace stream {
    	Foo Bar
    	re "\s+foo(bar|baz)\s+" " foo $1 "
    	A B
    }
    
    # Using a matcher to target specific Content-Types
    replace {
    	match {
    		header Content-Type application/json*
    	}
    	Foo Bar
    }
  4. Configure replace_response via JSON

    master

    You can configure the replace_response handler in your Caddy JSON configuration using the replacements array. Each replacement object can specify either search (for substrings) or search_regexp (for regular expressions), along with the replace string. You can also enable stream mode and use a match object to restrict replacements to specific response types (e.g., specific Content-Type headers).

    {
    	"handler": "replace_response",
    	"replacements": [
    		{
    			"search": "Foo",
    			"replace": "Bar"
    		}
    	]
    }
  5. Configure the `replace` directive in a Caddyfile

    master

    The replace directive allows you to search for and replace strings (or regular expressions) within a response body. It can be used in a single-line format or a block format for more complex configurations.

    Syntax Options

    1. Streaming Mode: Use the stream keyword to enable streaming replacements. This prevents buffering the entire response body, which is more memory-efficient but may remove the Content-Length header.

    2. Regular Expressions: Prefix your search pattern with re to treat the search string as a regular expression.

    3. Standard String Replacement: Provide a <search> string followed by a <replace> string.

    4. Matching Blocks: Use a match block to restrict replacements to specific response criteria (e.g., matching a specific Content-Type).

    Examples

    Simple string replacement:

    replace "old-text" "new-text"

    Regular expression replacement:

    replace re "regex-pattern" "replacement"

    Streaming replacement with matching:

    replace stream {
        match {
            header Content-Type application/json*
        }
        "search-term" "replacement-term"
    }
    replace [stream | [re] <search> <replace>] {
        stream
        match {
            header Content-Type application/json*
        }
        [re] <search> <replace>
    }
  6. Use the `match` block to filter replacements

    master

    Within a replace block, you can define a match sub-block. This allows you to apply replacements only when the response meets certain criteria, such as matching specific headers. The match block uses standard Caddy response matcher syntax.

    Example of restricting replacement to JSON responses:

    replace {
        match {
            header Content-Type application/json*
        }
        "foo" "bar"
    }
    replace {
        match {
            header Content-Type application/json*
        }
        "foo" "bar"
    }
  7. Configure the replace_response handler

    master

    The replace_response handler (ID: http.handlers.replace_response) allows you to manipulate HTTP response bodies by performing substring or regular expression replacements.

    Configuration Options

    KeyTypeDescription
    replacements[]ReplacementA list of search-and-replace operations to perform.
    streamboolIf true, replacements are performed in a streaming fashion. This is more memory-efficient but will remove the Content-Length header because the final size is unknown without buffering.
    match*caddyhttp.ResponseMatcherAn optional matcher to determine which responses should undergo replacement based on status code or headers.

    Replacement Rules

    Each object in the replacements array must follow these rules:

    • You must provide either search (substring) or search_regexp (regular expression).
    • You cannot provide both search and search_regexp in a single replacement object.
    • The replace field is required and specifies the value to insert.
    {
      "replacements": [
        {
          "search": "old-text",
          "replace": "new-text"
        },
        {
          "search_regexp": "foo-(\\d+)",
          "replace": "bar-$1"
        }
      ],
      "stream": true
    }
  8. Define a Replacement object

    master

    A Replacement defines a single transformation rule. It supports two modes:

    1. Substring Replacement: Uses the search field to find an exact string match.
    2. Regex Replacement: Uses the search_regexp field to find matches via regular expression. This mode supports expansion (e.g., using $1 to refer to capture groups).

    Note: search and search_regexp are mutually exclusive.

    type Replacement struct {
    	Search       string `json: