diff options
| author | dakkar <dakkar@thenautilus.net> | 2024-03-02 17:43:24 +0000 |
|---|---|---|
| committer | dakkar <dakkar@thenautilus.net> | 2024-03-02 17:43:24 +0000 |
| commit | 2cad97c1ab39b5ae4ace4314cd3d90b574ea72c6 (patch) | |
| tree | 4a7407d9502aba227e9da65c15f76306c6b43480 /packages/backend/src/server/FileServerService.ts | |
| parent | merge: Add missing IMPORTANT_NOTES.md from Sharkey/OldJoinSharkey (!443) (diff) | |
| parent | remove duplicate method (diff) | |
| download | sharkey-2cad97c1ab39b5ae4ace4314cd3d90b574ea72c6.tar.gz sharkey-2cad97c1ab39b5ae4ace4314cd3d90b574ea72c6.tar.bz2 sharkey-2cad97c1ab39b5ae4ace4314cd3d90b574ea72c6.zip | |
merge: release 2024.3.1 (!449)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/449
Approved-by: Amelia Yukii <amelia.yukii@shourai.de>
Approved-by: Marie <marie@kaifa.ch>
Diffstat (limited to 'packages/backend/src/server/FileServerService.ts')
| -rw-r--r-- | packages/backend/src/server/FileServerService.ts | 145 |
1 files changed, 120 insertions, 25 deletions
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index e82ef64dc4..6d24898acc 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,7 +9,7 @@ import { dirname } from 'node:path'; import { Inject, Injectable } from '@nestjs/common'; import rename from 'rename'; import sharp from 'sharp'; -import { sharpBmp } from 'sharp-read-bmp'; +import { sharpBmp } from '@misskey-dev/sharp-read-bmp'; import type { Config } from '@/config.js'; import type { MiDriveFile, DriveFilesRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; @@ -27,6 +27,7 @@ import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import { isMimeImage } from '@/misc/is-mime-image.js'; import { correctFilename } from '@/misc/correct-filename.js'; +import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js'; import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify'; const _filename = fileURLToPath(import.meta.url); @@ -65,20 +66,23 @@ export class FileServerService { done(); }); - fastify.get('/files/app-default.jpg', (request, reply) => { - const file = fs.createReadStream(`${_dirname}/assets/dummy.png`); - reply.header('Content-Type', 'image/jpeg'); - reply.header('Cache-Control', 'max-age=31536000, immutable'); - return reply.send(file); - }); + fastify.register((fastify, options, done) => { + fastify.addHook('onRequest', handleRequestRedirectToOmitSearch); + fastify.get('/files/app-default.jpg', (request, reply) => { + const file = fs.createReadStream(`${_dirname}/assets/dummy.png`); + reply.header('Content-Type', 'image/jpeg'); + reply.header('Cache-Control', 'max-age=31536000, immutable'); + return reply.send(file); + }); - fastify.get<{ Params: { key: string; } }>('/files/:key', async (request, reply) => { - return await this.sendDriveFile(request, reply) - .catch(err => this.errorHandler(request, reply, err)); - }); - fastify.get<{ Params: { key: string; } }>('/files/:key/*', async (request, reply) => { - return await this.sendDriveFile(request, reply) - .catch(err => this.errorHandler(request, reply, err)); + fastify.get<{ Params: { key: string; } }>('/files/:key', async (request, reply) => { + return await this.sendDriveFile(request, reply) + .catch(err => this.errorHandler(request, reply, err)); + }); + fastify.get<{ Params: { key: string; } }>('/files/:key/*', async (request, reply) => { + return await reply.redirect(301, `${this.config.url}/files/${request.params.key}`); + }); + done(); }); fastify.get<{ @@ -166,11 +170,35 @@ export class FileServerService { } if (!image) { - image = { - data: fs.createReadStream(file.path), - ext: file.ext, - type: file.mime, - }; + if (request.headers.range && file.file.size > 0) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + if (end > file.file.size) { + end = file.file.size - 1; + } + const chunksize = end - start + 1; + + image = { + data: fs.createReadStream(file.path, { + start, + end, + }), + ext: file.ext, + type: file.mime, + }; + + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + } else { + image = { + data: fs.createReadStream(file.path), + ext: file.ext, + type: file.mime, + }; + } } if ('pipe' in image.data && typeof image.data.pipe === 'function') { @@ -201,11 +229,54 @@ export class FileServerService { reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.mime) ? file.mime : 'application/octet-stream'); reply.header('Cache-Control', 'max-age=31536000, immutable'); reply.header('Content-Disposition', contentDisposition('inline', filename)); + + if (request.headers.range && file.file.size > 0) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + if (end > file.file.size) { + end = file.file.size - 1; + } + const chunksize = end - start + 1; + const fileStream = fs.createReadStream(file.path, { + start, + end, + }); + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + reply.code(206); + return fileStream; + } + return fs.createReadStream(file.path); } else { 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.filename)); + + if (request.headers.range && file.file.size > 0) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + console.log(end); + if (end > file.file.size) { + end = file.file.size - 1; + } + const chunksize = end - start + 1; + const fileStream = fs.createReadStream(file.path, { + start, + end, + }); + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + reply.code(206); + return fileStream; + } + return fs.createReadStream(file.path); } } catch (e) { @@ -338,11 +409,35 @@ export class FileServerService { } if (!image) { - image = { - data: fs.createReadStream(file.path), - ext: file.ext, - type: file.mime, - }; + if (request.headers.range && file.file && file.file.size > 0) { + const range = request.headers.range as string; + const parts = range.replace(/bytes=/, '').split('-'); + const start = parseInt(parts[0], 10); + let end = parts[1] ? parseInt(parts[1], 10) : file.file.size - 1; + if (end > file.file.size) { + end = file.file.size - 1; + } + const chunksize = end - start + 1; + + image = { + data: fs.createReadStream(file.path, { + start, + end, + }), + ext: file.ext, + type: file.mime, + }; + + reply.header('Content-Range', `bytes ${start}-${end}/${file.file.size}`); + reply.header('Accept-Ranges', 'bytes'); + reply.header('Content-Length', chunksize); + } else { + image = { + data: fs.createReadStream(file.path), + ext: file.ext, + type: file.mime, + }; + } } if ('cleanup' in file) { |