Skip to content

Add ETag / If-None-Match conditional-request support to the PyPI JSON Metadata API #1338

Description

@dkliban

Summary

The PyPI JSON Metadata API ({package}/json/, {package}/{version}/json/, served by MetadataView) sends no cache-validation headers and does not support conditional requests. This means every client and edge cache must re-download the full JSON body on each request, even when nothing has changed. Add ETag / If-None-Match304 Not Modified support to match pypi.org.

Motivation — pypi.org behavior

I compared against pypi.org (Warehouse). Both its JSON and Simple JSON endpoints standardize on ETag as the cache validator:

Endpoint ETag Last-Modified If-None-Match→304 Cache-Control
/pypi/{pkg}/json ❌ never sent max-age=900, public
/simple/{pkg}/ ❌ never sent max-age=600, public

Warehouse never emits Last-Modified; it uses ETag. (pypi.org also answers If-Modified-Since with a 304, but that is the Fastly CDN layer synthesizing it from the cached object — the origin validator is the ETag.)

Current state in pulp_python

  • The Simple API (SimpleView.list/retrieve) already matches Warehouse: it emits ETag and honors If-None-Match→304 via @method_decorator(condition(etag_func=_etag_func)), with the same Cache-Control: max-age=600, public. ✅
  • The JSON MetadataView has no ETag, no Cache-Control, and no conditional-request handling. ❌ ← this is the gap.

Proposed change

  • Apply the same condition(etag_func=_etag_func) decorator (and a cache_control decorator) to MetadataView.retrieve, reusing the existing repo-version-based _etag_func in pulp_python/app/pypi/views.py.
  • Add functional tests mirroring test_simple_cache_etag_conditional_request for the JSON Metadata endpoint (matching ETag → 304, bogus ETag → 200).

Related / out of scope

pulpcore #7929 (pulp/pulpcore#7929) adds Last-Modified / If-Modified-Since / 304 to the content app, which serves package file downloads — pulp_python inherits that automatically. Adding Last-Modified to the PyPI metadata views is not required for pypi.org parity (Warehouse doesn't send it) and is left out of this issue.

Files

  • pulp_python/app/pypi/views.py
  • pulp_python/tests/functional/api/test_simple_cache.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions