aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2024-01-05 03:47:20 +0300
committerRblSb <msrblsb@gmail.com>2024-01-05 03:47:20 +0300
commitf6a89cb793ff5272f0d259b0e296b3862f0c4798 (patch)
tree4c77d9516fe10a7d7bc22a6aaade09a3d14889e3
parentc9b920cea600b5fbe84ad7ab0b279275243faacb (diff)
Fix file descriptor leaks when streaming files
-rw-r--r--build/server.js53
-rw-r--r--src/server/HttpServer.hx44
2 files changed, 64 insertions, 33 deletions
diff --git a/build/server.js b/build/server.js
index c4fd7c8..5fe867b 100644
--- a/build/server.js
+++ b/build/server.js
@@ -3756,32 +3756,50 @@ server_HttpServer.serveMedia = function(req,res,filePath) {
return false;
}
var videoSize = js_node_Fs.statSync(filePath).size;
- var range = req.headers["range"];
- if(range == null) {
+ var rangeHeader = req.headers["range"];
+ if(rangeHeader == null) {
res.statusCode = 200;
res.setHeader("Content-Length","" + videoSize);
var videoStream = js_node_Fs.createReadStream(filePath);
videoStream.pipe(res);
+ res.on("error",function() {
+ return videoStream.destroy();
+ });
+ res.on("close",function() {
+ return videoStream.destroy();
+ });
return true;
}
- var ranges = new EReg("[-=]","g").split(range);
+ var range = server_HttpServer.parseRangeHeader(rangeHeader,videoSize);
+ var start = range.start;
+ var end = range.end;
+ res.setHeader("Content-Range","bytes " + start + "-" + end + "/" + videoSize);
+ res.setHeader("Content-Length","" + (end - start + 1));
+ res.statusCode = 206;
+ var videoStream1 = js_node_Fs.createReadStream(filePath,{ start : start, end : end});
+ videoStream1.pipe(res);
+ res.on("error",function() {
+ return videoStream1.destroy();
+ });
+ res.on("close",function() {
+ return videoStream1.destroy();
+ });
+ return true;
+};
+server_HttpServer.parseRangeHeader = function(rangeHeader,videoSize) {
+ var ranges = new EReg("[-=]","g").split(rangeHeader);
var start = parseFloat(ranges[1]);
if(server_Utils.isOutOfRange(start,0,videoSize - 1)) {
start = 0;
}
var end = parseFloat(ranges[2]);
if(isNaN(end)) {
- end = start + 5242880;
+ end = start + server_HttpServer.CHUNK_SIZE;
}
if(server_Utils.isOutOfRange(end,start,videoSize - 1)) {
end = videoSize - 1;
}
- res.setHeader("Content-Range","bytes " + start + "-" + end + "/" + videoSize);
- res.setHeader("Content-Length","" + (end - start + 1));
- res.statusCode = 206;
- var videoStream = js_node_Fs.createReadStream(filePath,{ start : start, end : end});
- videoStream.pipe(res);
- return true;
+ return { start : start, end : end};
};
server_HttpServer.isMediaExtension = function(ext) {
if(!(ext == "mp4" || ext == "webm" || ext == "mp3")) {
@@ -3805,24 +3823,24 @@ server_HttpServer.localizeHtml = function(data,lang) {
server_HttpServer.proxyUrl = function(req,res) {
var url = StringTools.replace(req.url,"/proxy?url=","");
var proxy = server_HttpServer.proxyRequest(url,req,res,function(proxyReq) {
- var url = proxyReq.headers["location"];
- if(url == null) {
+ var tmp = proxyReq.headers["location"];
+ if(tmp == null) {
return false;
}
- var proxy2 = server_HttpServer.proxyRequest(url,req,res,function(proxyReq) {
+ var proxy2 = server_HttpServer.proxyRequest(tmp,req,res,function(proxyReq) {
return false;
});
if(proxy2 == null) {
- res.end("Proxy error: multiple redirects for url " + url);
+ res.end("Proxy error: multiple redirects for url " + tmp);
return true;
}
- req.pipe(proxy2,{ end : true});
+ req.pipe(proxy2);
return true;
});
if(proxy == null) {
return false;
}
- req.pipe(proxy,{ end : true});
+ req.pipe(proxy);
return true;
};
server_HttpServer.proxyRequest = function(url,req,res,fn) {
@@ -3843,7 +3861,7 @@ server_HttpServer.proxyRequest = function(url,req,res,fn) {
}
proxyReq.headers["Content-Type"] = "application/octet-stream";
res.writeHead(proxyReq.statusCode,proxyReq.headers);
- proxyReq.pipe(res,{ end : true});
+ proxyReq.pipe(res);
});
proxy.on("error",function(err) {
res.end("Proxy error: " + url1.href);
@@ -5317,6 +5335,7 @@ server_HttpServer.mimeTypes = (function($this) {
server_HttpServer.hasCustomRes = false;
server_HttpServer.allowedLocalFiles = new haxe_ds_StringMap();
server_HttpServer.allowLocalRequests = false;
+server_HttpServer.CHUNK_SIZE = 5242880;
server_HttpServer.matchLang = new EReg("^[A-z]+","");
server_HttpServer.matchVarString = new EReg("\\${([A-z_]+)}","g");
server_HttpServer.ctrlCharacters = new EReg("[\\u0000-\\u001F\\u007F-\\u009F\\u2000-\\u200D\\uFEFF]","g");
diff --git a/src/server/HttpServer.hx b/src/server/HttpServer.hx
index acb8955..c953bb0 100644
--- a/src/server/HttpServer.hx
+++ b/src/server/HttpServer.hx
@@ -43,6 +43,7 @@ class HttpServer {
static var hasCustomRes = false;
static var allowedLocalFiles:Map<String, Bool> = [];
static var allowLocalRequests = false;
+ static final CHUNK_SIZE = 1024 * 1024 * 5; // 5 MB
public static function init(dir:String, ?customDir:String, allowLocalRequests:Bool):Void {
HttpServer.dir = dir;
@@ -125,25 +126,22 @@ class HttpServer {
static function serveMedia(req:IncomingMessage, res:ServerResponse, filePath:String):Bool {
if (!Fs.existsSync(filePath)) return false;
final videoSize = Fs.statSync(filePath).size;
- var range:String = req.headers["range"];
- if (range == null) {
+ final rangeHeader:String = req.headers["range"];
+ if (rangeHeader == null) {
res.statusCode = 200;
res.setHeader("Content-Length", '$videoSize');
final videoStream = Fs.createReadStream(filePath);
videoStream.pipe(res);
+ res.on("error", () -> videoStream.destroy());
+ res.on("close", () -> videoStream.destroy());
return true;
}
- // if (range == null) range = "bytes=0-";
- final ranges = ~/[-=]/g.split(range);
- var start = Std.parseFloat(ranges[1]);
- if (Utils.isOutOfRange(start, 0, videoSize - 1)) start = 0;
- final CHUNK_SIZE = 1024 * 1024 * 5; // 5 MB
- var end = Std.parseFloat(ranges[2]);
- if (Math.isNaN(end)) end = start + CHUNK_SIZE;
- if (Utils.isOutOfRange(end, start, videoSize - 1)) end = videoSize - 1;
+ final range = parseRangeHeader(rangeHeader, videoSize);
+ final start = range.start;
+ final end = range.end;
final contentLength = end - start + 1;
- res.setHeader("Content-Range", 'bytes ${start}-${end}/${videoSize}');
+ res.setHeader("Content-Range", 'bytes $start-$end/$videoSize');
res.setHeader("Content-Length", '$contentLength');
// HTTP Status 206 for Partial Content
res.statusCode = 206;
@@ -151,9 +149,24 @@ class HttpServer {
final videoStream = Fs.createReadStream(filePath, {start: cast start, end: cast end});
// stream the video chunk to the client
videoStream.pipe(res);
+ res.on("error", () -> videoStream.destroy());
+ res.on("close", () -> videoStream.destroy());
return true;
}
+ static function parseRangeHeader(rangeHeader:String, videoSize:Float):{start:Float, end:Float} {
+ final ranges = ~/[-=]/g.split(rangeHeader);
+ var start = Std.parseFloat(ranges[1]);
+ if (Utils.isOutOfRange(start, 0, videoSize - 1)) start = 0;
+ var end = Std.parseFloat(ranges[2]);
+ if (Math.isNaN(end)) end = start + CHUNK_SIZE;
+ if (Utils.isOutOfRange(end, start, videoSize - 1)) end = videoSize - 1;
+ return {
+ start: start,
+ end: end
+ };
+ }
+
static function isMediaExtension(ext:String):Bool {
return ext == "mp4" || ext == "webm" || ext == "mp3" || ext == "wav";
}
@@ -175,18 +188,17 @@ class HttpServer {
static function proxyUrl(req:IncomingMessage, res:ServerResponse):Bool {
final url = req.url.replace("/proxy?url=", "");
final proxy = proxyRequest(url, req, res, proxyReq -> {
- final url = proxyReq.headers["location"];
- if (url == null) return false;
+ final url = proxyReq.headers["location"] ?? return false;
final proxy2 = proxyRequest(url, req, res, proxyReq -> false);
if (proxy2 == null) {
res.end('Proxy error: multiple redirects for url $url');
return true;
}
- req.pipe(proxy2, {end: true});
+ req.pipe(proxy2);
return true;
});
if (proxy == null) return false;
- req.pipe(proxy, {end: true});
+ req.pipe(proxy);
return true;
}
@@ -209,7 +221,7 @@ class HttpServer {
if (fn(proxyReq)) return;
proxyReq.headers["Content-Type"] = "application/octet-stream";
res.writeHead(proxyReq.statusCode, proxyReq.headers);
- proxyReq.pipe(res, {end: true});
+ proxyReq.pipe(res);
});
proxy.on("error", err -> {
res.end('Proxy error: ${url.href}');
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage