Source: server/protocol/http.js

const JsonRpcServerProtocol = require("./base");
const { errorToStatus } = require("../../util/constants");

/**
 * Creates instance of HttpServerProtocol
 * @extends JsonRpcServerProtocol
 *
 */
class HttpServerProtocol extends JsonRpcServerProtocol {
  /**
   * As well as all the params and properties in [JsonRpcServerProtocol]{@link JsonRpcServerProtocol}
   * the following properties are available.
   *
   * @property {class} response HTTP response object
   * @property {object} headers={"Content-Type":"application/json"} HTTP response headers
   */
  constructor(factory, client, response, version, delimiter) {
    super(factory, client, version, delimiter);
    this.response = response;
    this.headers = {
      "Content-Type": "application/json"
    };
    this.status = null;
  }

  /**
   * Send message to the client.
   *
   * @param {string} message Stringified JSON-RPC message object
   */
  writeToClient(message) {
    const json = JSON.parse(message);
    if (!this.status) {
      // set the status code if it has not been overwritten
      if (json.error) {
        this.setResponseStatus({
          errorCode: json.error.code
        });
      } else {
        this.status = 200;
      }
    }
    this.response.writeHead(this.status, this.headers).end(message);
  }

  /**
   * Calls `emit` on factory with the event name being `message.method` and
   * the data being `message`.
   *
   * Responds to client with 204 status.
   *
   * @param {object} message JSON-RPC message object
   */
  gotNotification(message) {
    super.gotNotification(message.method, message);
    this.setResponseStatus({
      notification: true
    });
    this.response.writeHead(this.status, this.headers).end();
  }

  /**
   * Registers the `event` data listener when client connects.
   *
   * Pushes received data into `messageBuffer` and calls
   * [_waitForData]{@link JsonRpcServerProtocol#_waitForData}.
   *
   * The HTTP server does not use the delimiter since the completion of a request indicates
   * the end of data.
   *
   * @extends JsonRpcServerProtocol.clientConnected
   */
  clientConnected() {
    this.client.on(this.event, (chunk) => {
      this.messageBuffer.push(chunk);
    });
    this.client.on("end", () => {
      this._validateData(this.messageBuffer.emptyBuffer());
      this.factory._removeFromArray(this, this.factory.pendingRequests);
    });
  }

  /**
   * Set response status code
   *
   * @param {object} options
   * @param {number} options.errorCode The JSON-RPC error code to lookup a corresponding status code for
   * @param {number} options.status The HTTP status code (will override the errorCode)
   * @param {boolean} options.notification Inidicate if setting header for notification (will override other options with 204 status)
   */
  setResponseStatus({ errorCode, status, notification }) {
    this.status = 200;
    if (errorCode) {
      this.status = errorToStatus[String(errorCode)];
    }
    if (status) {
      this.status = status;
    }
    if (notification) {
      this.status = 204; // notification responses must be 204 per spec, so no point in allowing an override
    }
  }
}

module.exports = HttpServerProtocol;