aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/object-storage-proxy.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/object-storage-proxy.ts')
-rw-r--r--server/controllers/object-storage-proxy.ts87
1 files changed, 15 insertions, 72 deletions
diff --git a/server/controllers/object-storage-proxy.ts b/server/controllers/object-storage-proxy.ts
index c530b57f8..8e2cc4af9 100644
--- a/server/controllers/object-storage-proxy.ts
+++ b/server/controllers/object-storage-proxy.ts
@@ -1,11 +1,7 @@
1import cors from 'cors' 1import cors from 'cors'
2import express from 'express' 2import express from 'express'
3import { PassThrough, pipeline } from 'stream'
4import { logger } from '@server/helpers/logger'
5import { StreamReplacer } from '@server/helpers/stream-replacer'
6import { OBJECT_STORAGE_PROXY_PATHS } from '@server/initializers/constants' 3import { OBJECT_STORAGE_PROXY_PATHS } from '@server/initializers/constants'
7import { injectQueryToPlaylistUrls } from '@server/lib/hls' 4import { proxifyHLS, proxifyWebTorrentFile } from '@server/lib/object-storage'
8import { getHLSFileReadStream, getWebTorrentFileReadStream } from '@server/lib/object-storage'
9import { 5import {
10 asyncMiddleware, 6 asyncMiddleware,
11 ensureCanAccessPrivateVideoHLSFiles, 7 ensureCanAccessPrivateVideoHLSFiles,
@@ -13,9 +9,7 @@ import {
13 ensurePrivateObjectStorageProxyIsEnabled, 9 ensurePrivateObjectStorageProxyIsEnabled,
14 optionalAuthenticate 10 optionalAuthenticate
15} from '@server/middlewares' 11} from '@server/middlewares'
16import { HttpStatusCode } from '@shared/models' 12import { doReinjectVideoFileToken } from './shared/m3u8-playlist'
17import { buildReinjectVideoFileTokenQuery, doReinjectVideoFileToken } from './shared/m3u8-playlist'
18import { GetObjectCommandOutput } from '@aws-sdk/client-s3'
19 13
20const objectStorageProxyRouter = express.Router() 14const objectStorageProxyRouter = express.Router()
21 15
@@ -25,14 +19,14 @@ objectStorageProxyRouter.get(OBJECT_STORAGE_PROXY_PATHS.PRIVATE_WEBSEED + ':file
25 ensurePrivateObjectStorageProxyIsEnabled, 19 ensurePrivateObjectStorageProxyIsEnabled,
26 optionalAuthenticate, 20 optionalAuthenticate,
27 asyncMiddleware(ensureCanAccessVideoPrivateWebTorrentFiles), 21 asyncMiddleware(ensureCanAccessVideoPrivateWebTorrentFiles),
28 asyncMiddleware(proxifyWebTorrent) 22 asyncMiddleware(proxifyWebTorrentController)
29) 23)
30 24
31objectStorageProxyRouter.get(OBJECT_STORAGE_PROXY_PATHS.STREAMING_PLAYLISTS.PRIVATE_HLS + ':videoUUID/:filename', 25objectStorageProxyRouter.get(OBJECT_STORAGE_PROXY_PATHS.STREAMING_PLAYLISTS.PRIVATE_HLS + ':videoUUID/:filename',
32 ensurePrivateObjectStorageProxyIsEnabled, 26 ensurePrivateObjectStorageProxyIsEnabled,
33 optionalAuthenticate, 27 optionalAuthenticate,
34 asyncMiddleware(ensureCanAccessPrivateVideoHLSFiles), 28 asyncMiddleware(ensureCanAccessPrivateVideoHLSFiles),
35 asyncMiddleware(proxifyHLS) 29 asyncMiddleware(proxifyHLSController)
36) 30)
37 31
38// --------------------------------------------------------------------------- 32// ---------------------------------------------------------------------------
@@ -41,76 +35,25 @@ export {
41 objectStorageProxyRouter 35 objectStorageProxyRouter
42} 36}
43 37
44async function proxifyWebTorrent (req: express.Request, res: express.Response) { 38function proxifyWebTorrentController (req: express.Request, res: express.Response) {
45 const filename = req.params.filename 39 const filename = req.params.filename
46 40
47 logger.debug('Proxifying WebTorrent file %s from object storage.', filename) 41 return proxifyWebTorrentFile({ req, res, filename })
48
49 try {
50 const { response: s3Response, stream } = await getWebTorrentFileReadStream({
51 filename,
52 rangeHeader: req.header('range')
53 })
54
55 setS3Headers(res, s3Response)
56
57 return stream.pipe(res)
58 } catch (err) {
59 return handleObjectStorageFailure(res, err)
60 }
61} 42}
62 43
63async function proxifyHLS (req: express.Request, res: express.Response) { 44function proxifyHLSController (req: express.Request, res: express.Response) {
64 const playlist = res.locals.videoStreamingPlaylist 45 const playlist = res.locals.videoStreamingPlaylist
65 const video = res.locals.onlyVideo 46 const video = res.locals.onlyVideo
66 const filename = req.params.filename 47 const filename = req.params.filename
67 48
68 logger.debug('Proxifying HLS file %s from object storage.', filename) 49 const reinjectVideoFileToken = filename.endsWith('.m3u8') && doReinjectVideoFileToken(req)
69
70 try {
71 const { response: s3Response, stream } = await getHLSFileReadStream({
72 playlist: playlist.withVideo(video),
73 filename,
74 rangeHeader: req.header('range')
75 })
76
77 setS3Headers(res, s3Response)
78
79 const streamReplacer = filename.endsWith('.m3u8') && doReinjectVideoFileToken(req)
80 ? new StreamReplacer(line => injectQueryToPlaylistUrls(line, buildReinjectVideoFileTokenQuery(req, filename.endsWith('master.m3u8'))))
81 : new PassThrough()
82 50
83 return pipeline( 51 return proxifyHLS({
84 stream, 52 req,
85 streamReplacer, 53 res,
86 res, 54 playlist,
87 err => { 55 video,
88 if (!err) return 56 filename,
89 57 reinjectVideoFileToken
90 handleObjectStorageFailure(res, err)
91 }
92 )
93 } catch (err) {
94 return handleObjectStorageFailure(res, err)
95 }
96}
97
98function handleObjectStorageFailure (res: express.Response, err: Error) {
99 if (err.name === 'NoSuchKey') {
100 logger.debug('Could not find key in object storage to proxify private HLS video file.', { err })
101 return res.sendStatus(HttpStatusCode.NOT_FOUND_404)
102 }
103
104 return res.fail({
105 status: HttpStatusCode.INTERNAL_SERVER_ERROR_500,
106 message: err.message,
107 type: err.name
108 }) 58 })
109} 59}
110
111function setS3Headers (res: express.Response, s3Response: GetObjectCommandOutput) {
112 if (s3Response.$metadata.httpStatusCode === HttpStatusCode.PARTIAL_CONTENT_206) {
113 res.setHeader('Content-Range', s3Response.ContentRange)
114 res.status(HttpStatusCode.PARTIAL_CONTENT_206)
115 }
116}