Match by response header

Is it possible to match by response content-type?

I want to match all html files, but with file server you can’t rely on the path ending with .html.

I could exclude all my others assets

not {
  path *.jpg
  ...
}

But that’s more prone to error.

No, that’s not possible. Matching is on requests, once a response has begun to be written, it’s too late.

I don’t think I understand what you’re trying to do though. Could you elaborate? What do the requests look like (paths/headers and expected responses)?

I’ll back up a bit so I can get your opinion on the whole.

My experience with working on websites for clients where a CMS causes minor page updates, is to use Cache-Control: max-age=0 on the HTML content to get consistent behavior in terms of what a user sees. I’ve been criticised in terms of performance for this being heavy-handed, but once the end users have cached the page, sometimes things don’t behave the way the documentation says. This is just my experience.

I hash all my assets (images, css, js), so I can set different headers for those explicitly. Something like

@assets {
  path *.jpg
  path *.gif
  path *.js
  path *.css
}
header @assets cache-control max-age=1000

But I want to set specific headers for the html files. I’m static generating my sites most of the time, then using file_server to serve them. So I can’t match them using path *.html.

Maybe I could

@content {
  not @assets
}
header @content cache-control max-age=0

So to clarifiy, I’m working on cache rules by matching certain requests and setting headers. I’m trying to find the best way to make this work without unintended results.

I was thinking about matching on the response content type to get around the fact that .html paths don’t always end with .html, but I get that it’s too late once the response exists.

Maybe you could use path_regexp to match any path that doesn’t end in a file extension? Something like /[^\.]+.*$ possibly (i.e. where no . appears between a / and the end of the path). Not sure if that’ll work, just throwing an idea out there.

I don’t know what all the request paths in your app might include, so I don’t have any other good suggestions. You may need to collect a list of all the paths your site can serve then figure out a rule that can exclude the right things.

You can control response headers based on properties of the response using the JSON config. The Caddyfile doesn’t support response matchers, and they’re usable only in very specific situations. See the “require” property of the “response” object in the headers handler:

(Scroll up from that anchor and you can see the JSON structure.)

Something like this:

{
	"handler": "headers",
	"response": {
		"set": {
			"cache-control": ["max-age=31536000"]
		},
		"require": {
			"headers": {
				"content-type": ["text/html"]
			}
		}
	}
}

path_regexp is for smart people :wink:

I guess I’ll draw a line in the sand and set the max-age something like this

(asset-paths) {
	path *.bmp
	path *.jpg
	path *.png
	path *.svg
	path *.gif
	path *.pdf
	path *.css
	path *.js
}
(cache) {
	@content {
		not {
			import asset-paths
		}
	}
	header @content cache-control max-age=0
	@assets {
		import asset-paths
	}
	header @assets cache-control max-age=31536000
}

These things tend to change over time. Thanks for your input.

@matt

so something like

response: {
  require: {
    header: {
      'Content-Type': 'text/html'
    }
  }
}

I’ll give that a try

(not real json)

…but if I can solve it with Caddyfile I will… faster to work with

Well, kind of; I gave you an example in my post, please refer to that and the documentation.

But it won’t do the same thing, just know that.

You can make that all one line btw:

(asset-paths) {
	path *.bmp *.jpg *.png *.svg *.gif *.pdf *.css *.js
}
1 Like

The end result for me is getting a cache-control header on the content I want. If someone reads this thread looking for a way to control response headers based on other response headers, maybe it’ll be good for them.

1 Like

Thanks for the feedback guys.

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