| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 | var assert = require('assert');var util = require('util');var Buffer = require('buffer').Buffer;// Node.js versionvar mode = /^v0\.8\./.test(process.version) ? 'rusty' :           /^v0\.(9|10)\./.test(process.version) ? 'old' :           /^v0\.12\./.test(process.version) ? 'normal' :           'modern';var HTTPParser;var methods;var reverseMethods;var kOnHeaders;var kOnHeadersComplete;var kOnMessageComplete;var kOnBody;if (mode === 'normal' || mode === 'modern') {  HTTPParser = process.binding('http_parser').HTTPParser;  methods = HTTPParser.methods;  // v6  if (!methods)    methods = process.binding('http_parser').methods;  reverseMethods = {};  methods.forEach(function(method, index) {    reverseMethods[method] = index;  });  kOnHeaders = HTTPParser.kOnHeaders | 0;  kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;  kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;  kOnBody = HTTPParser.kOnBody | 0;} else {  kOnHeaders = 'onHeaders';  kOnHeadersComplete = 'onHeadersComplete';  kOnMessageComplete = 'onMessageComplete';  kOnBody = 'onBody';}function Deceiver(socket, options) {  this.socket = socket;  this.options = options || {};  this.isClient = this.options.isClient;}module.exports = Deceiver;Deceiver.create = function create(stream, options) {  return new Deceiver(stream, options);};Deceiver.prototype._toHeaderList = function _toHeaderList(object) {  var out = [];  var keys = Object.keys(object);  for (var i = 0; i < keys.length; i++)    out.push(keys[i], object[keys[i]]);  return out;};Deceiver.prototype._isUpgrade = function _isUpgrade(request) {  return request.method === 'CONNECT' ||         request.headers.upgrade ||         request.headers.connection &&            /(^|\W)upgrade(\W|$)/i.test(request.headers.connection);};// TODO(indutny): support CONNECTif (mode === 'modern') {  /*  function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,                                   url, statusCode, statusMessage, upgrade,                                   shouldKeepAlive) {   */  Deceiver.prototype.emitRequest = function emitRequest(request) {    var parser = this.socket.parser;    assert(parser, 'No parser present');    parser.execute = null;    var self = this;    var method = reverseMethods[request.method];    parser.execute = function execute() {      self._skipExecute(this);      this[kOnHeadersComplete](1,                               1,                               self._toHeaderList(request.headers),                               method,                               request.path,                               0,                               '',                               self._isUpgrade(request),                               true);      return 0;    };    this._emitEmpty();  };  Deceiver.prototype.emitResponse = function emitResponse(response) {    var parser = this.socket.parser;    assert(parser, 'No parser present');    parser.execute = null;    var self = this;    parser.execute = function execute() {      self._skipExecute(this);      this[kOnHeadersComplete](1,                               1,                               self._toHeaderList(response.headers),                               response.path,                               response.code,                               response.status,                               response.reason || '',                               self._isUpgrade(response),                               true);      return 0;    };    this._emitEmpty();  };} else {  /*    `function parserOnHeadersComplete(info) {`    info = { .versionMajor, .versionMinor, .url, .headers, .method,             .statusCode, .statusMessage, .upgrade, .shouldKeepAlive }   */  Deceiver.prototype.emitRequest = function emitRequest(request) {    var parser = this.socket.parser;    assert(parser, 'No parser present');    var method = request.method;    if (reverseMethods)      method = reverseMethods[method];    var info = {      versionMajor: 1,      versionMinor: 1,      url: request.path,      headers: this._toHeaderList(request.headers),      method: method,      statusCode: 0,      statusMessage: '',      upgrade: this._isUpgrade(request),      shouldKeepAlive: true    };    var self = this;    parser.execute = function execute() {      self._skipExecute(this);      this[kOnHeadersComplete](info);      return 0;    };    this._emitEmpty();  };  Deceiver.prototype.emitResponse = function emitResponse(response) {    var parser = this.socket.parser;    assert(parser, 'No parser present');    var info = {      versionMajor: 1,      versionMinor: 1,      url: response.path,      headers: this._toHeaderList(response.headers),      method: false,      statusCode: response.status,      statusMessage: response.reason || '',      upgrade: this._isUpgrade(response),      shouldKeepAlive: true    };    var self = this;    parser.execute = function execute() {      self._skipExecute(this);      this[kOnHeadersComplete](info);      return 0;    };    this._emitEmpty();  };}Deceiver.prototype._skipExecute = function _skipExecute(parser) {  var self = this;  var oldExecute = parser.constructor.prototype.execute;  var oldFinish = parser.constructor.prototype.finish;  parser.execute = null;  parser.finish = null;  parser.execute = function execute(buffer, start, len) {    // Parser reuse    if (this.socket !== self.socket) {      this.execute = oldExecute;      this.finish = oldFinish;      return this.execute(buffer, start, len);    }    if (start !== undefined)      buffer = buffer.slice(start, start + len);    self.emitBody(buffer);    return len;  };  parser.finish = function finish() {    // Parser reuse    if (this.socket !== self.socket) {      this.execute = oldExecute;      this.finish = oldFinish;      return this.finish();    }    this.execute = oldExecute;    this.finish = oldFinish;    self.emitMessageComplete();  };};Deceiver.prototype.emitBody = function emitBody(buffer) {  var parser = this.socket.parser;  assert(parser, 'No parser present');  parser[kOnBody](buffer, 0, buffer.length);};Deceiver.prototype._emitEmpty = function _emitEmpty() {  // Emit data to force out handling of UPGRADE  var empty = new Buffer(0);  if (this.socket.ondata)    this.socket.ondata(empty, 0, 0);  else    this.socket.emit('data', empty);};Deceiver.prototype.emitMessageComplete = function emitMessageComplete() {  var parser = this.socket.parser;  assert(parser, 'No parser present');  parser[kOnMessageComplete]();};
 |