<commit_before>"use strict";


/*global nodeca, _*/


// stdlib
var http = require('http');


// 3rd-party
var treeGet = require('nlib').Support.tree.cache.get;


// internal
var env         = require('../../../env');
var compression = require('./compression');
var logger      = nodeca.logger.getLogger('rpc');


////////////////////////////////////////////////////////////////////////////////


function log(req, res) {
  var level = 'info', message = 'OK';

  if (res.error) {
    message = res.error.message || JSON.stringify(res.error);

    if (!res.error.statusCode || 500 <= res.error.statusCode) {
      level = 'fatal';
    } else if (400 <= res.error.statusCode && 500 > res.error.statusCode) {
      level = 'error';
    } else {
      level = 'info';
    }
  }

  logger[level]('%s - %s() - "%s" - %s',
                req.connection.remoteAddress,
                req.payload.method,
                req.headers['user-agent'],
                message);
}


// Ends response with given `error`, `response` and nodeca version.
//
function end(req, res, error, response) {
  var payload, compressor, size;

  //
  // Set some obligatory headers
  //

  res.removeHeader('Accept-Ranges');

  res.setHeader('Content-Type', 'application/json; charset=UTF-8');
  res.setHeader('Server', 'Sansung Calakci');
  res.setHeader('Date',   (new Date).toUTCString());

  //
  // Prepare and stringify payload
  //

  payload = res.payload = JSON.stringify({
    version:  nodeca.runtime.version,
    error:    error,
    response: error ? null : response
  });

  //
  // Status code always OK
  //

  res.error       = error;
  res.statusCode  = 200;

  //
  // Check whenever compression is allowed by client or not
  //

  compressor = compression.is_allowed(req);

  //
  // Mark for proxies, that we can return different content (plain & gzipped),
  // depending on specified (comma-separated) headers
  //

  res.setHeader('Vary', 'Accept-Encoding');

  //
  // Return raw response, if compression is not allowed or body is too small
  //

  size = Buffer.byteLength(payload);

  if (false === compressor || 500 > size) {
    log(req, res);
    res.setHeader('Content-Length', size);
    res.end(payload);
    return;
  }

  //
  // Compress body
  //

  compression.process(compressor, payload, function (err, buffer) {
    if (err) {
      // should never happen
      nodeca.logger.fatal('Failed to compress RPC response', err);

      res.error   = err;
      res.payload = JSON.stringify({
        version:  nodeca.runtime.version,
        error:    err,
        response: null
      });

      log(req, res);
      res.end(res.payload);
      return;
    }

    //
    // Compression is allowed and succeed, set Content-Encoding
    //

    res.setHeader('Content-Encoding', compressor);
    res.setHeader('Content-Length', buffer.length);
    log(req, res);
    res.end(buffer);
  });
}


function process_error(req, res, err) {
  var message;

  //
  // user asks for request termination providing:
  //
  //    - statusCode  (Number)
  //    - body        (String|Buffer) Optional
  //

  if (err.statusCode) {
    end(req, res, {statusCode: err.statusCode, message: err.body}, null);
    return;
  }

  //
  // exceptions or fatal fuckup happened
  //

  message = ('development' !== nodeca.runtime.env) ? 'Application error'
          : (err.stack || err.toString());
  end(req, res, {statusCode: 500, message: message}, null);
}


////////////////////////////////////////////////////////////////////////////////


module.exports = function handle_rpc(req, res) {
  var payload = req.params,
      params  = payload.params || {},
      func, validation;

  // save request payload
  req.payload = payload;

  // invalid request
  if ('POST' !== req.method) {
    process_error(req, res, { statusCode: 400, body: 'Invalid request method' });
    return;
  }<commit_msg>Send headers of error for RPC<commit_after>"use strict";


/*global nodeca, _*/


// stdlib
var http = require('http');


// 3rd-party
var treeGet = require('nlib').Support.tree.cache.get;


// internal
var env         = require('../../../env');
var compression = require('./compression');
var logger      = nodeca.logger.getLogger('rpc');


////////////////////////////////////////////////////////////////////////////////


function log(req, res) {
  var level = 'info', message = 'OK';

  if (res.error) {
    message = res.error.message || JSON.stringify(res.error);

    if (!res.error.statusCode || 500 <= res.error.statusCode) {
      level = 'fatal';
    } else if (400 <= res.error.statusCode && 500 > res.error.statusCode) {
      level = 'error';
    } else {
      level = 'info';
    }
  }

  logger[level]('%s - %s() - "%s" - %s',
                req.connection.remoteAddress,
                req.payload.method,
                req.headers['user-agent'],
                message);
}


// Ends response with given `error`, `response` and nodeca version.
//
function end(req, res, error, response) {
  var payload, compressor, size;

  //
  // Set some obligatory headers
  //

  res.removeHeader('Accept-Ranges');

  res.setHeader('Content-Type', 'application/json; charset=UTF-8');
  res.setHeader('Server', 'Sansung Calakci');
  res.setHeader('Date',   (new Date).toUTCString());

  //
  // Prepare and stringify payload
  //

  payload = res.payload = JSON.stringify({
    version:  nodeca.runtime.version,
    error:    error,
    response: error ? null : response
  });

  //
  // Status code always OK
  //

  res.error       = error;
  res.statusCode  = 200;

  //
  // Check whenever compression is allowed by client or not
  //

  compressor = compression.is_allowed(req);

  //
  // Mark for proxies, that we can return different content (plain & gzipped),
  // depending on specified (comma-separated) headers
  //

  res.setHeader('Vary', 'Accept-Encoding');

  //
  // Return raw response, if compression is not allowed or body is too small
  //

  size = Buffer.byteLength(payload);

  if (false === compressor || 500 > size) {
    log(req, res);
    res.setHeader('Content-Length', size);
    res.end(payload);
    return;
  }

  //
  // Compress body
  //

  compression.process(compressor, payload, function (err, buffer) {
    if (err) {
      // should never happen
      nodeca.logger.fatal('Failed to compress RPC response', err);

      res.error   = err;
      res.payload = JSON.stringify({
        version:  nodeca.runtime.version,
        error:    err,
        response: null
      });

      log(req, res);
      res.end(res.payload);
      return;
    }

    //
    // Compression is allowed and succeed, set Content-Encoding
    //

    res.setHeader('Content-Encoding', compressor);
    res.setHeader('Content-Length', buffer.length);
    log(req, res);
    res.end(buffer);
  });
}


function process_error(req, res, err) {
  var message;

  //
  // user asks for request termination providing:
  //
  //    - statusCode  (Number)
  //    - headers     (Object)        Optional
  //    - body        (String|Buffer) Optional
  //

  if (err.statusCode) {
    end(req, res, {statusCode: err.statusCode, headers: err.headers, message: err.body}, null);
    return;
  }

  //
  // exceptions or fatal fuckup happened
  //

  message = ('development' !== nodeca.runtime.env) ? 'Application error'
          : (err.stack || err.toString());
  end(req, res, {statusCode: 500, message: message}, null);
}


////////////////////////////////////////////////////////////////////////////////


module.exports = function handle_rpc(req, res) {
  var payload = req.params,
      params  = payload.params || {},
      func, validation;

  // save request payload
  req.payload = payload;

  // invalid request
  if ('POST' !== req.method) {
    process_error(req, res, { statusCode: 400, body: 'Invalid request method' });
    return;
  }
{'fraction_non_alphanumeric': 0.18718960906659876, 'fraction_numerical': 0.005857634025213295, 'mean_word_length': 2.1006711409395975, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '1192385', 'n_tokens_mistral': 2467, 'n_tokens_neox': 2319, 'n_words': 594}