aboutsummaryrefslogtreecommitdiffstats
path: root/src/server/HttpServer.hx
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2021-02-10 05:02:36 +0300
committerRblSb <msrblsb@gmail.com>2021-02-10 05:02:36 +0300
commit71d2415a7992c7142200656857ecee3512b238a4 (patch)
tree86ad20e7ecfe2e260da3df29e217de9ea5b06b00 /src/server/HttpServer.hx
parent2bb127e1cd582d9151ef1b70c3496bc79776a95a (diff)
Support partial content streams
Diffstat (limited to 'src/server/HttpServer.hx')
-rw-r--r--src/server/HttpServer.hx49
1 files changed, 34 insertions, 15 deletions
diff --git a/src/server/HttpServer.hx b/src/server/HttpServer.hx
index 0388c28..46540a3 100644
--- a/src/server/HttpServer.hx
+++ b/src/server/HttpServer.hx
@@ -53,10 +53,17 @@ class HttpServer {
var url = req.url;
if (url == "/") url = "/index.html";
var filePath = dir + url;
+ final ext = Path.extension(filePath).toLowerCase();
+
+ res.setHeader("Accept-Ranges", "bytes");
+ res.setHeader("Content-Type", getMimeType(ext));
if (allowLocalRequests && req.connection.remoteAddress == req.connection.localAddress
|| allowedLocalFiles[url]) {
- if (serveLocalFile(res, url)) return;
+ if (isMediaExtension(ext)) {
+ allowedLocalFiles[url] = true;
+ if (serveMedia(req, res, url)) return;
+ }
}
if (!isChildOf(dir, filePath)) {
@@ -81,13 +88,15 @@ class HttpServer {
}
}
+ if (isMediaExtension(ext)) {
+ if (serveMedia(req, res, filePath)) return;
+ }
+
Fs.readFile(filePath, (err:Dynamic, data:Buffer) -> {
if (err != null) {
readFileError(err, res, filePath);
return;
}
- final ext = Path.extension(filePath).toLowerCase();
- res.setHeader("Content-Type", getMimeType(ext));
if (ext == "html") {
// replace ${textId} to localized strings
data = cast localizeHtml(data.toString(), req.headers["accept-language"]);
@@ -107,22 +116,32 @@ class HttpServer {
}
}
- static function serveLocalFile(res:ServerResponse, filePath:String):Bool {
- final ext = Path.extension(filePath).toLowerCase();
- if (ext != "mp4" && ext != "mp3" && ext != "wav") return false;
+ static function serveMedia(req:IncomingMessage, res:ServerResponse, filePath:String):Bool {
+ final range:String = req.headers["range"];
+ if (range == null) return false;
if (!Fs.existsSync(filePath)) return false;
- allowedLocalFiles[filePath] = true;
- Fs.readFile(filePath, (err:Dynamic, data:Buffer) -> {
- if (err != null) {
- readFileError(err, res, filePath);
- return;
- }
- res.setHeader("Content-Type", getMimeType(ext));
- res.end(data);
- });
+ final videoSize = Fs.statSync(filePath).size;
+ // range example: "bytes=24182784-"
+ final CHUNK_SIZE = 1024 * 1024 * 5; // 5 MB
+ final start = Std.parseInt(~/[^0-9]/g.replace(range, ""));
+ final end = Std.int(Math.min(start + CHUNK_SIZE, videoSize - 1));
+ final contentLength = end - start + 1;
+
+ res.setHeader("Content-Range", 'bytes ${start}-${end}/${videoSize}');
+ res.setHeader("Content-Length", '$contentLength');
+ // HTTP Status 206 for Partial Content
+ res.statusCode = 206;
+ // create video read stream for this particular chunk
+ final videoStream = Fs.createReadStream(filePath, {start: start, end: end});
+ // stream the video chunk to the client
+ videoStream.pipe(res);
return true;
}
+ static function isMediaExtension(ext:String):Bool {
+ return ext == "mp4" || ext == "mp3" || ext == "wav";
+ }
+
static final matchLang = ~/^[A-z]+/;
static final matchVarString = ~/\${([A-z_]+)}/g;
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage