Skip to content

hosting: TenantMiddleware drops existing Vary header lines, including Vary: *, when it adds its own #423

Description

@antosubash

Problem

TenantMiddleware._vary_sender (framework/hosting/simple_module_hosting/_tenant.py) merges the resolver's vary names into the response with

headers = MutableHeaders(scope=message)
merged = merge_vary(headers.get("vary"), vary)
if merged is not None:
    headers["vary"] = merged

MutableHeaders.get returns only the first Vary header line, and the assignment then deletes every other Vary line. A response that carries more than one Vary field loses all but the first. If a later line is Vary: *, the wildcard disappears and is replaced by a finite list, so a shared cache treats a deliberately uncacheable response as cacheable. #367 promised that existing entries are kept and Vary: * is left untouched.

Reproduction

Found by independent QA on #384 and still on main at 7db61a0. A downstream app returns two header lines, Vary: Accept and Vary: *, and the resolver answers TenantResolution("acme", "header", ("Host",)). The response leaves the middleware with one line:

before: [(b"vary", b"Accept"), (b"vary", b"*")]
after:  [(b"vary", b"Accept, Host")]   # wildcard gone

A smaller issue in the same helper: merge_vary("Accept, accept", ("Host",)) returns Accept, accept, Host. Case-insensitive duplicates already present in the input are kept, and only appended names are de-duplicated.

Expected

  • Every existing Vary line is read (headers.getlist("vary"), split on commas), merged, and written back as one line.
  • If any existing line contains *, the response is left exactly as it was.
  • Existing tokens are de-duplicated case-insensitively, keeping the first spelling.

Tests to add

  • Two Vary lines (Accept + Accept-Language) plus resolver ("Host",) → one line Accept, Accept-Language, Host.
  • Vary: Accept + Vary: * → unchanged, * preserved.
  • merge_vary("Accept, accept", ("Host",)) → Accept, Host.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions