Repository navigation
fix: preview untyped objects as safe text - #291
Merged
Merged
Conversation
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.
Contributor
There was a problem hiding this comment.
🟡 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
Keep ordinary downloads unversioned instead of inheriting HEAD metadata. Track explicitly selected versions separately and require object-scoped GetObjectVersion permission for those downloads.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Pull Request
Description
Opening an extensionless text object such as
fredwith 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-scopeds3: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
Testing
Passed all repository checks, including 924 tests:
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
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.
Loading, fallback, error, and permission states
Mobile preview and 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 checkss3:GetObjectVersionfor selected versions and hides that action when denied. Ordinary downloads remain available using an unversioned GET.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, andbinary/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.