Using internal HTTPParser for fun and tests
If you wanna use Node's http(s) library but don't want run/simulate http server - read on :)
So, for using native http parser, which in a nutshell are C library binded to Node with a bunch of internal helpers and local functions we need just a several lines of code.
/**
* using internal .binding method
*/
var HTTPParser = process.binding('http_parser').HTTPParser;
/**
* specify that wee wanna parse request
* HTTPParser.REQUEST == 1
* HTTPParser.RESPONSE == 0
*/
var parser = new HTTPParser(HTTPParser.REQUEST);
//closure, just for convenience
var log = console.log;
/**
* creates new Buffer and pass it to parser
* @param {Buffer} buffer
*/
function parse(buffer) {
var _data = new Buffer(buffer);
//this method is described below
parser.execute(_data, 0, _data.length);
}
/**
* set event emitters
*/
parser.onHeadersComplete = function(headers) {
log(".onHeadersComplete, arguments: \n%s\n", JSON.stringify(arguments));
}
parser.onMessageComplete = function() {
log(".onMessageComplete invoked");
}
parser.onBody = function(body, start, len) {
log(".onBody, arguments: \n%s\n", JSON.stringify(arguments));
log(body.toString());
}
/**
* Make tests with proper requests
*/
//single string
parse("GET / HTTP/1.1\r\nhost:google.com\r\ncontent-length: 0\r\n\r\n");
//multiline
parse("PUT /api/v1/spot HTTP/1.1\r\n");
parse("content-type: application/json\r\n");
parse("host: example.com\r\ncontent-length:31\r\n\r\n");
parse("{\"stock\": \"AAPL\", \"price\": 643}");
Results:
single string
.onHeadersComplete, arguments:
{"0":{"headers":["host","google.com","content-length","0"],"url":"/","method":"GET","versionMajor":1,"versionMinor":1,"shouldKeepAlive":true,"upgrade":false}}
.onMessageComplete invoked
and multiline one
.onHeadersComplete, arguments:
{"0":{"headers":["content-type","application/json","host","example.com","content-length","31"],"url":"/api/v1/spot","method":"PUT","versionMajor":1,"versionMinor":1,"shouldKeepAlive":true,"upgrade":false}}
.onBody, arguments:
{"0":[123,34,115,116,111,99,107,34,58,32,34,65,65,80,76,34,44,32,34,112,114,105,99,101,34,58,32,54,52,51,125],"1":0,"2":31}
{"stock": "AAPL", "price": 643}
.onMessageComplete invoked
Cool, we have headers, request line and body buffer.
Btw, .execute method needs data, start and end positions
let's take a peek to http.js:2167
function socketOnData(d, start, end) {
var socket = this;
var req = this._httpMessage;
var parser = this.parser;
var ret = parser.execute(d, start, end - start);
if (ret instanceof Error) {
debug('parse error');
freeParser(parser, req);
socket.destroy();
req.emit('error', ret);
req._hadError = true;
} else if (parser.incoming && parser.incoming.upgrade) {
// Upgrade or CONNECT
var bytesParsed = ret;
var res = parser.incoming;
req.res = res;
...
Also, here is npm module with this stuff.