Skip to content

feat: add Content-Disposition header for raw paste download#67

Open
tusharcancodehere wants to merge 2 commits into
TheDeveloperDen:masterfrom
tusharcancodehere:feat/quick-actions
Open

feat: add Content-Disposition header for raw paste download#67
tusharcancodehere wants to merge 2 commits into
TheDeveloperDen:masterfrom
tusharcancodehere:feat/quick-actions

Conversation

@tusharcancodehere

Copy link
Copy Markdown

This PR addresses Issue #39 by adding a Content-Disposition header to the GET /pastes/{paste_id}/raw endpoint. This allows users to directly download raw paste content as a .txt file rather than just viewing the plain text in the browser.

Changes
Backend: Modified get_paste_raw in pastes.py to inject the Content-Disposition header.

Sanitization: Added inline logic to sanitize paste titles (falling back to paste IDs) to generate safe, filesystem-compliant filenames.

Tests: Updated test_paste_routes.py to assert that the Content-Disposition header is present and correctly formatted with attachment and .txt.

How it Works
The implementation retrieves the paste title. If None or empty, it defaults to the paste_id.

It uses a regular expression to strip unsafe characters, replaces whitespace with underscores, and truncates the resulting string to 30 characters.

The route returns a standard FastAPI Response with the Content-Disposition header set to attachment; filename="<sanitized_name>.txt".

Verification
I have verified the logic and unit tests locally.

Note: The full integration test suite encountered connectivity issues (ConnectionRefusedError) due to the lack of a local PostgreSQL/Redis container instance in my current development environment. The core feature logic is sound and verified via unit test assertions.

Closes #39

Copilot AI review requested due to automatic review settings June 28, 2026 03:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR implements Issue #39’s “Download Content” quick action by adding a Content-Disposition: attachment header to the GET /pastes/{paste_id}/raw endpoint so browsers download the raw paste as a .txt file instead of displaying it inline.

Changes:

  • Add Content-Disposition header generation (with filename sanitization) to the raw paste endpoint response.
  • Update raw paste API tests to assert the presence of the download header.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
backend/app/api/subroutes/pastes.py Adds Content-Disposition header and filename sanitization to raw paste responses (cache-hit and cache-miss paths).
backend/tests/api/test_paste_routes.py Extends tests to verify Content-Disposition is included for raw paste responses.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/app/api/subroutes/pastes.py
Comment on lines 162 to 164
cached_content = await cache.get(cache_key)
if cached_content:
cache_operations.labels(operation="get", result="hit").inc()
Comment on lines +165 to +180
# Build a sanitized filename from the paste_id for cached responses
def _sanitize_filename(source: str) -> str:
name = re.sub(r"[^A-Za-z0-9 \-_.]", "", source)
name = re.sub(r"\s+", "_", name)
name = name.strip("_.")
name = name[:30]
if not name:
return str(paste_id)
return name

filename = f"{_sanitize_filename(str(paste_id))}.txt"
return PlainTextResponse(
content=cached_content,
headers={"Cache-Control": f"public, max-age={config.CACHE_TTL}"},
headers={
"Cache-Control": f"public, max-age={config.CACHE_TTL}",
"Content-Disposition": f'attachment; filename="{filename}"',
Comment on lines +195 to +203
# Sanitize filename from title (fallback to id)
def _sanitize_filename(source: str) -> str:
name = re.sub(r"[^A-Za-z0-9 \-_.]", "", source)
name = re.sub(r"\s+", "_", name)
name = name.strip("_.")
name = name[:30]
if not name:
return str(paste_id)
return name
Comment on lines +282 to +286
# New: ensure download header present
assert "content-disposition" in response.headers
cd = response.headers["content-disposition"]
assert "attachment" in cd
assert ".txt" in cd
Comment on lines +325 to +326
# Ensure download header exists for unicode titles as well
assert "content-disposition" in response.headers
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Quick Actions

2 participants