bun icon indicating copy to clipboard operation
bun copied to clipboard

Bun does not support streaming videos with range requests

Open gal-yedidovich opened this issue 1 year ago • 5 comments

What version of Bun is running?

1.1.4

What platform is your computer?

Darwin 23.4.0 arm64 arm

What steps can reproduce the bug?

I created a sample http server using express that streams videos with range requests, but it seems that bun is not able to handle it and the request is loading indefinitely.

here is an express sample project code: server.js

import express from 'express'
import fs from 'fs'

console.log('Starting server...')
const port = 3000
const app = express()

app.use(express.static('public'))

app.get('/video', function (req, res) {
    try {
        const range = req.headers.range
        if (!range) {
            res.status(416).send('Requires Range header')
            return
        }

        const videoPath = 'local-file-path.mp4'

        const size = fs.statSync(videoPath).size
        const CHUNK_SIZE = 2 * (10 ** 6) // 2MB each chunk
        const start = Number(range.replace(/\D/g, '')) // starting point from the request range
        const end = Math.min(start + CHUNK_SIZE, size - 1) // ending point
        const contentLength = end - start + 1

        res.writeHead(206, {
            'Content-Range': `bytes ${start}-${end}/${size}`,
            'Accept-Ranges': 'bytes',
            'Content-Length': contentLength,
            'Content-Type': 'video/mp4',
            'Access-Control-Allow-Origin': '*',
        })

        const videoStream = fs.createReadStream(videoPath, { start, end })
        videoStream.pipe(res)
    } catch (e) {
        console.error('failed to get video:', e)
        res.status(500)
    }
})

app.listen(port, function () {
    console.log(`Listening on port ${port}...`)
})

also, index.html:

<!DOCTYPE html>
<html lang="en">
<body>
<video style="width: 100vw; height: 100vh" controls autofocus>
    <source src="/video">
</video>
</body>
</html>

Using Bun.file

I tried also using the standard Bun way with Bun.file('path'), it seems to download the entire file instead of serving the requested range.

What is the expected behavior?

I'm expecting bun to support every use case of video streaming

  1. supporting express library
  2. supporting with Bun.file('path')

What do you see instead?

  1. with express example: The request is indefinite, and does not ever ends
  2. using Bun.file (with Bun.serve): The video file is served from beginning before video reaching the requested start-range

Additional information

I also tried it with Elysia to be sure there is no workaround with a supporting framework, I got the similar result as using only Bun.serve with Bun.file

server.ts: (serving identical index.html for the client)

import { Elysia } from 'elysia'
import { staticPlugin } from '@elysiajs/static'

const app = new Elysia()
    .get('/', Bun.file('public/index.html')
    .get('/video', Bun.file('local-file-path.mp4'))
    .listen(3000)


console.log(
    `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`,
)

gal-yedidovich avatar Apr 22 '24 18:04 gal-yedidovich

Sadly there is no way to slice a Bun.file (yet)

7f8ddd avatar Apr 22 '24 21:04 7f8ddd

I'm pretty sure we have tests that verify this works

Jarred-Sumner avatar Apr 22 '24 21:04 Jarred-Sumner

oh this is using express, that makes more sense

Jarred-Sumner avatar Apr 22 '24 21:04 Jarred-Sumner

@Jarred-Sumner

I'm pretty sure we have tests that verify this works

Can you direct me to an example?

gal-yedidovich avatar Apr 23 '24 11:04 gal-yedidovich

I think it's this example?

slmjkdbtl avatar May 21 '24 14:05 slmjkdbtl

Fixed in Bun v1.1.9

Note the current version of Bun is Bun v1.2.5. We are a little behind on issues.

Jarred-Sumner avatar Mar 22 '25 04:03 Jarred-Sumner