/** * @license * Copyright 2017 Google Inc. * SPDX-License-Identifier: Apache-2.0
*/
importassert from 'assert'; import {readFile, readFileSync} from 'fs'; import {
createServer as createHttpServer,
type IncomingMessage,
type RequestListener,
type Server as HttpServer,
type ServerResponse,
} from 'http'; import {
createServer as createHttpsServer,
type Server as HttpsServer,
type ServerOptions as HttpsServerOptions,
} from 'https'; import type {AddressInfo} from 'net'; import {join} from 'path'; import type {Duplex} from 'stream'; import {gzip} from 'zlib';
import {getType as getMimeType} from 'mime'; import {Server as WebSocketServer, type WebSocket} from 'ws';
if (sslOptions) { this.#server = createHttpsServer(sslOptions, this.#onRequest);
} else { this.#server = createHttpServer(this.#onRequest);
} this.#server.on('connection', this.#onServerConnection); // Disable this as sometimes the socket will timeout // We rely on the fact that we will close the server at the end this.#server.keepAliveTimeout = 0; this.#server.on('clientError', err => { if ( 'code' in err &&
err.code === 'ERR_SSL_SSLV3_ALERT_CERTIFICATE_UNKNOWN'
) { return;
}
console.error('test-server client error', err);
}); this.#wsServer = new WebSocketServer({server: this.#server}); this.#wsServer.on('connection', this.#onWebSocketConnection);
}
#onServerConnection = (connection: Duplex): void => { this.#connections.add(connection); // ECONNRESET is a legit error given // that tab closing simply kills process.
connection.on('error', error => { if ((error as NodeJS.ErrnoException).code !== 'ECONNRESET') { throw error;
}
});
connection.once('close', () => { returnthis.#connections.delete(connection);
});
};
get port(): number { return (this.#server.address() as AddressInfo).port;
}
reset(): void { this.#routes.clear(); this.#auths.clear(); this.#csp.clear(); this.#gzipRoutes.clear(); const error = new Error('Static Server has been reset'); for (const subscriber of this.#requestSubscribers.values()) {
subscriber.reject.call(undefined, error);
} this.#requestSubscribers.clear(); for (const request of this.#requests.values()) { if (!request.writableEnded) {
request.destroy();
}
} this.#requests.clear();
}
if (this.#cachedPathPrefix && filePath.startsWith(this.#cachedPathPrefix)) { if (request.headers['if-modified-since']) {
response.statusCode = 304; // not modified
response.end(); return;
}
response.setHeader('Cache-Control', 'public, max-age=31536000');
response.setHeader('Last-Modified', this.#startTime.toISOString());
} else {
response.setHeader('Cache-Control', 'no-cache, no-store');
} const csp = this.#csp.get(pathName); if (csp) {
response.setHeader('Content-Security-Policy', csp);
}
readFile(filePath, (err, data) => { // This can happen if the request is not awaited but started // in the test and get clean via `reset()` if (response.writableEnded) { return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.