summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/FileServerService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/FileServerService.ts')
-rw-r--r--packages/backend/src/server/FileServerService.ts48
1 files changed, 27 insertions, 21 deletions
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index e5eefac1fa..8eeb76f7c7 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -22,6 +22,7 @@ import { bindThis } from '@/decorators.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
import { isMimeImage } from '@/misc/is-mime-image.js';
import sharp from 'sharp';
+import { correctFilename } from '@/misc/correct-filename.js';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
@@ -52,15 +53,6 @@ export class FileServerService {
}
@bindThis
- public commonReadableHandlerGenerator(reply: FastifyReply) {
- return (err: Error): void => {
- this.logger.error(err);
- reply.code(500);
- reply.header('Cache-Control', 'max-age=300');
- };
- }
-
- @bindThis
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
fastify.addHook('onRequest', (request, reply, done) => {
reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\'');
@@ -190,13 +182,19 @@ export class FileServerService {
}
reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
+ reply.header('Content-Disposition',
+ contentDisposition(
+ 'inline',
+ correctFilename(file.filename, image.ext)
+ )
+ );
return image.data;
}
if (file.fileRole !== 'original') {
- const filename = rename(file.file.name, {
+ const filename = rename(file.filename, {
suffix: file.fileRole === 'thumbnail' ? '-thumb' : '-web',
- extname: file.ext ? `.${file.ext}` : undefined,
+ extname: file.ext ? `.${file.ext}` : '.unknown',
}).toString();
reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.mime) ? file.mime : 'application/octet-stream');
@@ -204,12 +202,10 @@ export class FileServerService {
reply.header('Content-Disposition', contentDisposition('inline', filename));
return fs.createReadStream(file.path);
} else {
- const stream = fs.createReadStream(file.path);
- stream.on('error', this.commonReadableHandlerGenerator(reply));
reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.file.type) ? file.file.type : 'application/octet-stream');
reply.header('Cache-Control', 'max-age=31536000, immutable');
- reply.header('Content-Disposition', contentDisposition('inline', file.file.name));
- return stream;
+ reply.header('Content-Disposition', contentDisposition('inline', file.filename));
+ return fs.createReadStream(file.path);
}
} catch (e) {
if ('cleanup' in file) file.cleanup();
@@ -360,6 +356,12 @@ export class FileServerService {
reply.header('Content-Type', image.type);
reply.header('Cache-Control', 'max-age=31536000, immutable');
+ reply.header('Content-Disposition',
+ contentDisposition(
+ 'inline',
+ correctFilename(file.filename, image.ext)
+ )
+ );
return image.data;
} catch (e) {
if ('cleanup' in file) file.cleanup();
@@ -369,8 +371,8 @@ export class FileServerService {
@bindThis
private async getStreamAndTypeFromUrl(url: string): Promise<
- { state: 'remote'; fileRole?: 'thumbnail' | 'webpublic' | 'original'; file?: DriveFile; mime: string; ext: string | null; path: string; cleanup: () => void; }
- | { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; }
+ { state: 'remote'; fileRole?: 'thumbnail' | 'webpublic' | 'original'; file?: DriveFile; mime: string; ext: string | null; path: string; cleanup: () => void; filename: string; }
+ | { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; filename: string; mime: string; ext: string | null; path: string; }
| '404'
| '204'
> {
@@ -386,11 +388,11 @@ export class FileServerService {
@bindThis
private async downloadAndDetectTypeFromUrl(url: string): Promise<
- { state: 'remote' ; mime: string; ext: string | null; path: string; cleanup: () => void; }
+ { state: 'remote' ; mime: string; ext: string | null; path: string; cleanup: () => void; filename: string; }
> {
const [path, cleanup] = await createTemp();
try {
- await this.downloadService.downloadUrl(url, path);
+ const { filename } = await this.downloadService.downloadUrl(url, path);
const { mime, ext } = await this.fileInfoService.detectType(path);
@@ -398,6 +400,7 @@ export class FileServerService {
state: 'remote',
mime, ext,
path, cleanup,
+ filename,
};
} catch (e) {
cleanup();
@@ -407,8 +410,8 @@ export class FileServerService {
@bindThis
private async getFileFromKey(key: string): Promise<
- { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; url: string; mime: string; ext: string | null; path: string; cleanup: () => void; }
- | { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; }
+ { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; filename: string; url: string; mime: string; ext: string | null; path: string; cleanup: () => void; }
+ | { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; filename: string; mime: string; ext: string | null; path: string; }
| '404'
| '204'
> {
@@ -432,6 +435,7 @@ export class FileServerService {
url: file.uri,
fileRole: isThumbnail ? 'thumbnail' : isWebpublic ? 'webpublic' : 'original',
file,
+ filename: file.name,
};
}
@@ -443,6 +447,7 @@ export class FileServerService {
state: 'stored_internal',
fileRole: isThumbnail ? 'thumbnail' : 'webpublic',
file,
+ filename: file.name,
mime, ext,
path,
};
@@ -452,6 +457,7 @@ export class FileServerService {
state: 'stored_internal',
fileRole: 'original',
file,
+ filename: file.name,
mime: file.type,
ext: null,
path,