caddyserver/cache-handler

Set custom headers in cache config

Closed this issue · 17 comments

Hi,

Thanks for your work!

Not an issue/bug, but I'm playing around with the cache handler module and figured it would be really great (for my use case) to set custom headers (not cache-related headers) to the cache service reqs.

(For what it's worth, I think that even a regular Caddy matcher that would only apply to the cache-related requests and can set a custom header would work)

Is there anything to make than happen somehow?

Thanks!

Hey @stpp2 what do you want to do? Can you give me a request/response to illustrate your mind?

@darkweak thank you so much for the reply!

It's a little non-standard, but basically just pass through a new header for any req/res that goes between Caddy and the cache storer service. I'm planning to later use those headers to distribute the cache on multiple instances.

Just want to set something like this: (if it was via the Caddyfile)
header Custom-Header "My value"

If it helps to be more specific, I really just want to apply the headers when a cache key is stored in the storer. For reference that's probably when the debug log level returns something like this:

 {"level":"debug","ts":12345,"logger":"http.handlers.cache","msg":"Stored the key abc123 in the REDIS provider"}

I don't think I really understand the question. But do you mean you want the cache to store a extra header in addition to the one your upstream would have written? What does your entire config look like? It matters to what we can suggest as a solution.

Hi @francislavoie,

Thanks for jumping in!

Basically just like you are able to set custom headers to the upstream/downstream servers with Caddy on specific routes - I was wondering if the same can be achieved with the cache stores.

I don't have anything in my Caddyfile that attempts that at the moment - so not much relevant config to share.

Essentially I'm just using an external Redis server, and I want to set a header for whenever Caddy is communicating with that server - without affecting the actual upstream/downstream headers for regular traffic.
(It would be even nicer if I could set different headers for reads and writes but no big deal.)

I don't know if that's even possible, but there is some communication between Caddy and the cache upstream so i've figured there might be a way to set that up.

Thanks again!!

I don't follow. Redis doesn't speak HTTP, so why would it care about headers?

Do you mean like "only include a response header to the client when it was cached" or something like that? Can you be more specific?

I'm also not sure if you mean request headers or response headers, and on which leg of it you mean (the proxy half, or the client half).

Seeing an example config would help here. Hypotheticals are hard without something concrete to discuss.

Oh, that's a very valid point with Redis and HTTP.

I suppose the only include a response header to the client when it was cached is indeed what I'm after. I'm only interested in the response header. (probably only to the client half rather than the proxy half but whichever can work would be great)

And sorry for not posting code references - It's just still very hypothetical and I don't really have any code around that part. (Besides standard Caddy and cache handler config which works great)

@stpp2 Do you want to know when it's stored or when it serves cached responses?

When it's stored, ideally.

What is the use case? To have some metrics?
You can detect if it has been stored reading the Cache-Status HTTP response header that should have the stored directive.

Hmm I haven't thought of using the stored directive, I'll explore that soon - thanks!
The use case for adding custom headers here is to use those headers to sync the cache across multiple distributed instances.

How do you sync the cache between multiple instances? Why not using a redis cluster that can be accessed by all your instances?

I've hit some other blockers with the redis cluster implementation and I've found a way to replicate writes/purges via the headers.

Either way I'll try to move forward with adding a matcher on the stored directive, then adding the custom downstream response header from that.

Really appreciate all your help @darkweak (and @francislavoie) !!

I'll close this for now and report back if I have any further insights.

Quick followup @darkweak / @francislavoie -

Not sure if this is a core Caddy thing or a Cache-Handler issue, but I can't seem to match anything in the Cache-Status header?
Even if it is deferred:

:443 {
  cache
  @cache_status header Cache-Status *
  handle @cache_status {
    header >Test 123
  }
  respond "Hello World!"
}

Not sure where to look into next but any other matcher that does not rely on the cache-status header does seem to work.

Well first of all your matcher is wrong, you're missing the matcher type (header) but either way it's a request matcher so it matches request headers, not response headers. Also, directive order matters, it would need to check the response headers after they're written. You might be able to use the new intercept directive to have some behaviour that matches response headers. Need to make sure intercept runs before cache because it sets up a response intercept that checks the response on the way back up the middleware chain.

Oh, really sorry for missing the header matcher! (updated the message above.. fwiw I did use the header matcher type when testing, just a typo in here)
And also tried with intercept but I don't think it's working -

:443 {
  intercept {
    @status_header header Cache-Status *
    handle_response @status_header {
      header test 123
    }
  }

  cache

  respond "Hello World!"
}

I've tried it also after the cache directive, but it didn't work

Like I said, directive order. cache is ordered before rewrite but intercept is after. See https://caddyserver.com/docs/caddyfile/directives#directive-order and

httpcaddyfile.RegisterDirectiveOrder(moduleName, httpcaddyfile.Before, "rewrite")

You need to wrap both in a route, or set intercept to be higher, or cache to be after intercept.

Ah, yes! That was it.
Setting the directive globally to order cache after intercept got it working. (not sure if that has any side effects but will check)

Thanks for the help @francislavoie !!