Modernize the remainder of the webserver's code and enable the no-var ESLint rule

This commit also moves the content type logic into a helper method to
ever so slightly reduce duplication.
This commit is contained in:
Tim van der Meij 2024-02-11 20:10:27 +01:00
parent 0015eb2431
commit 985ba77579
No known key found for this signature in database
GPG Key ID: 8C3FD2925A5F2762

View File

@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/* eslint-disable no-var */
import fs from "fs"; import fs from "fs";
import fsPromises from "fs/promises"; import fsPromises from "fs/promises";
import http from "http"; import http from "http";
import path from "path"; import path from "path";
var mimeTypes = { const MIME_TYPES = {
".css": "text/css", ".css": "text/css",
".html": "text/html", ".html": "text/html",
".js": "application/javascript", ".js": "application/javascript",
@ -36,8 +35,7 @@ var mimeTypes = {
".bcmap": "application/octet-stream", ".bcmap": "application/octet-stream",
".ftl": "text/plain", ".ftl": "text/plain",
}; };
const DEFAULT_MIME_TYPE = "application/octet-stream";
var defaultMimeType = "application/octet-stream";
class WebServer { class WebServer {
constructor() { constructor() {
@ -58,9 +56,7 @@ class WebServer {
this.#ensureNonZeroPort(); this.#ensureNonZeroPort();
this.server = http.createServer(this.#handler.bind(this)); this.server = http.createServer(this.#handler.bind(this));
this.server.listen(this.port, this.host, callback); this.server.listen(this.port, this.host, callback);
console.log( console.log(`Server running at http://${this.host}:${this.port}/`);
"Server running at http://" + this.host + ":" + this.port + "/"
);
} }
stop(callback) { stop(callback) {
@ -71,11 +67,11 @@ class WebServer {
#ensureNonZeroPort() { #ensureNonZeroPort() {
if (!this.port) { if (!this.port) {
// If port is 0, a random port will be chosen instead. Do not set a host // If port is 0, a random port will be chosen instead. Do not set a host
// name to make sure that the port is synchronously set by .listen(). // name to make sure that the port is synchronously set by `.listen()`.
var server = http.createServer().listen(0); const server = http.createServer().listen(0);
var address = server.address(); const address = server.address();
// .address().port being available synchronously is merely an // `.address().port` being available synchronously is merely an
// implementation detail. So we are defensive here and fall back to some // implementation detail, so we are defensive here and fall back to a
// fixed port when the address is not available yet. // fixed port when the address is not available yet.
this.port = address ? address.port : 8000; this.port = address ? address.port : 8000;
server.close(); server.close();
@ -300,13 +296,10 @@ class WebServer {
response.end(); response.end();
}); });
const extension = path.extname(filePath).toLowerCase();
const contentType = mimeTypes[extension] || defaultMimeType;
if (!this.disableRangeRequests) { if (!this.disableRangeRequests) {
response.setHeader("Accept-Ranges", "bytes"); response.setHeader("Accept-Ranges", "bytes");
} }
response.setHeader("Content-Type", contentType); response.setHeader("Content-Type", this.#getContentType(filePath));
response.setHeader("Content-Length", fileSize); response.setHeader("Content-Length", fileSize);
if (this.cacheExpirationTime > 0) { if (this.cacheExpirationTime > 0) {
const expireTime = new Date(); const expireTime = new Date();
@ -328,11 +321,8 @@ class WebServer {
response.end(); response.end();
}); });
const extension = path.extname(filePath).toLowerCase();
const contentType = mimeTypes[extension] || defaultMimeType;
response.setHeader("Accept-Ranges", "bytes"); response.setHeader("Accept-Ranges", "bytes");
response.setHeader("Content-Type", contentType); response.setHeader("Content-Type", this.#getContentType(filePath));
response.setHeader("Content-Length", end - start); response.setHeader("Content-Length", end - start);
response.setHeader( response.setHeader(
"Content-Range", "Content-Range",
@ -341,19 +331,24 @@ class WebServer {
response.writeHead(206); response.writeHead(206);
stream.pipe(response); stream.pipe(response);
} }
#getContentType(filePath) {
const extension = path.extname(filePath).toLowerCase();
return MIME_TYPES[extension] || DEFAULT_MIME_TYPE;
}
} }
// This supports the "Cross-origin" test in test/unit/api_spec.js // This supports the "Cross-origin" test in test/unit/api_spec.js
// It is here instead of test.js so that when the test will still complete as // It is here instead of test.js so that when the test will still complete as
// expected if the user does "gulp server" and then visits // expected if the user does "gulp server" and then visits
// http://localhost:8888/test/unit/unit_test.html?spec=Cross-origin // http://localhost:8888/test/unit/unit_test.html?spec=Cross-origin
function crossOriginHandler(req, res) { function crossOriginHandler(request, response) {
if (req.url === "/test/pdfs/basicapi.pdf?cors=withCredentials") { if (request.url === "/test/pdfs/basicapi.pdf?cors=withCredentials") {
res.setHeader("Access-Control-Allow-Origin", req.headers.origin); response.setHeader("Access-Control-Allow-Origin", request.headers.origin);
res.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Credentials", "true");
} }
if (req.url === "/test/pdfs/basicapi.pdf?cors=withoutCredentials") { if (request.url === "/test/pdfs/basicapi.pdf?cors=withoutCredentials") {
res.setHeader("Access-Control-Allow-Origin", req.headers.origin); response.setHeader("Access-Control-Allow-Origin", request.headers.origin);
} }
} }