@@ -19,11 +19,16 @@ const https = require('https');
1919const url = require ( 'url' ) ;
2020const fs = require ( 'fs' ) ;
2121const path = require ( 'path' ) ;
22+ const zlib = require ( 'zlib' ) ;
23+ const util = require ( 'util' ) ;
2224const WebSocketServer = require ( 'ws' ) . Server ;
2325
2426const fulfillSymbol = Symbol ( 'fullfil callback' ) ;
2527const rejectSymbol = Symbol ( 'reject callback' ) ;
2628
29+ const readFileAsync = util . promisify ( fs . readFile . bind ( fs ) ) ;
30+ const gzipAsync = util . promisify ( zlib . gzip . bind ( zlib ) ) ;
31+
2732class TestServer {
2833 /**
2934 * @param {string } dirPath
@@ -236,7 +241,7 @@ class TestServer {
236241 * @param {!http.ServerResponse } response
237242 * @param {string|undefined } filePath
238243 */
239- serveFile ( request , response , filePath ) {
244+ async serveFile ( request , response , filePath ) {
240245 let pathName = url . parse ( request . url ) . path ;
241246 if ( ! filePath ) {
242247 if ( pathName === '/' )
@@ -258,27 +263,29 @@ class TestServer {
258263 if ( this . _csp . has ( pathName ) )
259264 response . setHeader ( 'Content-Security-Policy' , this . _csp . get ( pathName ) ) ;
260265
261- fs . readFile ( filePath , ( err , data ) => {
262- if ( err ) {
263- response . statusCode = 404 ;
264- response . end ( `File not found: ${ filePath } ` ) ;
265- return ;
266- }
267- const extension = filePath . substring ( filePath . lastIndexOf ( '.' ) + 1 ) ;
268- const mimeType = extensionToMime [ extension ] || 'application/octet-stream' ;
269- const isTextEncoding = / ^ t e x t \/ | ^ a p p l i c a t i o n \/ ( j a v a s c r i p t | j s o n ) / . test ( mimeType ) ;
270- const contentType = isTextEncoding ? `${ mimeType } ; charset=utf-8` : mimeType ;
271- response . setHeader ( 'Content-Type' , contentType ) ;
272- if ( this . _gzipRoutes . has ( pathName ) ) {
273- response . setHeader ( 'Content-Encoding' , 'gzip' ) ;
274- const zlib = require ( 'zlib' ) ;
275- zlib . gzip ( data , ( _ , result ) => {
276- response . end ( result ) ;
277- } ) ;
278- } else {
279- response . end ( data ) ;
280- }
281- } ) ;
266+ const { err, data} = await readFileAsync ( filePath ) . then ( data => ( { data} ) ) . catch ( err => ( { err} ) ) ;
267+ // The HTTP transaction might be already terminated after async hop here - do nothing in this case.
268+ if ( response . writableEnded )
269+ return ;
270+ if ( err ) {
271+ response . statusCode = 404 ;
272+ response . end ( `File not found: ${ filePath } ` ) ;
273+ return ;
274+ }
275+ const extension = filePath . substring ( filePath . lastIndexOf ( '.' ) + 1 ) ;
276+ const mimeType = extensionToMime [ extension ] || 'application/octet-stream' ;
277+ const isTextEncoding = / ^ t e x t \/ | ^ a p p l i c a t i o n \/ ( j a v a s c r i p t | j s o n ) / . test ( mimeType ) ;
278+ const contentType = isTextEncoding ? `${ mimeType } ; charset=utf-8` : mimeType ;
279+ response . setHeader ( 'Content-Type' , contentType ) ;
280+ if ( this . _gzipRoutes . has ( pathName ) ) {
281+ response . setHeader ( 'Content-Encoding' , 'gzip' ) ;
282+ const result = await gzipAsync ( data ) ;
283+ // The HTTP transaction might be already terminated after async hop here.
284+ if ( ! response . writableEnded )
285+ response . end ( result ) ;
286+ } else {
287+ response . end ( data ) ;
288+ }
282289 }
283290
284291 _onWebSocketConnection ( ws ) {
0 commit comments