CacheCow icon indicating copy to clipboard operation
CacheCow copied to clipboard

Observe the `DefaultVaryHeaders` when creating the cache key

Open 0xced opened this issue 2 years ago • 3 comments

If the server replies with a Vary header then the DefaultVaryHeaders are not used when computing the cache key.

The new IncludeRangeHeaderInCacheKey test demonstrates this issue and ensure it's fixed.

This is a followup to #268

0xced avatar Apr 15 '22 09:04 0xced

Hi,

I am not going to close this one ye. But if the server itself tells us what Vary headers are, then what good are default vary headers? The default vary headers are there as a starting point.

The point is the server is the definitive authority in declaring the parameters of its resources. Now if you are saying this is a means of dealing with Bad Servers is another thing but let me understand what we are trying to fix/improve.

aliostad avatar Apr 15 '22 12:04 aliostad

If I understood the code correctly, the existing code varyHeaders = serverResponse.Headers.Vary.Select(x => x).ToArray() are always replacing either there is varyHeaders or not. DefaultVaryHeaders are not being used as it is being replaced.

Therefore, in my understanding at least if (serverResponse.Headers.Vary != null)
should be if (serverResponse.Headers.Vary != null && serverResponse.Headers.Vary.Count() > 0)

prajon84 avatar Sep 22 '22 00:09 prajon84

Let me review, thanks for raising again. I might have overlooked it.

aliostad avatar Sep 22 '22 07:09 aliostad

Let me review, thanks for raising again. I might have overlooked it.

Any update on this @aliostad

prajon84 avatar Oct 03 '22 20:10 prajon84

I promise tonight, sorry!

aliostad avatar Oct 12 '22 18:10 aliostad

The issue (before this pull request) is that if you want to explicitly always include a header in the cache key (e.g. the Range header) and the server returns a Vary header, then what was explicitly configured is overridden by the content of the Vary header.

This pull request fixes this. Have a look at the IncludeRangeHeaderInCacheKey: if you run this test without the fix applied in CachineHandler.cs then the test doesn't pass because the Range header is not part of the cache key.

Also, the condition testing whether a Vary header exists in the response was incorrect: serverResponse.Headers.Vary != null is always true. The correct way to test if a Vary header is present in the response is if (serverResponse.Headers.Vary?.Any() ?? false).

0xced avatar Oct 12 '22 19:10 0xced

OK apologies for not reviewing it earlier.

The behaviour is the one that is intended by deign. The server is indeed the ultimate authority to define its vary headers. There is a reason what you pass in is called DefaultVaryHeaders, it is merely the default which can be used in absence of server headers. As such your pull request cannot be accepted.

Now if you are saying that the server sends wrong headers and you need a means to deal with it then that is a different thing.

Can you please confirm if this was the case?

aliostad avatar Oct 12 '22 20:10 aliostad

By the way as for the if (serverResponse.Headers.Vary != null) you are right that is a bug - but not one that hurts much. So let's clarify the situation and decide what to do.

aliostad avatar Oct 12 '22 21:10 aliostad

OK apologies for not reviewing it earlier.

No need to apologise, you get to choose your own pace!

Now if you are saying that the server sends wrong headers and you need a means to deal with it then that is a different thing. Can you please confirm if this was the case?

I'm not familiar enough with RFC 7234 to assess whether it's wrong but yes, that's the case: I'd like to be able to choose a request header to be part of the cache key no matter what the server replies. Granted, re-using the DefaultVaryHeaders property and hijacking its intended purpose was probably not the best idea.

I personally like Cashew design with its ICacheKeyStrategy interface. Would you mind a similar approach? Or would you prefer to introduce a new property for the purpose of always including a header in the cache key?

0xced avatar Oct 12 '22 23:10 0xced

No I think you have acted quite naturally.

Looking at the decision taken by Cashew, I must say it might be OK for them, but for me is too broad. There are issues such as someone might try to use the response stream and messing up with it (especially now that the ASP.NET have imposed restrictions on when something can be accessed and all). I would probably go for passing a copy of the headers. But that is perhaps just taste.

Anyway, it is perhaps not ideal but you can create your own IVaryHeaderStore which when returns the list of header names, adds the headers you are interested in on top based on the URL (obviously after checking if they are not already there). Unfortunately TryGet is not virtual but you can achieve the same with minimal code with composition (based on InMemoryVaryHeaderStore) instead of inheritance.

Meanwhile I will have a think about this where it can best fit - but cannot guarantee when can be done although it does not necessarily mean never!

Thanks for your interest. Keep it open for conversations but once you are OK please close it.

aliostad avatar Oct 13 '22 07:10 aliostad

At least we can fix the bug that we know, hence created the PR, because it gives confidence to move ahead in use of this library further.

prajon84 avatar Oct 18 '22 20:10 prajon84

OK, I have merged. Thanks a lot.

aliostad avatar Oct 18 '22 20:10 aliostad