|
@ -11,101 +11,91 @@ var sys = require('sys'); |
|
|
var net = require('net'); |
|
|
var net = require('net'); |
|
|
var events = require('events'); |
|
|
var events = require('events'); |
|
|
|
|
|
|
|
|
|
|
|
var FreeList = require('freelist').FreeList; |
|
|
var HTTPParser = process.binding('http_parser').HTTPParser; |
|
|
var HTTPParser = process.binding('http_parser').HTTPParser; |
|
|
|
|
|
|
|
|
var parserFreeList = []; |
|
|
var parsers = new FreeList('parsers', 1000, function () { |
|
|
|
|
|
var parser = new HTTPParser('request'); |
|
|
|
|
|
|
|
|
function newParser (type) { |
|
|
parser.onMessageBegin = function () { |
|
|
var parser; |
|
|
parser.incoming = new IncomingMessage(parser.socket); |
|
|
if (parserFreeList.length) { |
|
|
parser.field = null; |
|
|
parser = parserFreeList.shift(); |
|
|
parser.value = null; |
|
|
parser.reinitialize(type); |
|
|
}; |
|
|
} else { |
|
|
|
|
|
parser = new HTTPParser(type); |
|
|
// Only servers will get URL events.
|
|
|
|
|
|
parser.onURL = function (b, start, len) { |
|
|
|
|
|
var slice = b.toString('ascii', start, start+len); |
|
|
|
|
|
if (parser.incoming.url) { |
|
|
|
|
|
parser.incoming.url += slice; |
|
|
|
|
|
} else { |
|
|
|
|
|
// Almost always will branch here.
|
|
|
|
|
|
parser.incoming.url = slice; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
parser.onMessageBegin = function () { |
|
|
parser.onHeaderField = function (b, start, len) { |
|
|
parser.incoming = new IncomingMessage(parser.socket); |
|
|
var slice = b.toString('ascii', start, start+len).toLowerCase(); |
|
|
|
|
|
if (parser.value) { |
|
|
|
|
|
parser.incoming._addHeaderLine(parser.field, parser.value); |
|
|
parser.field = null; |
|
|
parser.field = null; |
|
|
parser.value = null; |
|
|
parser.value = null; |
|
|
}; |
|
|
} |
|
|
|
|
|
if (parser.field) { |
|
|
|
|
|
parser.field += slice; |
|
|
|
|
|
} else { |
|
|
|
|
|
parser.field = slice; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// Only servers will get URL events.
|
|
|
parser.onHeaderValue = function (b, start, len) { |
|
|
parser.onURL = function (b, start, len) { |
|
|
var slice = b.toString('ascii', start, start+len); |
|
|
var slice = b.toString('ascii', start, start+len); |
|
|
if (parser.value) { |
|
|
if (parser.incoming.url) { |
|
|
parser.value += slice; |
|
|
parser.incoming.url += slice; |
|
|
} else { |
|
|
} else { |
|
|
parser.value = slice; |
|
|
// Almost always will branch here.
|
|
|
} |
|
|
parser.incoming.url = slice; |
|
|
}; |
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
parser.onHeaderField = function (b, start, len) { |
|
|
|
|
|
var slice = b.toString('ascii', start, start+len).toLowerCase(); |
|
|
|
|
|
if (parser.value) { |
|
|
|
|
|
parser.incoming._addHeaderLine(parser.field, parser.value); |
|
|
|
|
|
parser.field = null; |
|
|
|
|
|
parser.value = null; |
|
|
|
|
|
} |
|
|
|
|
|
if (parser.field) { |
|
|
|
|
|
parser.field += slice; |
|
|
|
|
|
} else { |
|
|
|
|
|
parser.field = slice; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
parser.onHeaderValue = function (b, start, len) { |
|
|
parser.onHeadersComplete = function (info) { |
|
|
var slice = b.toString('ascii', start, start+len); |
|
|
if (parser.field && parser.value) { |
|
|
if (parser.value) { |
|
|
parser.incoming._addHeaderLine(parser.field, parser.value); |
|
|
parser.value += slice; |
|
|
} |
|
|
} else { |
|
|
|
|
|
parser.value = slice; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
parser.onHeadersComplete = function (info) { |
|
|
parser.incoming.httpVersionMajor = info.versionMajor; |
|
|
if (parser.field && parser.value) { |
|
|
parser.incoming.httpVersionMinor = info.versionMinor; |
|
|
parser.incoming._addHeaderLine(parser.field, parser.value); |
|
|
parser.incoming.httpVersion = info.versionMajor |
|
|
} |
|
|
+ '.' |
|
|
|
|
|
+ info.versionMinor ; |
|
|
|
|
|
|
|
|
parser.incoming.httpVersionMajor = info.versionMajor; |
|
|
if (info.method) { |
|
|
parser.incoming.httpVersionMinor = info.versionMinor; |
|
|
// server only
|
|
|
parser.incoming.httpVersion = info.versionMajor |
|
|
parser.incoming.method = info.method; |
|
|
+ '.' |
|
|
} else { |
|
|
+ info.versionMinor ; |
|
|
// client only
|
|
|
|
|
|
parser.incoming.statusCode = info.statusCode; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (info.method) { |
|
|
parser.onIncoming(parser.incoming, info.shouldKeepAlive); |
|
|
// server only
|
|
|
}; |
|
|
parser.incoming.method = info.method; |
|
|
|
|
|
} else { |
|
|
|
|
|
// client only
|
|
|
|
|
|
parser.incoming.statusCode = info.statusCode; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
parser.onIncoming(parser.incoming, info.shouldKeepAlive); |
|
|
parser.onBody = function (b, start, len) { |
|
|
}; |
|
|
// TODO body encoding?
|
|
|
|
|
|
var enc = parser.incoming._encoding; |
|
|
|
|
|
if (!enc) { |
|
|
|
|
|
parser.incoming.emit('data', b.slice(start, start+len)); |
|
|
|
|
|
} else { |
|
|
|
|
|
var string = b.toString(enc, start, start+len); |
|
|
|
|
|
parser.incoming.emit('data', string); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
parser.onBody = function (b, start, len) { |
|
|
parser.onMessageComplete = function () { |
|
|
// TODO body encoding?
|
|
|
parser.incoming.emit("end"); |
|
|
var enc = parser.incoming._encoding; |
|
|
}; |
|
|
if (!enc) { |
|
|
|
|
|
parser.incoming.emit('data', b.slice(start, start+len)); |
|
|
|
|
|
} else { |
|
|
|
|
|
var string = b.toString(enc, start, start+len); |
|
|
|
|
|
parser.incoming.emit('data', string); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
parser.onMessageComplete = function () { |
|
|
|
|
|
parser.incoming.emit("end"); |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
return parser; |
|
|
return parser; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
function freeParser (parser) { |
|
|
|
|
|
if (parserFreeList.length < 1000) parserFreeList.push(parser); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var CRLF = "\r\n"; |
|
|
var CRLF = "\r\n"; |
|
@ -517,7 +507,9 @@ function connectionListener (socket) { |
|
|
// we need to keep track of the order they were sent.
|
|
|
// we need to keep track of the order they were sent.
|
|
|
var responses = []; |
|
|
var responses = []; |
|
|
|
|
|
|
|
|
var parser = newParser('request'); |
|
|
var parser = parsers.alloc(); |
|
|
|
|
|
parser.reinitialize('request'); |
|
|
|
|
|
parser.socket = socket; |
|
|
|
|
|
|
|
|
socket.ondata = function (d, start, end) { |
|
|
socket.ondata = function (d, start, end) { |
|
|
parser.execute(d, start, end - start); |
|
|
parser.execute(d, start, end - start); |
|
@ -526,7 +518,7 @@ function connectionListener (socket) { |
|
|
socket.onend = function () { |
|
|
socket.onend = function () { |
|
|
parser.finish(); |
|
|
parser.finish(); |
|
|
// unref the parser for easy gc
|
|
|
// unref the parser for easy gc
|
|
|
freeParser(parser); |
|
|
parsers.free(parser); |
|
|
|
|
|
|
|
|
if (responses.length == 0) { |
|
|
if (responses.length == 0) { |
|
|
socket.end(); |
|
|
socket.end(); |
|
@ -535,7 +527,6 @@ function connectionListener (socket) { |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
parser.socket = socket; |
|
|
|
|
|
// The following callback is issued after the headers have been read on a
|
|
|
// The following callback is issued after the headers have been read on a
|
|
|
// new message. In this callback we setup the response object and pass it
|
|
|
// new message. In this callback we setup the response object and pass it
|
|
|
// to the user.
|
|
|
// to the user.
|
|
@ -563,7 +554,8 @@ function Client ( ) { |
|
|
var requests = []; |
|
|
var requests = []; |
|
|
var currentRequest; |
|
|
var currentRequest; |
|
|
|
|
|
|
|
|
var parser = newParser('response'); |
|
|
var parser = parsers.alloc(); |
|
|
|
|
|
parser.reinitialize('response'); |
|
|
parser.socket = this; |
|
|
parser.socket = this; |
|
|
|
|
|
|
|
|
self._reconnect = function () { |
|
|
self._reconnect = function () { |
|
@ -617,7 +609,7 @@ function Client ( ) { |
|
|
if (requests.length > 0) { |
|
|
if (requests.length > 0) { |
|
|
self._reconnect(); |
|
|
self._reconnect(); |
|
|
} else { |
|
|
} else { |
|
|
freeParser(parser); |
|
|
parsers.free(parser); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|