Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
Support Upgrade in HTTP messages
Browse files Browse the repository at this point in the history
This allows for web servers to be "hijacked" and used as Web Socket servers
(or other). You simply listen for requests as normal, but check if

  req.upgrade === true

If so, this will be the last request of the connection. It's your job now to
hijack req.connection and start reading from it. req.upgradeHead is a buffer
containing the first part of the new protocol communication (in the case it
arrived on the same packet).

This needs tests and documentation. API subject to change.
  • Loading branch information
ry committed Apr 14, 2010
1 parent af49187 commit 760bba5
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 8 deletions.
40 changes: 33 additions & 7 deletions lib/http.js
Expand Up @@ -76,7 +76,13 @@ var parsers = new FreeList('parsers', 1000, function () {
parser.incoming.statusCode = info.statusCode;
}

parser.onIncoming(parser.incoming, info.shouldKeepAlive);
parser.incoming.upgrade = info.upgrade;

if (!info.upgrade) {
// For upgraded connections, we'll emit this after parser.execute
// so that we can capture the first part of the new protocol
parser.onIncoming(parser.incoming, info.shouldKeepAlive);
}
};

parser.onBody = function (b, start, len) {
Expand All @@ -91,7 +97,10 @@ var parsers = new FreeList('parsers', 1000, function () {
};

parser.onMessageComplete = function () {
parser.incoming.emit("end");
if (!parser.incoming.upgrade) {
// For upgraded connections, also emit this after parser.execute
parser.incoming.emit("end");
}
};

return parser;
Expand Down Expand Up @@ -512,7 +521,16 @@ function connectionListener (socket) {
parser.socket = socket;

socket.ondata = function (d, start, end) {
parser.execute(d, start, end - start);
var bytesParsed = parser.execute(d, start, end - start);
if (parser.incoming && parser.incoming.upgrade) {
var upgradeHead = d.slice(start + bytesParsed, end - start);
parser.incoming.upgradeHead = upgradeHead;
socket.ondata = null;
socket.onend = null;

self.emit('request', parser.incoming, null);
parser.incoming.emit('end');
}
};

socket.onend = function () {
Expand Down Expand Up @@ -579,8 +597,16 @@ function Client ( ) {
requests.push(req);
};

this.ondata = function (d, start, end) {
parser.execute(d, start, end - start);
self.ondata = function (d, start, end) {
var bytesParsed = parser.execute(d, start, end - start);
if (parser.incoming && parser.incoming.upgrade) {
var upgradeHead = d.slice(start + bytesParsed, end - start);
parser.incoming.upgradeHead = upgradeHead;
currentRequest.emit("response", parser.incoming);
parser.incoming.emit('end');
self.ondata = null;
self.onend = null
}
};

self.addListener("connect", function () {
Expand All @@ -590,12 +616,12 @@ function Client ( ) {
currentRequest.flush();
});

self.addListener("end", function () {
self.onend = function () {
parser.finish();

debug("self got end closing. readyState = " + self.readyState);
self.end();
});
};

self.addListener("close", function (e) {
if (e) {
Expand Down
6 changes: 5 additions & 1 deletion src/node_http_parser.cc
Expand Up @@ -61,6 +61,7 @@ static Persistent<String> http_version_sym;
static Persistent<String> version_major_sym;
static Persistent<String> version_minor_sym;
static Persistent<String> should_keep_alive_sym;
static Persistent<String> upgrade_sym;

static struct http_parser_settings settings;

Expand Down Expand Up @@ -165,6 +166,8 @@ class Parser : public ObjectWrap {
message_info->Set(should_keep_alive_sym,
http_should_keep_alive(p) ? True() : False());

message_info->Set(upgrade_sym, p->upgrade ? True() : False());

Local<Value> argv[1] = { message_info };

Local<Value> ret = cb->Call(parser->handle_, 1, argv);
Expand Down Expand Up @@ -243,7 +246,7 @@ class Parser : public ObjectWrap {
Local<Integer> nparsed_obj = Integer::New(nparsed);
// If there was a parse error in one of the callbacks
// TODO What if there is an error on EOF?
if (nparsed != len) {
if (!parser->parser_.upgrade && nparsed != len) {
Local<Value> e = Exception::Error(String::New("Parse Error"));
Local<Object> obj = e->ToObject();
obj->Set(String::NewSymbol("bytesParsed"), nparsed_obj);
Expand Down Expand Up @@ -345,6 +348,7 @@ void InitHttpParser(Handle<Object> target) {
version_major_sym = NODE_PSYMBOL("versionMajor");
version_minor_sym = NODE_PSYMBOL("versionMinor");
should_keep_alive_sym = NODE_PSYMBOL("shouldKeepAlive");
upgrade_sym = NODE_PSYMBOL("upgrade");

settings.on_message_begin = Parser::on_message_begin;
settings.on_path = Parser::on_path;
Expand Down

0 comments on commit 760bba5

Please sign in to comment.