<commit_before>// Initializes (start) HTTP and RPC server listeners.
// Used as last step in `cli/server.js`
//
// Emits sub events `init:server.https` and `init:server.http`
//


'use strict';


// stdlib
var fs    = require('fs');
var path  = require('path');
var http  = require('http');
var https = require('https');
var url   = require('url');
var querystring = require('querystring');


// 3rd-party
var _        = require('lodash');
var async    = require('async');
var parseURL = require('pointer').parseURL;


// internal
var env = require('../env');


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


// Parse binding config and returns a parsed map:
//
//  {
//    '127.0.0.1:3000': {
//      address: '127.0.0.1',
//      port:    3000,
//      ssl:     null,
//      hosts:  [ 'localhost', ... ]
//    },
//    // ...
//  }
//
function extractBindings(config, mainApp, logger) {
  var result = {};

  // Collect non-SSL bindings.
  _.forEach(config, function (options, apiPath) {
    if (apiPath === '_') {
      return; // skip special case keyword
    }

    if (!result[options.listen]) {
      result[options.listen] = {
        address:   options.listen.address,
        port:      options.listen.port,
        forwarded: options.forwarded,
        hosts:     [],
        ssl:       null
      };
    }
  });

  // Collect SSL bindings.
  _.forEach(config, function (options, apiPath) {

    if (!options.ssl) { return; }

    if (apiPath === '_') {
      return; // skip special case keyword
    }

    if (!result[options.ssl.listen]) {
      result[options.ssl.listen] = {
        address:   options.ssl.listen.address,
        port:      options.ssl.listen.port,
        forwarded: options.ssl.forwarded,
        hosts:     [],
        ssl:       _.omit(options.ssl, 'listen')
      };

      // Read files.
      [ 'key', 'cert' ].forEach(function (val) {
        if (!options.ssl[val]) { return; }

        var filename = path.resolve(mainApp.root, options.ssl[val]);

        try {
          result[options.ssl.listen].ssl[val] = fs.readFileSync(filename, 'utf8');
        } catch (err) {
          logger.error('Can\'t read %s-file from SSL config (%s): %s', val, filename, err);
        }
      });
    }
  });

  // Fill-in host lists that should be served by <address:port>
  _.forEach(config, function (options, apiPath) {
    if (apiPath === '_') {
      return; // skip special case keyword
    }

    var host = parseURL(options.mount).host || '*';

    // For non-SSL.
    if (result[options.listen].hosts.indexOf(host) < 0) {
      result[options.listen].hosts.push(host);
    }

    // For SSL.
    if (options.ssl && result[options.ssl.listen].hosts.indexOf(host) < 0) {
      result[options.ssl.listen].hosts.push(host);
    }
  });

  return result;
}


// Returns protocol name of `req` request object.
// If `isForwarded` is true, it will respect X-Forwarded-* headers used when
// Nodeca is behind a proxy.
//
function getRequestProtocol(req, isForwarded) {
  if (isForwarded) {
    if (req.headers['x-forwarded-ssl'] === 'on') {
      return 'https';
    }

    if (req.headers['x-forwarded-scheme']) {
      return req.headers['x-forwarded-scheme'];
    }

    if (req.headers['x-forwarded-proto']) {
      return req.headers['x-forwarded-proto'].split(/\s*,\s*/)[0];
    }
  }

  return req.connection.encrypted ? 'https' : 'http';
}


// Returns remote IP address of `req` request object.
// If `isForwarded` is true, it will respect X-Forwarded-For header used when
// Nodeca is behind a proxy.
//
function getRequestRemoteAddress(req, isForwarded) {
  if (isForwarded && req.headers['x-forwarded-for']) {
    // X-Forwarded-For can contain chain of proxies.
    return req.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
  }

  return req.connection.remoteAddress;
}


// Takes a params hash (can be nested) and tries to parse each string-value as
// number or boolean. Returns a new hash with parsed values.
//
/*function castParamTypes(inputValue) {
  var parsedValue;

  if (_.isArray(inputValue)) {
    return _.map(inputValue, castParamTypes);

  } else if (_.isObject(inputValue)) {
    parsedValue = {};

    _.forEach(inputValue, function (value, key) {
      parsedValue[key] = castParamTypes(value);
    });

    return parsedValue;

  } else if ('true' === inputValue) {
    return true;

  } else if ('false' === inputValue) {
    return false;

  } else if (/^[0-9\.\-]+$/.test(inputValue)) {
    parsedValue = Number(inputValue);
    return String(parsedValue) === inputValue ? parsedValue : inputValue;

  } else {
    return inputValue;
  }
}*/


// Parses URL query string and resolves numbers and booleans.
//
function parseQueryString(inputQuery) {
  if (!inputQuery) {
    return {};
  }

  return querystring.parse(String(inputQuery));
}


// MODULE EXPORTS //////////////////////////////////////////////////////////////


// starts http(s) server(s) and attach application listener to it
//
module.exports = function (N) {

  N.wire.on('init:server', function models_init(N, cb) {
    var bindings = extractBindings(N.config.bind, N.mainApp, N.logger),
        handle_invalid_host = N.config.bind._;

    //<commit_msg>Polished proxy headers processing (ip, proto)<commit_after>// Initializes (start) HTTP and RPC server listeners.
// Used as last step in `cli/server.js`
//
// Emits sub events `init:server.https` and `init:server.http`
//


'use strict';


// stdlib
var fs    = require('fs');
var path  = require('path');
var http  = require('http');
var https = require('https');
var url   = require('url');
var querystring = require('querystring');


// 3rd-party
var _        = require('lodash');
var async    = require('async');
var parseURL = require('pointer').parseURL;


// internal
var env = require('../env');


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


// Parse binding config and returns a parsed map:
//
//  {
//    '127.0.0.1:3000': {
//      address: '127.0.0.1',
//      port:    3000,
//      ssl:     null,
//      hosts:  [ 'localhost', ... ]
//    },
//    // ...
//  }
//
function extractBindings(config, mainApp, logger) {
  var result = {};

  // Collect non-SSL bindings.
  _.forEach(config, function (options, apiPath) {
    if (apiPath === '_') {
      return; // skip special case keyword
    }

    if (!result[options.listen]) {
      result[options.listen] = {
        address:   options.listen.address,
        port:      options.listen.port,
        forwarded: options.forwarded,
        hosts:     [],
        ssl:       null
      };
    }
  });

  // Collect SSL bindings.
  _.forEach(config, function (options, apiPath) {

    if (!options.ssl) { return; }

    if (apiPath === '_') {
      return; // skip special case keyword
    }

    if (!result[options.ssl.listen]) {
      result[options.ssl.listen] = {
        address:   options.ssl.listen.address,
        port:      options.ssl.listen.port,
        forwarded: options.ssl.forwarded,
        hosts:     [],
        ssl:       _.omit(options.ssl, 'listen')
      };

      // Read files.
      [ 'key', 'cert' ].forEach(function (val) {
        if (!options.ssl[val]) { return; }

        var filename = path.resolve(mainApp.root, options.ssl[val]);

        try {
          result[options.ssl.listen].ssl[val] = fs.readFileSync(filename, 'utf8');
        } catch (err) {
          logger.error('Can\'t read %s-file from SSL config (%s): %s', val, filename, err);
        }
      });
    }
  });

  // Fill-in host lists that should be served by <address:port>
  _.forEach(config, function (options, apiPath) {
    if (apiPath === '_') {
      return; // skip special case keyword
    }

    var host = parseURL(options.mount).host || '*';

    // For non-SSL.
    if (result[options.listen].hosts.indexOf(host) < 0) {
      result[options.listen].hosts.push(host);
    }

    // For SSL.
    if (options.ssl && result[options.ssl.listen].hosts.indexOf(host) < 0) {
      result[options.ssl.listen].hosts.push(host);
    }
  });

  return result;
}


// Returns protocol name of `req` request object.
// If `isForwarded` is true, it will respect X-Forwarded-* headers used when
// Nodeca is behind a proxy.
//
function getRequestProtocol(req, isForwarded) {
  if (!isForwarded) { return req.connection.encrypted ? 'https' : 'http'; }

  if (req.headers['x-forwarded-ssl'] === 'on') { return 'https'; }

  if (req.headers['x-forwarded-scheme']) {
    return req.headers['x-forwarded-scheme'];
  }

  if (req.headers['x-forwarded-proto']) {
    return req.headers['x-forwarded-proto'].split(/\s*,\s*/)[0];
  }

  return req.connection.encrypted ? 'https' : 'http';
}


// Returns remote IP address of `req` request object.
// If `isForwarded` is true, it will respect `X-Real-IP` and `X-Forwarded-For`
// header (when Nodeca is behind a proxy).
//
function getRequestRemoteAddress(req, isForwarded) {
  if (!isForwarded) { return req.connection.remoteAddress; }

  if (req.headers['x-real-ip']) { return req.headers['x-real-ip']; }

  if (req.headers['x-forwarded-for']) {
    // X-Forwarded-For can contain chain of proxies.
    return req.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
  }

  return req.connection.remoteAddress;
}


// Parses URL query string and resolves numbers and booleans.
//
function parseQueryString(inputQuery) {
  if (!inputQuery) {
    return {};
  }

  return querystring.parse(String(inputQuery));
}


// MODULE EXPORTS //////////////////////////////////////////////////////////////


// starts http(s) server(s) and attach application listener to it
//
module.exports = function (N) {

  N.wire.on('init:server', function models_init(N, cb) {
    var bindings = extractBindings(N.config.bind, N.mainApp, N.logger),
        handle_invalid_host = N.config.bind._;

    //
{'fraction_non_alphanumeric': 0.18894758228362454, 'fraction_numerical': 0.005485574969524584, 'mean_word_length': 2.3181664981462755, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, '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': '2727919', 'n_tokens_mistral': 3172, 'n_tokens_neox': 3043, 'n_words': 741}