pulp / pulp/pulpcore

Add content negotiation to content app for JSON distribution representation

Open
#7,887 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Feature
Dominant language
Python
Stars
598
Forks
168
Avg merge
1d 4h
Merged PRs (30d)
86

Description

Problem Statement

The pulpcore content app has no content negotiation — the Accept request header is never inspected. When a client requests a distribution's base path or content path, it always gets an HTML directory listing or a binary file stream. There is no standardized way for a client to request a JSON representation of a distribution or its contents.

Some plugins have worked around this with custom URL patterns (e.g., PythonDistribution.content_handler serves JSON at pypi/*/json), but this is ad-hoc and plugin-specific. There is no common mechanism that all distribution types can use.

Proposed Solution

1. Content negotiation in the content app

Handler._match_and_stream() should inspect the Accept request header. When a client sends Accept: application/json, the handler should call a new method on the resolved distribution to produce a JSON response instead of serving files or HTML directory listings.

2. New Distribution extension method

Add a method to the base Distribution model that plugin distributions can override:

class Distribution(MasterModel):
    def content_handler_json(self, path):
        """
        Return a JSON representation of the distribution's contents at the given path.
        
        Plugin distributions override this to provide content-type-specific data.
        Return None to fall through to default behavior.
        """
        return None
3. Default behavior

The base Distribution could provide a minimal default JSON response with distribution metadata (name, base_path, repository info). Plugin distributions would enrich this with content-type-specific data. For example:

  • Maven: list MavenPackage content (GAV coordinates, POM metadata)
  • RPM: list packages by NEVRA
  • Python: list Python packages by name/version
  • File: list files by relative path
4. Integration with existing content_handler

The content negotiation check should happen in _match_and_stream (handler.py) after resolving the distribution but before calling the existing content_handler. When Accept: application/json is present:

  1. Call distribution.content_handler_json(rel_path)
  2. If it returns a response, serve it
  3. If it returns None, fall through to existing behavior

This preserves backward compatibility — distributions that don't override the method behave exactly as before.

Use Cases

  • CLI tools and automation scripts can query distribution contents programmatically
  • Web UIs can fetch structured data about available packages without screen-scraping HTML
  • Plugin distributions get a standardized extension point instead of inventing ad-hoc JSON endpoints

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Handler._match_and_stream in handler.py and the base Distribution model, then trace how the existing content_handler resolves and streams content. Define the JSON negotiation and fallback behavior around content_handler_json, including the extension point for plugin distributions. Done means application/json requests can receive a distribution response while unsupported distributions retain their existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.