Skip to content

fix: preview untyped objects as safe text - #291

Merged
cxymds merged 2 commits into
mainfrom
cxymds/fix-extensionless-text-preview
Nov 10, 2026
Merged

cxymds merged 2 commits into
mainfrom
cxymds/fix-extensionless-text-preview

Conversation

@cxymds

@cxymds cxymds commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Pull Request

Description

Opening an extensionless text object such as fred with missing or generic MIME metadata currently shows a blank iframe. Preview now checks objects up to 2 MiB for complete, valid UTF-8 text and displays accepted content as literal text.

Binary, empty, or oversized content shows a clear fallback with download when permitted; request failures show an error. Preview downloads retain the selected object key. Ordinary downloads use an unversioned GET and require s3:GetObject; explicitly selected versions are kept separately from HEAD metadata and require object-scoped s3:GetObjectVersion, including when HEAD does not expose the version header. Existing image, audio, video, PDF, Parquet, and TIFF renderer priorities are preserved.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test improvements
  • Security fix

Testing

  • Unit tests added/updated
  • Manual testing completed

Passed all repository checks, including 924 tests:

nvm use v22
pnpm install --frozen-lockfile
pnpm type-check
pnpm lint
pnpm format:check
pnpm test:run
pnpm build

Regression coverage includes split UTF-8 sequences, non-ASCII content, binary controls, invalid UTF-8, empty/BOM-only content, exact and exceeded size limits, inaccurate size metadata, HTTP/network errors, cancellation, stale responses, selected key/version preservation, current-object versus version-read permissions, object scope, and explicit version-read denials.

Browser checks used real Console preview components, BrowserContent, and the signed-URL download hook with local HTTP fixtures: generic/missing MIME text, loading, binary, empty, oversized, error, literal HTML, download permission, selected-version download, and mobile layouts at 390 × 844. Independent Reviewer, Tester, and UX/Simplifier checks passed.

Checklist

  • Code follows the project's style guidelines
  • Self-review completed
  • TypeScript types are properly defined
  • All commit messages are in English (Conventional Commits)
  • All existing tests pass
  • No new dependencies added, or they are justified

Related Issues

Fixes rustfs/rustfs#9230

Screenshots (if applicable)

The before/after pair uses the main and updated Console components with the same object, HTTP fixture, and 1280 × 720 viewport.

Before After
Blank extensionless text preview on main Extensionless UTF-8 text preview
Loading, fallback, error, and permission states
State Screenshot
Loading Loading
Binary Binary fallback
Empty Empty object
Oversized Size limit
HTTP error Error
Download permission denied Download unavailable
Missing MIME Missing MIME text
Literal HTML Literal HTML text
Mobile preview and fallback
Text Binary fallback
Mobile text preview Mobile download fallback
Preview download permission regression

With the same selected version and a policy allowing only s3:GetObject, the previous implementation showed an unusable download action. The updated implementation checks s3:GetObjectVersion for selected versions and hides that action when denied. Ordinary downloads remain available using an unversioned GET.

Before After
Version download shown with current-object read permission only Version download hidden without version-read permission
Ordinary download with GetObject Selected version with GetObjectVersion
Current-object download Authorized selected-version download

Actual browser downloads were checked against local HTTP fixture response bodies: the ordinary path returned current content without versionId, while the selected-version path returned the chosen version.

Additional Notes

Detection only applies to missing MIME, application/octet-stream, and binary/octet-stream. It bounds actual streamed bytes and rejects binary control characters. Object metadata is unchanged and detected HTML is displayed literally.

Browser evidence uses local HTTP fixtures; no live RustFS deployment was exercised. Screenshots are stored on a separate evidence branch and do not add assets to this implementation diff.

Detect bounded UTF-8 content when object metadata has no specific MIME type so extensionless text no longer opens a blank iframe. Keep unsupported content downloadable and preserve the selected key and version for preview downloads.
Copilot AI balanced review requested due to automatic review settings November 9, 2026 11:10

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.

🟡 Changes recommended

Ordinary preview downloads in versioned buckets incorrectly use the HEAD-returned version, requiring unchecked s3:GetObjectVersion permission and potentially causing AccessDenied for users with s3:GetObject access.

1 open issue
What changed in this PR

This PR fixes blank previews for extensionless objects with missing or generic MIME metadata by detecting bounded UTF-8 content and displaying it as literal text.

Changes:

  • Adds text detection up to 2 MiB while preserving existing renderer priorities.
  • Adds loading, error, and download fallback states, with selected key/version handling.
  • Adds regression coverage for decoding, size limits, cancellation, and stale responses.
File Description
tests/​lib/​object-preview.test.ts Tests text detection, limits, and preview metadata.
tests/​lib/​object-preview-source.test.js Updates dispatch and request-handling assertions.
tests/​hooks/​use-object-preview-text.test.ts Tests loading, errors, cancellation, and stale responses.
lib/​object-preview.ts Adds bounded UTF-8 detection and metadata helpers.
hooks/​use-object.ts Supports version-specific signed download URLs.
hooks/​use-object-preview-text.ts Manages text fetching and preview state.
components/​object/​preview-modal.tsx Integrates detection and download/error fallbacks.
components/​object/​info.tsx Preserves selected key and version in preview metadata.
app/​(dashboard)/​browser/​content.tsx Connects preview downloads to permissions and object metadata.

Review effort: Balanced

Comment thread app/(dashboard)/browser/content.tsx Resolved
Keep ordinary downloads unversioned instead of inheriting HEAD metadata. Track explicitly selected versions separately and require object-scoped GetObjectVersion permission for those downloads.
@cxymds
cxymds merged commit f663fab into main Nov 10, 2026
10 checks passed
@cxymds
cxymds deleted the cxymds/fix-extensionless-text-preview branch November 10, 2026 02:03
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.

browser unable to preview text files

2 participants