Skip to content

bug fix: serve /report error responses as text/html (not octet-stream) - #41

Merged
ejanalysis merged 2 commits into
mainfrom
fix-report-error-content-type
Jun 30, 2026
Merged

bug fix: serve /report error responses as text/html (not octet-stream)#41
ejanalysis merged 2 commits into
mainfrom
fix-report-error-content-type

Conversation

@ejanalysis

Copy link
Copy Markdown
Contributor

Problem

The /report endpoints declare #* @serializer contentType list(type = "application/octet-stream") so finished report bytes (HTML or PDF) pass through untouched. But their endpoint-level error paths returned a bare HTML string, which the octet-stream serializer then labeled Content-Type: application/octet-stream. Result: a 400 error page downloads as a file instead of rendering in the browser.

(Found by review during the #36/#40 merge — pre-existing, not introduced by that work.)

Fix

Add a small html_error(res, status, message) helper that sets the status, an explicit text/html Content-Type, and the body, then returns the response object — the same pattern report_response() already uses for successful HTML reports, which bypasses the octet-stream serializer.

Route every GET/POST /report validation error and the ejamit_interface() tryCatch failures through it. The tryCatch now returns the condition and is checked with inherits(result, "error") (instead of the old is.character(result) on a returned string).

Scope: /report only. /data and /query use the default JSON serializer and were already fine; report_response()'s own fileextension validation already set text/html.

Verified locally

Case Result
GET /report lat/lon count mismatch 400 text/html
GET /report buffer>15 (exercises the tryCatch path) 400 text/html
POST /report empty body 400 text/html
GET /report?fips=10001&fileextension=html (success) 200 text/html (unchanged)
GET / redirect / /__docs__/ 302 / 200 (no regression)

🤖 Generated with Claude Code

The /report endpoints use `@serializer contentType
list(type="application/octet-stream")` so finished report bytes pass
through untouched. But the endpoint-level error paths returned a bare HTML
string, which the serializer then labeled application/octet-stream -- so a
400 error page downloaded instead of rendering in the browser.

Add an html_error(res, status, message) helper that sets the status, a
text/html Content-Type, and the body, then returns the response object --
the same pattern report_response() already uses for successful HTML
reports, which bypasses the octet-stream serializer. Route all GET/POST
/report validation errors and the ejamit_interface tryCatch failures
through it; the tryCatch now returns the condition and is checked with
inherits(result, "error").

Verified locally: GET/POST /report error cases now return 400 text/html
(previously octet-stream); successful reports and the docs page / root
redirect are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ejanalysis ejanalysis changed the title Serve /report error responses as text/html (not octet-stream) bug fix: serve /report error responses as text/html (not octet-stream) Jun 30, 2026
@ejanalysis
ejanalysis requested a review from Copilot June 30, 2026 16:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 fixes /report endpoint error responses being served with Content-Type: application/octet-stream (due to the endpoint-level octet-stream serializer), which caused browsers to download HTML error pages instead of rendering them.

Changes:

  • Added an html_error(res, status, message) helper that writes an HTML error body to the response object and sets an explicit text/html Content-Type.
  • Routed /report validation failures and ejamit_interface() tryCatch failures through html_error() to ensure consistent, renderable HTML errors.
  • Updated tryCatch error handling to return the error condition and detect failures via inherits(result, "error").

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

Comment thread rest_controller.r

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread rest_controller.r
handle_error(..., "html") interpolated the message directly into the error
page. Now that /report errors render as text/html, that could break markup
or become a reflected-injection vector if a message ever carries
user-influenced text. Add an escape_html() helper and apply it in
handle_error()'s HTML branch (escapes &, <, >, ", ' -- ampersand first).
The JSON branch is unchanged (the JSON serializer encodes safely) and plain
static messages are unaffected. Unit-tested with a <script> payload;
endpoints still return 400 text/html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@ejanalysis
ejanalysis merged commit 905000e into main Jun 30, 2026
1 check passed
@ejanalysis
ejanalysis deleted the fix-report-error-content-type branch June 30, 2026 17:02
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.

Multisite GET /report, token handoff, and CORS for EJScreen multisite selection

2 participants