Skip to content

Conversation

santysisi
Copy link
Contributor

@santysisi santysisi commented Aug 9, 2025

Q A
Branch? 6.4
Bug fix? yes
New feature? no
Deprecations? no
Issues Fix #61229
License MIT

Summary

Refine Vary header check to skip special handling of 'Accept-Language' when it's the only entry and '_vary_by_language' is true in CacheAttributeListener

Reason

Previously, the CacheAttributeListener was executed after the ResponseListener. When the set_locale_from_accept_language option is enabled in framework.yaml, the ResponseListener sets a Vary header on the response. Because CacheAttributeListener checks if a Vary header already exists before modifying it, its logic was being bypassed if it ran after the ResponseListener.

References

@carsonbot

This comment has been minimized.

@carsonbot carsonbot added this to the 7.4 milestone Aug 9, 2025
@santysisi santysisi changed the base branch from 7.4 to 6.4 August 9, 2025 00:47
@santysisi santysisi force-pushed the fix/cache-listener-priority branch from 9eec426 to 04f4315 Compare August 9, 2025 00:48
@santysisi
Copy link
Contributor Author

If we want to avoid changing the priority, we can add a condition to check whether the request has the _vary_by_language attribute set to true, and the response's Vary header contains only Accept-Language.

@nicolas-grekas
Copy link
Member

check whether the request has the _vary_by_language

let's do this, so that this won't interfere with app's listeners

@santysisi santysisi force-pushed the fix/cache-listener-priority branch 2 times, most recently from 8240e2d to 8085b7e Compare August 20, 2025 02:18
@santysisi santysisi changed the title [HttpKernel] Adjust priority of CacheAttributeListener to ensure Vary header is not skipped [HttpKernel] Refine Vary header check to ignore 'Accept-Language' when handled by request in CacheAttributeListener Aug 20, 2025
@santysisi santysisi force-pushed the fix/cache-listener-priority branch from 8085b7e to 4a186a5 Compare August 20, 2025 02:20
@santysisi santysisi changed the title [HttpKernel] Refine Vary header check to ignore 'Accept-Language' when handled by request in CacheAttributeListener [HttpKernel] Refine Vary header check to skip special handling of 'Accept-Language' when it's the only entry and '_vary_by_language' is true in CacheAttributeListener Aug 20, 2025
@santysisi santysisi force-pushed the fix/cache-listener-priority branch from 4a186a5 to 85c3d45 Compare August 20, 2025 02:27
@santysisi
Copy link
Contributor Author

santysisi commented Aug 20, 2025

status: needs work

There is a problem, i will try to resolve that problem tomorrow

@santysisi
Copy link
Contributor Author

status: needs review

The problem was resolved by sending the 'Accept-Language' header at the end

@Spomky
Copy link
Contributor

Spomky commented Aug 27, 2025

Many thanks @santysisi.
Looks good to me. I have just one question: how Vary: * is covered?

@santysisi
Copy link
Contributor Author

Thanks for the review! 🙌

Regarding Vary: *, I don't think it's currently covered.

I tested it locally, and it seems that when the response includes Vary: *, it still gets cached. I'm not sure if that's a bug or expected behavior, but it happens regardless of this PR, so it doesn't appear to be introduced by these changes.

@Spomky
Copy link
Contributor

Spomky commented Aug 28, 2025

I found in RFC9111 section4.1 the following sentence: A stored response with a Vary header field value containing a member "*" always fails to match..
So I understand Vary * should be treated as a relevant case and left untouched (no append).

May I suggest to add 2 test cases.

    yield 'vary * (no append) — vary_by_language=true' => [
        'responseVary'   => ['*'],
        'cacheVary'      => ['X-Foo'],
        'varyByLanguage' => true,
        'expectedVary'   => ['*'],
    ];

    yield 'vary * (no append) — vary_by_language=false' => [
        'responseVary'   => ['*'],
        'cacheVary'      => ['X-Foo'],
        'varyByLanguage' => false,
        'expectedVary'   => ['*'],
    ];

Edit: and hasRelevantVaryHeader to directly return true if * is present.

@santysisi
Copy link
Contributor Author

santysisi commented Aug 28, 2025

Hey, thanks a lot for your suggestions! The change has been made

Edit: I'm not sure if it's necessary to add the modification to the hasRelevantVaryHeader method to directly return true when * is present. With the current condition, I believe it already returns true in that case (your suggested test seems to confirm that behavior, thanks again for the suggestion! ❤️ ). But if you still think the change is needed, I'm happy to update it! 😄

@santysisi santysisi force-pushed the fix/cache-listener-priority branch from 34293e7 to ce29227 Compare August 28, 2025 22:21
Copy link
Contributor

@Spomky Spomky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. No additional comment.
Many thanks!

@cdaguerre
Copy link

This should also fix: #58663

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some nitpicking

@santysisi santysisi force-pushed the fix/cache-listener-priority branch from ce29227 to da81baf Compare September 5, 2025 13:26
@santysisi
Copy link
Contributor Author

Hi! Thanks a lot for your suggestions. I’ve made the changes you recommended.
Please let me know if there’s anything else needed.
Thanks again! ❤️

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I'm just wondering about these.

}

if (($vary = $response->getVary()) && \in_array('Accept-Language', $vary, true)) {
// Ensure 'Accept-Language' is included at the end of the Vary header
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary BTW?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary because when you have multiple requests with different headers listed in the Vary response header, if Accept-Language is not included in the final response, the cache will not be used for subsequent requests. Each request will be treated as unique, and the previously cached response won't apply.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my question was about the ordering: why do we need to reorder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my previous comment was incorrect. What I meant to say is:

The issue occurs if Accept-Language is not included at the end of the Vary header in the response , not if Accept-Language is missing from the response itself.

I haven't tested this with many servers yet, but I noticed this behavior using the Symfony local server (started via symfony server:start). I'm not sure whether it's an issue with Symfony itself (I don't think so), or something related to the local web server.

I'll try to test with other servers over the weekend and will update here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you have some reproducer I could run with the Symfony local server?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I’ll give it a try as soon as possible 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case you're up to having a look: ping @philpichet ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! I hope you're doing well 😊
I tried to reproduce the error yesterday and today, but I haven’t been able to 🤔
I’m not sure if it was something specific to my computer or environment at the time, but I'm now using the same machine and the same reproducer and everything is working fine.

I’m really not sure what happened. Sorry for the confusion 🙏

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@philpichet did some changes in #61518 on the topic, this might have fixed it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, got it! 😄 Thanks for the explanation, and big thanks to @philpichet for the fix ❤️

@santysisi santysisi force-pushed the fix/cache-listener-priority branch from da81baf to ff32a6e Compare September 8, 2025 21:18
@santysisi
Copy link
Contributor Author

Hi Nicolas, thanks a lot for your suggestions! ❤️
The changes have been made. Please let me know if there's anything else you'd like to adjust

@nicolas-grekas nicolas-grekas modified the milestones: 7.4, 6.4 Sep 9, 2025
@santysisi santysisi force-pushed the fix/cache-listener-priority branch from ff32a6e to 9537e1c Compare September 10, 2025 03:14
…cept-Language' when it's the only entry and '_vary_by_language' is `true` in `CacheAttributeListener`
@nicolas-grekas nicolas-grekas force-pushed the fix/cache-listener-priority branch from 9537e1c to fa2bcbe Compare September 15, 2025 14:23
@nicolas-grekas
Copy link
Member

Thank you @santysisi.

@nicolas-grekas nicolas-grekas merged commit cae30bb into symfony:6.4 Sep 15, 2025
10 of 11 checks passed
This was referenced Sep 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CacheAttributeListener overrides custom Vary headers when set_locale_from_accept_language is enabled

5 participants