Skip to content

Maxed-OSS/mimefix

Repository files navigation

MimeFix

Re-derive a useful content type for uploaded documents, in Swift. Zero dependencies beyond the standard library, no network calls.

Many storage backends and upload paths return a content type of application/octet-stream (or nothing at all) for files they could not sniff. When that blob is later served to a browser, an octet-stream is treated as a download instead of being rendered inline, so a PDF the user expects to preview becomes a forced save dialog.

MimeFix fixes that deterministically. It re-derives the real content type from the filename extension, and optionally confirms it from the leading "magic" bytes of the content, preferring the bytes when a file was renamed to lie about its type.

Install

Add MimeFix to your Package.swift dependencies:

.package(url: "https://github.com/maxed-oss/mimefix.git", from: "0.1.0")

Then add "MimeFix" to your target's dependencies:

.target(name: "YourApp", dependencies: ["MimeFix"])

Usage

import MimeFix

// The common case: storage handed you an octet-stream for a real PDF.
let result = MimeFix.normalize(
    reported: "application/octet-stream",
    filename: "invoice.pdf"
)
result.contentType      // "application/pdf"
result.changed          // true
result.renderableInline // true  -> safe to serve inline

// A specific, trustworthy reported type is kept untouched.
MimeFix.normalize(reported: "image/png", filename: "x.bin").contentType
// "image/png"

// Magic bytes win over a misleading extension (a PNG named ".pdf").
let png: [UInt8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
MimeFix.normalize(
    reported: nil,
    filename: "screenshot.pdf",
    magicBytes: png
).contentType
// "image/png"

// Direct lookups are available too.
MimeFix.contentType(forExtension: "statement.CSV")          // "text/csv"
MimeFix.contentType(forMagicBytes: [0x25, 0x50, 0x44, 0x46]) // "application/pdf"

How it decides

normalize(reported:filename:magicBytes:) follows a small, predictable set of rules:

  1. If reported is specific and trustworthy (anything other than a generic placeholder), keep it. MimeFix never second-guesses a server that already knows the type. A ; charset=... parameter is ignored when judging this.
  2. Otherwise, derive the type. Magic bytes are preferred over the extension, so a renamed file is served as what it actually is. The extension is used when no bytes are provided or the bytes are unrecognized.
  3. If nothing can be determined, fall back to application/octet-stream and flag the result as not inline-renderable, so callers always get a valid type and a clear signal.

The Result tells you what happened:

Field Meaning
contentType The content type to use going forward.
changed True when MimeFix replaced the caller-supplied type.
renderableInline True when the result is no longer an opaque octet-stream and is safe to render inline.

Scope

The extension table and signature set cover the document, image, data, archive, and media formats that flow through real upload pipelines. They are intentionally not a full IANA mirror: the goal is to recover inline-renderable types reliably, not to enumerate every registered type. Adding an entry is a one-line change to Tables.swift.

ZIP-container Office formats (.docx, .xlsx, .pptx) all share the ZIP magic signature, so byte-sniffing reports them as application/zip; the filename extension is the better source for the specific Office type, and normalize uses it accordingly.

Test

swift test

License

MIT. See LICENSE.

About

Re-derive a useful content type for uploaded documents: filename extension plus magic bytes, bytes winning over a renamed file. Fixes the octet-stream forced-download problem deterministically.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages