Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Support Upgrade in HTTP messages

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...
commit 760bba55186eba039ca00e532f7813d2aea450a2 1 parent af49187
@ry ry authored
Showing with 38 additions and 8 deletions.
  1. +33 −7 lib/http.js
  2. +5 −1 src/node_http_parser.cc
View
40 lib/http.js
@@ -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) {
@@ -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;
@@ -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 () {
@@ -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 () {
@@ -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) {
View
6 src/node_http_parser.cc
@@ -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;
@@ -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);
@@ -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);
@@ -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;
Please sign in to comment.
Something went wrong with that request. Please try again.