<commit_before>/**
 * @file 代理请求转发到其他服务器
 * @author zdying
 */

'use strict';

var http = require('http');
var https = require('https');
var zlib = require('zlib');

// var execDirectives = require('../../../directives').execDirectives;

module.exports = {
  response: function (ctx, request, response, next) {
    var proxyInfo = ctx.proxy;
    // var rewriteRule = proxyInfo.rewriteRule;
    var isHTTPS = proxyInfo.protocol === 'https:';
    var self = this;
    // var execResult;

    // proxyInfo.headers['accept-encoding'] = 'gzip,deflate';
    // if ('content-length' in proxyInfo.headers) {
    //   proxyInfo.headers['content-length'] = Buffer.byteLength(request.body || '');
    // }

    // TODO 支持读取配置，决定是否拒绝
    if (isHTTPS) {
      proxyInfo.rejectUnauthorized = false;
    }

    if (!proxyInfo.proxyPass && !proxyInfo.hostname) {
      log.debug(request.url, 'has no proxy_pass');
      // execResult = execDirectives(rewriteRule, {
      //   response: response,
      //   rewriteRule: rewriteRule
      // }, 'response');

      // execResult.then(function (values) {
      //   if (!response.finished) {
      //     response.end('');
      //   }

      //   // /**
      //   //  * Emitted when a response is end. This event is emitted only once.
      //   //  * @event ProxyServer#response
      //   //  * @property {http.ServerResponse} response response object
      //   //  */
      //   // self.emit('response', request, response);
      //   next();
      // });
      // TODO 如果在指令中再次调用了`end()`方法，会导致调用两次end，能否优化？？？
      response.end('');

      return;
    }

    var requestOptions = getRequestOption(proxyInfo);

    log.debug('request remote server proxy info', JSON.stringify(proxyInfo));
    log.debug('request remote server request option', JSON.stringify(requestOptions));
    log.debug('request original info', JSON.stringify(request.originReq));

    var proxy = (isHTTPS ? https : http).request(requestOptions, function (res) {
      log.debug('request remote result', JSON.stringify(res.headers));

      var contentType = res.headers['content-type'];
      var encoding = res.headers['content-encoding'];
      var needUnZip = encoding === 'gzip' || encoding === 'deflate';
      var isTextFile = /(text|xml|html|plain|json|javascript|css)/.test(contentType);

      response.headers = res.headers;
      response.statusCode = res.statusCode;
      response.statusMessage = res.statusMessage;

      if (needUnZip) {
        delete res.headers['content-encoding'];
        delete res.headers['content-length'];
        res.headers['x-hiproxy-origin-content-encoding'] = encoding;
      }

      // 这里暂时不执行
      // execDirectives(rewriteRule, {
      //   response: response,
      //   rewriteRule: rewriteRule
      // }, 'response');

      /**
       * Emitted each time the server set response info (eg: headers).
       * @event ProxyServer#setResponse
       * @property {http.ServerResponse} response request object
       */
      self.emit('setResponse', response);

      // response.pipe(res)

      /*
      res.pause()

      log.warn('request was paused:'.red, _url.bold.red)

      setTimeout(function(){
          res.resume()
          log.warn('request was resumed:'.red, _url.bold.red)
      }, 5000)
      */

      if (needUnZip && isTextFile) {
        var unzipStream = encoding === 'gzip' ? zlib.createUnzip() : zlib.createInflate();

        // unzipStream.on('data', function (chunk) {
        //   self.emit('data', chunk, request, response);
        // });

        /* istanbul ignore next */
        unzipStream.on('error', function (err) {
          log.error('error ==>', err);
        });

        res.pipe(unzipStream).pipe(response);
        // .on('end', function () {
        // request.res = res;

        // /**
        //  * Emitted when a response is end. This event is emitted only once.
        //  * @event ProxyServer#response
        //  * @property {http.ServerResponse} response response object
        //  */
        // self.emit('response', request, response);

        // next();
        // });
      } else {
        // res.on('data', function (chunk) {
        //   /**
        //    * Emitted whenever the response stream received some chunk of data.
        //    * @event ProxyServer#data
        //    * @property {Buffer} data response data
        //    */
        //   self.emit('data', chunk, request, response);
        // });

        // res.on('end', function () {
        //   request.res = res;

        //   /**
        //    * Emitted when a response is end. This event is emitted only once.
        //    * @event ProxyServer#response
        //    * @property {http.ServerResponse} response response object
        //    */
        //   self.emit('response', request, response);

        //   next();
        // });

        res.pipe(response);
      }

      res.on('end', function () {
        // request.res = res;

        // /**
        //  * Emitted when a response is end. This event is emitted only once.
        //  * @event ProxyServer#response
        //  * @property {http.ServerResponse} response response object
        //  */
        // self.emit('response', request, response);

        next();
      });

      // res.pipe(response);
    });

    proxy.on('error', function (e) {
      /* istanbul ignore next */
      if (e.code === 'ENOTFOUND') {
        response.statusCode = 404;
      } else {
        response.statusCode = 500;
      }

      response.end(e.stack);

      log.error('proxy error:', request.url);
      log.detail(e.stack);

      // self.emit('response', request, response);
<commit_msg>add `response.originRes` object<commit_after>/**
 * @file 代理请求转发到其他服务器
 * @author zdying
 */

'use strict';

var http = require('http');
var https = require('https');
var zlib = require('zlib');

// var execDirectives = require('../../../directives').execDirectives;

module.exports = {
  response: function (ctx, request, response, next) {
    var proxyInfo = ctx.proxy;
    // var rewriteRule = proxyInfo.rewriteRule;
    var isHTTPS = proxyInfo.protocol === 'https:';
    var self = this;
    // var execResult;

    // proxyInfo.headers['accept-encoding'] = 'gzip,deflate';
    // if ('content-length' in proxyInfo.headers) {
    //   proxyInfo.headers['content-length'] = Buffer.byteLength(request.body || '');
    // }

    // TODO 支持读取配置，决定是否拒绝
    if (isHTTPS) {
      proxyInfo.rejectUnauthorized = false;
    }

    if (!proxyInfo.proxyPass && !proxyInfo.hostname) {
      log.debug(request.url, 'has no proxy_pass');
      // execResult = execDirectives(rewriteRule, {
      //   response: response,
      //   rewriteRule: rewriteRule
      // }, 'response');

      // execResult.then(function (values) {
      //   if (!response.finished) {
      //     response.end('');
      //   }

      //   // /**
      //   //  * Emitted when a response is end. This event is emitted only once.
      //   //  * @event ProxyServer#response
      //   //  * @property {http.ServerResponse} response response object
      //   //  */
      //   // self.emit('response', request, response);
      //   next();
      // });
      // TODO 如果在指令中再次调用了`end()`方法，会导致调用两次end，能否优化？？？
      response.end('');

      return;
    }

    var requestOptions = getRequestOption(proxyInfo);

    log.debug('request remote server proxy info', JSON.stringify(proxyInfo));
    log.debug('request remote server request option', JSON.stringify(requestOptions));
    log.debug('request original info', JSON.stringify(request.originReq));

    var proxy = (isHTTPS ? https : http).request(requestOptions, function (res) {
      log.debug('request remote result', JSON.stringify(res.headers));

      var contentType = res.headers['content-type'];
      var encoding = res.headers['content-encoding'];
      var needUnZip = encoding === 'gzip' || encoding === 'deflate';
      var isTextFile = /(text|xml|html|plain|json|javascript|css)/.test(contentType);

      var stream = null;
      var originData = [];

      response.headers = res.headers;
      response.statusCode = res.statusCode;
      response.statusMessage = res.statusMessage;

      response.originRes = {
        headers: JSON.parse(JSON.stringify(res.headers)),
        statusCode: res.statusCode,
        statusMessage: res.statusMessage
      };

      if (needUnZip) {
        delete res.headers['content-encoding'];
        delete res.headers['content-length'];
        res.headers['x-hiproxy-origin-content-encoding'] = encoding;
      }

      // 这里暂时不执行
      // execDirectives(rewriteRule, {
      //   response: response,
      //   rewriteRule: rewriteRule
      // }, 'response');

      /**
       * Emitted each time the server set response info (eg: headers).
       * @event ProxyServer#setResponse
       * @property {http.ServerResponse} response request object
       */
      self.emit('setResponse', response);

      // response.pipe(res)

      /*
      res.pause()

      log.warn('request was paused:'.red, _url.bold.red)

      setTimeout(function(){
          res.resume()
          log.warn('request was resumed:'.red, _url.bold.red)
      }, 5000)
      */

      if (needUnZip && isTextFile) {
        var unzipStream = encoding === 'gzip' ? zlib.createUnzip() : zlib.createInflate();

        stream = unzipStream;

        /* istanbul ignore next */
        unzipStream.on('error', function (err) {
          log.error('error ==>', err);
        });

        res.pipe(unzipStream).pipe(response);
      } else {
        stream = res;

        res.pipe(response);
      }

      stream.on('data', function (chunk) {
        originData.push(chunk);
      });

      stream.on('end', function () {
        response.originRes.body = Buffer.concat(originData);
        next();
      });
    });

    proxy.on('error', function (e) {
      /* istanbul ignore next */
      if (e.code === 'ENOTFOUND') {
        response.statusCode = 404;
      } else {
        response.statusCode = 500;
      }

      response.end(e.stack);

      log.error('proxy error:', request.url);
      log.detail(e.stack);

      // self.emit('response', request, response);

{'fraction_non_alphanumeric': 0.15585054080629301, 'fraction_numerical': 0.0019665683382497543, 'mean_word_length': 2.1314655172413794, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '3852197', 'n_tokens_mistral': 3106, 'n_tokens_neox': 3035, 'n_words': 622}