<commit_before>/**
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

let http = require('http');
let url = require('url');
let fs = require('fs');
let path = require('path');
let mime = require('mime');
let WebSocketServer = require('ws').Server;

const fulfillSymbol = Symbol('fullfill callback');
const rejectSymbol = Symbol('reject callback');

class SimpleServer {
  /**
   * @param {string} dirPath
   * @param {number} port
   * @return {!SimpleServer}
   */
  static async create(dirPath, port) {
    let server = new SimpleServer(dirPath, port);
    await new Promise(x => server._server.once('listening', x));
    return server;
  }

  /**
   * @param {string} dirPath
   * @param {number} port
   */
  constructor(dirPath, port) {
    this._server = http.createServer(this._onRequest.bind(this));
    this._server.on('connection', socket => this._onSocket(socket));
    this._wsServer = new WebSocketServer({server: this._server});
    this._wsServer.on('connection', this._onWebSocketConnection.bind(this));
    this._server.listen(port);
    this._dirPath = dirPath;

    /** @type {!Set<!net.Socket>} */
    this._sockets = new Set();

    /** @type {!Map<string, function(!IncomingMessage, !ServerResponse)>} */
    this._routes = new Map();
    /** @type {!Map<string, !Promise>} */
    this._requestSubscribers = new Map();
  }

  _onSocket(socket) {
    this._sockets.add(socket);
    socket.once('close', () => this._sockets.delete(socket));
  }

  /**
   * @return {!Promise}
   */
  async stop() {
    this.reset();
    for (let socket of this._sockets)
      socket.destroy();
    this._sockets.clear();
    await new Promise(x => this._server.close(x));
  }

  /**
   * @param {string} path
   * @param {function(!IncomingMessage, !ServerResponse)} handler
   */
  setRoute(path, handler) {
    this._routes.set(path, handler);
  }

  /**
   * @param {string} fromPath
   * @param {string} toPath
   */
  setRedirect(from, to) {
    this.setRoute(from, (req, res) => {
      res.writeHead(302, { location: to });
      res.end();
    });
  }

  /**
   * @param {string} path
   * @return {!Promise<!IncomingMessage>}
   */
  waitForRequest(path) {
    let promise = this._requestSubscribers.get(path);
    if (promise)
      return promise;
    let fulfill, reject;
    promise = new Promise((f, r) => {
      fulfill = f;
      reject = r;
    });
    promise[fulfillSymbol] = fulfill;
    promise[rejectSymbol] = reject;
    this._requestSubscribers.set(path, promise);
    return promise;
  }

  reset() {
    this._routes.clear();
    let error = new Error('Static Server has been reset');
    for (let subscriber of this._requestSubscribers.values())
      subscriber[rejectSymbol].call(null, error);
    this._requestSubscribers.clear();
  }

  _onRequest(request, response) {
    let pathName = url.parse(request.url).path;
    // Notify request subscriber.
    if (this._requestSubscribers.has(pathName))
      this._requestSubscribers.get(pathName)[fulfillSymbol].call(null, request);
    let handler = this._routes.get(pathName);
    if (handler)
      handler.call(null, request, response);
    else
      this.defaultHandler(request, response);
  }

  /**
   * @param {!IncomingMessage} request
   * @param {!ServerResponse} response
   */
  defaultHandler(request, response) {
    let pathName = url.parse(request.url).path;
    if (pathName === '/')
      pathName = '/index.html';
    pathName = path.join(this._dirPath, pathName.substring(1));

    fs.readFile(pathName, function(err, data) {
      if (err) {<commit_msg>Handle ECONNRESET error in SimpleServer<commit_after>/**
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

let http = require('http');
let url = require('url');
let fs = require('fs');
let path = require('path');
let mime = require('mime');
let WebSocketServer = require('ws').Server;

const fulfillSymbol = Symbol('fullfill callback');
const rejectSymbol = Symbol('reject callback');

class SimpleServer {
  /**
   * @param {string} dirPath
   * @param {number} port
   * @return {!SimpleServer}
   */
  static async create(dirPath, port) {
    let server = new SimpleServer(dirPath, port);
    await new Promise(x => server._server.once('listening', x));
    return server;
  }

  /**
   * @param {string} dirPath
   * @param {number} port
   */
  constructor(dirPath, port) {
    this._server = http.createServer(this._onRequest.bind(this));
    this._server.on('connection', socket => this._onSocket(socket));
    this._wsServer = new WebSocketServer({server: this._server});
    this._wsServer.on('connection', this._onWebSocketConnection.bind(this));
    this._server.listen(port);
    this._dirPath = dirPath;

    /** @type {!Set<!net.Socket>} */
    this._sockets = new Set();

    /** @type {!Map<string, function(!IncomingMessage, !ServerResponse)>} */
    this._routes = new Map();
    /** @type {!Map<string, !Promise>} */
    this._requestSubscribers = new Map();
  }

  _onSocket(socket) {
    this._sockets.add(socket);
    socket.once('close', () => this._sockets.delete(socket));
  }

  /**
   * @return {!Promise}
   */
  async stop() {
    this.reset();
    for (let socket of this._sockets)
      socket.destroy();
    this._sockets.clear();
    await new Promise(x => this._server.close(x));
  }

  /**
   * @param {string} path
   * @param {function(!IncomingMessage, !ServerResponse)} handler
   */
  setRoute(path, handler) {
    this._routes.set(path, handler);
  }

  /**
   * @param {string} fromPath
   * @param {string} toPath
   */
  setRedirect(from, to) {
    this.setRoute(from, (req, res) => {
      res.writeHead(302, { location: to });
      res.end();
    });
  }

  /**
   * @param {string} path
   * @return {!Promise<!IncomingMessage>}
   */
  waitForRequest(path) {
    let promise = this._requestSubscribers.get(path);
    if (promise)
      return promise;
    let fulfill, reject;
    promise = new Promise((f, r) => {
      fulfill = f;
      reject = r;
    });
    promise[fulfillSymbol] = fulfill;
    promise[rejectSymbol] = reject;
    this._requestSubscribers.set(path, promise);
    return promise;
  }

  reset() {
    this._routes.clear();
    let error = new Error('Static Server has been reset');
    for (let subscriber of this._requestSubscribers.values())
      subscriber[rejectSymbol].call(null, error);
    this._requestSubscribers.clear();
  }

  _onRequest(request, response) {
    request.on('error', error => {
      if (error.code === 'ECONNRESET')
        response.end();
      else
        throw error;
    });
    let pathName = url.parse(request.url).path;
    // Notify request subscriber.
    if (this._requestSubscribers.has(pathName))
      this._requestSubscribers.get(pathName)[fulfillSymbol].call(null, request);
    let handler = this._routes.get(pathName);
    if (handler)
      handler.call(null, request, response);
    else
      this.defaultHandler(request, response);
  }

  /**
   * @param {!IncomingMessage} request
   * @param {!ServerResponse} response
   */
  defaultHandler(request, response) {
    let pathName = url.parse(request.url).path;
    if (pathName === '/')
      pathName = '/index.html';
    pathName = path.join(this._dirPath, pathName.substring(1));

    fs.readFile(pathName, function(err, data) {
      if (err) {
{'fraction_non_alphanumeric': 0.1469678953626635, 'fraction_numerical': 0.002853745541022592, 'mean_word_length': 3.2891381947985723, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2601815', 'n_tokens_mistral': 2607, 'n_tokens_neox': 2580, 'n_words': 653}