Chaining middleware

With caddy v1.0.3, is it possible to chain middlewares?

I’ve seen a comment for the Caddyfile that nested blocks are not allowed but the ServeHTTP signature and the AddMiddleware method are designed to let one middleware call another and then deal with the result.

The http.upload middleware is of particular interest to me. It can take a POST and create local files based on its configuration but is not designed to return a redirect or any indication to the user other than a return code like 201 or 204. It does return the http status codes per the ServeHTTP signature without writing them out so it is a higher level that writes the return code. How would an upper layer of middleware be
provisioned with a Caddyfile to write a body response?

Hi @FrankReh, welcome to the Caddy community!

Chaining middlewares is how Caddy works at a core level. Every middleware is designed to be called by the preceding middleware until one of them writes an actual response.

That said, you don’t have that much fine control over this chain from the Caddyfile. The order of execution is set here: https://github.com/caddyserver/caddy/blob/a23f707268b9f6a3613356ab426155969bb2320b/caddyhttp/httpserver/plugin.go#L626-L704

And each directive in that list, that is configured for the site in question, runs in order.

I don’t think it does pass it off to the next middleware. To do that, it has to call a specific function, see for example in the header directive:

I think that the upload middleware is in fact writing the response itself, ending the middleware chain.

If you wanted to write a response body, you’d have to modify the upload middleware itself, or write your own upload middleware that functions the way you want it to.

1 Like

Thanks for the confirmation. Look forward to seeing v2 evolve.

Whitestrake’s answer is very good.

I’ll add: v2 lets you customize the order of the middleware chain.

Will v2 allow a middleware to be written that defines its own plugin interface - so plugins to plugins could be written?

The upload functionality for example begs at least two questions, what to do with the byte slices once they are taken from the request body, and how to respond with a response body. Both could be answered by other plugins that conformed to the interfaces that such a new upload middleware module defined.

The idea that a portion of the configuration can be passed to a module for it to unmarshal and do with as it needs is very nice.

Yes. This is how all of Caddy 2 is designed: plugins of plugins of plugins, but registration is centralized with Caddy’s core, all their state and config is managed for you (and each plugin validates its own config, etc). I think it’s a really neat architecture which I will be talking about at the Go meetup here in a couple months.

See the docs here: https://github.com/caddyserver/caddy/wiki/v2:-Writing-a-Module (“module” roughly == “plugin”) - it’s basically just a LoadModule("name", rawConfig) and then a type assertion to the interface you expect that module to satisfy. This is how many existing v2 already work, like the reverse proxy, the encode middleware, and the TLS app.

So, Caddy knows about all “plugins of plugins” (“guest modules” – see the docs I linked, which explain these terms) but the “plugins” which load them (“host modules”) know how to access them and use them.