File Upload and Media Processing#
Misskey's file upload pipeline runs through three main layers: MIME detection (what the file is), media processing (generating display-optimized variants), and Content-Type enforcement (controlling browser behavior at serve time). The primary entry point is DriveService.addFile, which orchestrates all three.
MIME Type Detection & Validation#
FileInfoService.detectType detects MIME type by reading magic bytes with the file-type library. Key edge cases handled:
- SVG: If
file-typereturnsapplication/xmlor is inconclusive,checkSvgruns anis-svgcheck (files >1 MB are rejected as SVG). - Video-only audio: Files detected as video but lacking a video track (m4a, some webm) are re-typed to their
audio/*counterpart via ffprobe . - MIME normalization:
audio/x-flacβaudio/flac,audio/vnd.waveβaudio/wavviafixMime. - Zero-byte files and unrecognized files fall back to
application/octet-stream. - Filename-based fallback:
.txt,.csv,.jsonextensions are applied iffile-typereturnsoctet-stream.
getFileInfo also rejects images with dimensions exceeding 16383 Γ 16383 px by downgrading them to octet-stream , and computes MD5 hash, image dimensions (via probe-image-size), and blurhash.
MIME Whitelists#
Two named whitelists live in const.ts:
| Constant | Purpose |
|---|---|
FILE_TYPE_IMAGE | 9 raster image types β used for image-specific logic |
FILE_TYPE_BROWSERSAFE | All types safe to serve inline to a browser (images + audio + video); SVG is intentionally excluded to prevent XSS |
The isMimeImage utility extends this with four named subsets:
| Key | Contents |
|---|---|
safe-file | Alias for FILE_TYPE_BROWSERSAFE |
sharp-convertible-image | JPEG, TIFF, PNG, GIF, APNG, WebP, AVIF, SVG |
sharp-convertible-image-with-bmp | Same + BMP, ICO |
sharp-animation-convertible-image[-with-bmp] | As above but without APNG (no animated APNG) |
Image Processing & Alt Generation#
DriveService.generateAlts produces up to two variants per upload:
Thumbnail β always generated for Sharp-convertible images and videos:
- Static images: WebP at 498 Γ 422 via
convertSharpToWebp - Animated images (GIF, WebP): WebP at 374 Γ 317 with
alphaQuality: 70 - Videos: delegated to
VideoProcessingService.generateVideoThumbnail, or skipped ifconfig.videoThumbnailGeneratoris set
Webpublic (web-optimized copy) β generated only for local uploads (!file.uri) when the original doesn't already meet web-safe criteria:
- JPEG/WebP/AVIF β WebP at 2048 Γ 2048
- PNG/BMP/SVG β PNG at 2048 Γ 2048
- Skipped if: image is animated, has EXIF/IPTC/XMP metadata and is β€2048px, or is SVG/AVIF (security/compatibility)
All Sharp operations use sharpBmp (a Misskey-maintained wrapper that adds BMP/ICO support to Sharp). The default WebP encoding uses quality: 77, smartSubsample: true, effort: 2 .
Both thumbnail and webpublic are stored separately β their URLs are tracked as thumbnailUrl/webpublicUrl on MiDriveFile and uploaded to object storage (or internal storage) in parallel with the original .
Content-Type Enforcement at Serve Time#
getSafeContentType enforces FILE_TYPE_BROWSERSAFE: any MIME not in the list is served as application/octet-stream, forcing a browser download instead of inline rendering.
This is applied in two places:
FileServerUtils.setFileResponseHeaders: setsContent-TypeviagetSafeContentTypefor all local file responses .DriveService.upload(object storage upload): setsContentTypeon the S3PutObjectcall the same way;image/apngis also normalized toimage/pngat this point . For object storage, file extensions are also stripped from the key URL for non-browsersafe types to prevent content-type inference from the filename .
The proxy handler (FileServerProxyHandler) applies additional restrictions: SVG is converted to WebP , and non-image or non-browsersafe MIME types cause a 403 Rejected type .
Key Files#
| File | Role |
|---|---|
FileInfoService.ts | MIME detection, dimension validation, blurhash, sensitivity |
DriveService.ts | Upload orchestration, alt generation, storage |
ImageProcessingService.ts | Sharp-based WebP/PNG/AVIF conversion |
const.ts | FILE_TYPE_IMAGE and FILE_TYPE_BROWSERSAFE whitelists |
is-mime-image.ts | Named MIME subsets for Sharp capability checks |
FileServerUtils.ts | getSafeContentType, response headers, range streaming |
FileServerProxyHandler.ts | Proxy-time image conversion and MIME gating |