Execution order of 'handle' blocks

I have a doubt on the use of ‘handle’.

Are the following two blocks of code equivalent? [As in, will they produce the same effect?]

handle /api/* {
	reverse_proxy 127.0.0.1:9720}
handle /api/blah/* {
	reverse_proxy 127.0.0.1:9730}
handle /api/blah/* {
	reverse_proxy 127.0.0.1:9730}
handle /api/* {
	reverse_proxy 127.0.0.1:9720}

or is the second handle in the first example (api/blah) redundant, as Caddy will evaluate the handle blocks in the order in which it finds them, instead of going to the most specific (longest) matcher first?

If, on the other hand, it does reorder them (and execute the handle with the most specific/longest matcher first), perhaps we should mention it in this article – Composing in the Caddyfile

The sense I got from the article otherwise is that it won’t reorder the handles on the basis of specificity and will execute them as it finds them, and in that way, handle is different from most other directives such as reverse proxy and header. Is that the correct understanding?

Well first of all, you have a syntax error – you must place the } on a new line. Whitespace is important in the Caddyfile.

But to answer your question, the Caddyfile adapter has sorting logic, first according to the directive order:

Then according to the length (actual string length, regardless of contents) of the path matchers, for same-directives. Any named matcher without a path matcher will always be sorted after a path matcher, and no matcher at all (i.e. match anything) will always come last.

As a special case, handle and handle_path are sorted at the same priority because under the hood they’re actually both the same, with handle_path just having an implicit path rewrite as its first action.

All that is specific to the Caddyfile adapter. The actual JSON config will execute request handlers in the order they appear, so you have more control over the order, if you need it. But the Caddyfile is meant as a UX layer, so we involve a bit of magic to save users from their own mistakes. It works 99% of the time, but there are edgecases; and in those cases there are workarounds available, or you can just use JSON directly.

So, in short, the ‘/api/blah/’ handle will be considered before /api/, even if it’s written second?

Yep. That’s correct.

Ok, one more thing

what if both are equal in length?

For example, one has a path matcher ‘api’ and another handle has ‘bpi’ . Will ‘api’ be considered first because alphabetically it has a higher priority, or will the order in which they are written come into play?

So, in case I’m confused about which one will execute first, I can try converting the Caddyfile into the JSON format and see which one comes first?

If they’re equal length but different, then the order won’t really matter, because they can’t both match at the same time. But it’ll just be “luck” which one will come first, I think. Or maybe it’ll keep them in the order they were written if they’re equal. Depends on the internal Go sort function. But either way it doesn’t matter.

Yes exactly, with the caddy adapt --pretty command.

1 Like

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