Using placeholders/variables in handler

1. The problem I’m having:

I am using caddy, built using xcaddy, with the “non-standard” module replace-response to manipulate the content of the response. My goal is to find the phrase “localhost” and replace it with the value of the placeholder {http.request.host}, in my case an IPv4 address. Therefore I created this configuration

...
"handle":[
   {
      "handler":"replace_response",
      "replacements":[
         {
            "search":"localhost",
            "replace":"{http.request.host}"
         }
      ]
   }
]
...

As I can see in the response, this does not work. The replacement is done correctly, but instead of the expected value from the original request content "Hi, I replaced localhost" to e.g. "Hi, I replaced 192.168.172.36", the placeholder itself is placed: "Hi, I replaced {http.request.host}".

The same goes for a normal static_response. So I am not suspecting the module to be the problem.

2. Error messages and/or full log output:

2023/07/12 15:48:22.686 INFO    using provided configuration    {"config_file": "caddy-replace.json", "config_adapter": ""}
2023/07/12 15:48:22.687 INFO    admin   admin endpoint started  {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2023/07/12 15:48:22.687 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0xc0000fdf10"}
2023/07/12 15:48:22.687 INFO    tls     cleaning storage unit   {"description": "FileStorage:/home/user/.local/share/caddy"}
2023/07/12 15:48:22.687 INFO    http.log        server running  {"name": "example", "protocols": ["h1", "h2", "h3"]}
2023/07/12 15:48:22.687 INFO    tls     finished cleaning storage units
2023/07/12 15:48:22.687 INFO    autosaved config (load with --resume flag)      {"file": "/home/user/.config/caddy/autosave.json"}
2023/07/12 15:48:22.688 INFO    serving initial configuration

3. Caddy version:

user@ubuntu:~/Documents/caddy/xcaddy$ ./caddy version
v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

4. How I installed and ran Caddy:

Static self built binary via xcaddy
./caddy run --config caddy-replace.json

a. System environment:

Ubuntu

d. My complete Caddy config:

{
  "apps": {
    "http": {
      "servers": {
        "example": {
          "listen": [
            ":2015"
          ],
          "routes": [
            {
              "handle": [
                {
                  "handler": "replace_response",
                  "replacements": [
                    {
                      "search": "localhost",
                      "replace": "{http.request.host}"
                    }
                  ]
                },
                {
                  "handler": "static_response",
                  "body": "Hi, I replaced localhost"
                }
              ]
            }
          ]
        }
      }
    }
  }
}

5. Links to relevant resources:

Ok, after I just wrote all of this I had the idea of changing the sequence… Thank you for your indirect help, keep up the great work :smiley:

{
  "apps": {
    "http": {
      "servers": {
        "example": {
          "listen": [
            ":2015"
          ],
          "routes": [
            {
              "handle": [
                {
                  "handler": "static_response",
                  "body": "Hi {http.request.host}, I replaced localhost"
                },
                {
                  "handler": "replace_response",
                  "replacements": [
                    {
                      "search": "localhost",
                      "replace": "{http.request.host}"
                    }
                  ]
                }
              ]
            }
          ]
        }
      }
    }
  }
}

Hmm. My guess is that second one “works” only because you happen to be testing using http://localhost:2015.

The static_response handler being first would write the response and not invoke any further handlers.

The first one doesn’t work because placeholders are not evaluated after the response has been written; i.e. placeholders (dynamic content) are not expanded when performing replacements. This could be changed I guess, but my gut tells me it should be an opt-in to avoid surprises.

Hi, I have a similiar problem. Do you know if there is any other way to manipulate a response by using placeholders?

What are you trying to do exactly?

Hi @matt,
thank you for your answer! Sadly it is how you said. For example the following example still does not work:

{
  "apps": {
    "http": {
      "servers": {
        "example": {
          "listen": [
            ":2015"
          ],
          "routes": [
            {
              "handle": [
                {
                  "handler": "static_response",
                  "body": "Hi, I replaced should-be-replaced"
                },
                {
                  "handler": "replace_response",
                  "replacements": [
                    {
                      "search": "should-be-replaced",
                      "replace": "{http.request.host}"
                    }
                  ]
                }              
              ]
            }
          ]
        }
      }
    }
  }
}

Depending on the order of the two handler the response is one of the following:

  1. Hi, I replaced {http.request.host}
  2. Hi, I replaced should-be-replaced

My usecase for what I need this feature in the end is, that I want to manipulate responses of an reverse proxied application. So in the example the static_response would be a reverse_proxy . It does not support different hostnames, so links in the UI are wrong. It would be awesome to have caddy to be able to help here!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.