Custom plugin guidance: rewrite URI based on POST body

I’d like to make a custom plugin that does something kind of like this contrived example:

  • Examines the POST body
  • Does some sort of dynamic lookup based on the POST body
  • Uses the value of the lookup to determine the URL to write to.

Here’s a very contrived example:

  • Requests come in as POST to /foo w/ JSON payload {"destination": 42, ...other json.. }
  • Plugin intercepts this as lookups up destination 42 in it’s backend
  • In this case let’s say looking up destination 42 returns /bar
  • Request is rewritten to /bar keeping everything else about the request intact.

I think the route I want to look at is writing a custom middleware that acts like http.handlers.rewrite but before I dig too much deeper figured I’d post here and see if anyone knows of any examples that do something kind of similar.


You can just define a variable in your module (see the var handler for how that works, and read its source code), then you can just use Caddy’s existing rewrite handler like this:

rewrite * {vars.your_destination}

Awesome thanks I’ll take a look!

Ok cool, I also came across caddy-ext/requestbodyvar at master · RussellLuo/caddy-ext · GitHub which shows how and where to call Replacer.Map to load the placeholder value. Thanks! That combined w/ your rewrite suggestion should work!

This seems to be working perfectly, thanks!

For anyone else trying something similar here’s what my Caddyfile looks like:

route /foo* {
   # register my module that creates the request_body_destination variable

   rewrite /foo {request_body_destination}

   reverse_proxy /foo/bar { ... }

My request_body_destination_var module looks very much like caddy-ext/requestbodyvar at master · RussellLuo/caddy-ext · GitHub here’s the gist of the ServeHTTP:

func (v *RequestBodyDestinationVar) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
	// TODO: actually parse the payload and construct a dynamic route
	route := "/foo/bar"

	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
	repl.Set("request_body_destination", route)
        // set a response header just so I know this is working
	w.Header().Set("X-Debug-Destination", route)
	return next.ServeHTTP(w, r)
1 Like