From 84ff20f19370bb22c84749400d84fe1fbf3f13fb Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Thu, 10 Dec 2020 09:47:06 -0800 Subject: [PATCH] test: fix test server on Node 15 (#4668) This patch fixes a bug in our test server that manifests itself in Node 15. Context: Node 14 does not support Apple Silicon (and probably will not), so we currently have to run tests on Node 15 on new macs. --- utils/testserver/index.js | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/utils/testserver/index.js b/utils/testserver/index.js index 9927d6d0ea..335134b712 100644 --- a/utils/testserver/index.js +++ b/utils/testserver/index.js @@ -19,11 +19,16 @@ const https = require('https'); const url = require('url'); const fs = require('fs'); const path = require('path'); +const zlib = require('zlib'); +const util = require('util'); const WebSocketServer = require('ws').Server; const fulfillSymbol = Symbol('fullfil callback'); const rejectSymbol = Symbol('reject callback'); +const readFileAsync = util.promisify(fs.readFile.bind(fs)); +const gzipAsync = util.promisify(zlib.gzip.bind(zlib)); + class TestServer { /** * @param {string} dirPath @@ -236,7 +241,7 @@ class TestServer { * @param {!http.ServerResponse} response * @param {string|undefined} filePath */ - serveFile(request, response, filePath) { + async serveFile(request, response, filePath) { let pathName = url.parse(request.url).path; if (!filePath) { if (pathName === '/') @@ -258,27 +263,29 @@ class TestServer { if (this._csp.has(pathName)) response.setHeader('Content-Security-Policy', this._csp.get(pathName)); - fs.readFile(filePath, (err, data) => { - if (err) { - response.statusCode = 404; - response.end(`File not found: ${filePath}`); - return; - } - const extension = filePath.substring(filePath.lastIndexOf('.') + 1); - const mimeType = extensionToMime[extension] || 'application/octet-stream'; - const isTextEncoding = /^text\/|^application\/(javascript|json)/.test(mimeType); - const contentType = isTextEncoding ? `${mimeType}; charset=utf-8` : mimeType; - response.setHeader('Content-Type', contentType); - if (this._gzipRoutes.has(pathName)) { - response.setHeader('Content-Encoding', 'gzip'); - const zlib = require('zlib'); - zlib.gzip(data, (_, result) => { - response.end(result); - }); - } else { - response.end(data); - } - }); + const {err, data} = await readFileAsync(filePath).then(data => ({data})).catch(err => ({err})); + // The HTTP transaction might be already terminated after async hop here - do nothing in this case. + if (response.writableEnded) + return; + if (err) { + response.statusCode = 404; + response.end(`File not found: ${filePath}`); + return; + } + const extension = filePath.substring(filePath.lastIndexOf('.') + 1); + const mimeType = extensionToMime[extension] || 'application/octet-stream'; + const isTextEncoding = /^text\/|^application\/(javascript|json)/.test(mimeType); + const contentType = isTextEncoding ? `${mimeType}; charset=utf-8` : mimeType; + response.setHeader('Content-Type', contentType); + if (this._gzipRoutes.has(pathName)) { + response.setHeader('Content-Encoding', 'gzip'); + const result = await gzipAsync(data); + // The HTTP transaction might be already terminated after async hop here. + if (!response.writableEnded) + response.end(result); + } else { + response.end(data); + } } _onWebSocketConnection(ws) {