123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- var assert = require('assert');
- var util = require('util');
- var Buffer = require('buffer').Buffer;
- // Node.js version
- var 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 CONNECT
- if (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]();
- };
|