Compare commits

...

19 Commits
0.2 ... 0.3

Author SHA1 Message Date
Guillermo Rauch
a557bd6acb Updated client to 0.2.0 2010-04-30 08:55:09 -03:00
Guillermo Rauch
ae9e550c26 More support for disconnections 2010-04-30 08:48:17 -03:00
Guillermo Rauch
b19bac2d33 Updated Readme 2010-04-30 08:36:15 -03:00
Guillermo Rauch
a977ecd65b Fixes for htmlfile, multipart, polling
Removed patches
Removed server events
2010-04-30 08:35:34 -03:00
Guillermo Rauch
c4cf1b28f2 Updated JSON decoding 2010-04-30 08:12:08 -03:00
Guillermo Rauch
f5796c630c OCD-related work 2010-04-30 08:10:25 -03:00
Guillermo Rauch
6ce8c52c4d Updated README
Updated copyright
Updated project locations
2010-04-30 08:09:23 -03:00
Guillermo Rauch
408b2c73f8 Fixed encoding issues for WebSocket transport 2010-04-30 08:07:57 -03:00
Guillermo Rauch
16b5de7b4f All instances of 'close' now 'end' 2010-04-30 07:04:15 -03:00
Guillermo Rauch
b65e6fa611 'tcp' is now 'net' 2010-04-30 07:01:08 -03:00
Tobias Schneider
ddfc39826f Repository for submodule RosePad/Socket.IO doesn't exist anymore, use LearnBoost/Socket.IO instead. 2010-04-27 20:13:47 +02:00
Guillermo Rauch
1745e89936 Client update 2010-04-03 18:50:50 -07:00
Guillermo Rauch
10e6b66a97 Updating client 2010-04-03 18:31:34 -07:00
Guillermo Rauch
bf9ba8c08b Fixed encoding for WebSocket (set to utf-8 per spec)
Fixed handling of chunks sent by UA
2010-04-03 18:16:19 -07:00
Guillermo Rauch
4e58204b83 Updated client 2010-04-01 19:46:02 -07:00
Guillermo Rauch
4308ba8f14 Test client updated 2010-04-01 17:45:47 -07:00
Guillermo Rauch
0e5fb040a9 JSON try/catch (fixes #3) 2010-04-01 17:45:11 -07:00
Guillermo Rauch
e62370161d Clarified what versions of Node it's been tested on 2010-03-24 17:31:57 -07:00
Dan Loewenherz
5c5b7ee0ba update Socket.IO URL to be universally accessible 2010-03-24 17:15:22 -07:00
15 changed files with 89 additions and 315 deletions

2
.gitmodules vendored
View File

@@ -3,4 +3,4 @@
url = git://github.com/visionmedia/js-oo.git
[submodule "test/client"]
path = test/client
url = git@github.com:RosePad/Socket.IO.git
url = http://github.com/LearnBoost/Socket.IO.git

View File

@@ -4,7 +4,6 @@ Socket.IO Server: Sockets for the rest of us
The `Socket.IO` server provides seamless supports for a variety of transports intended for realtime communication
- WebSocket (with Flash policy support)
- Server-Sent Events
- XHR Polling
- XHR Multipart Streaming
- Forever Iframe
@@ -12,8 +11,8 @@ The `Socket.IO` server provides seamless supports for a variety of transports in
Requirements
------------
- Node v0.1.32+
- [Socket.IO client](http://github.com/RosePad/Socket.IO) to connect from the browser
- Node v0.1.93+
- [Socket.IO client](http://github.com/LearnBoost/Socket.IO) to connect from the browser
How to use
----------
@@ -35,16 +34,7 @@ By default, the server will intercept requests that contain `socket.io` in the p
// socket.io, I choose you
io.listen(server);
Due to a lack of flexibility in the current Node HTTP server implementation, you'll have to patch Node before using `socket.io`.
In the node directory run:
patch -p1 < {../directory/to/socket.io-node}/patch/{node version}.patch
./configure
make
make test
sudo make install
On the client side, you should use the [Socket.IO client](https://github.com/RosePad/Socket.IO) to connect.
On the client side, you should use the [Socket.IO client](https://github.com/LearnBoost/Socket.IO) to connect.
## Checking out
@@ -191,15 +181,13 @@ Despite this extra layer, your messages are delivered unaltered to the different
## Credits
Guillermo Rauch [guillermo@rosepad.com]
Special thanks to [Jonas Pfenniger](http://github.com/zimbatm) for his workaround patch to keep the HTTPConnection open after the request is successful.
Guillermo Rauch &lt;guillermo@learnboost.com&gt;
## License
(The MIT License)
Copyright (c) 2009 RosePad &lt;dev@rosepad.com&gt;
Copyright (c) 2010 LearnBoost &lt;dev@learnboost.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -22,18 +22,22 @@ this.Client = Class({
},
_onMessage: function(data){
var messages = JSON.parse(data);
try {
var messages = JSON.parse(data);
} catch(e){
return this.listener.options.log('Bad message received from client ' + this.sessionId);
}
for (var i = 0, l = messages.length; i < l; i++){
this.listener._onClientMessage(messages[i], this);
}
},
_onConnect: function(req, res){
var self = this;
var self = this;
this.request = req;
this.response = res;
this.connection = this.request.connection;
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
this.connection = this.request.connection;
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
},
_payload: function(){

View File

@@ -11,7 +11,7 @@ Listener = this.Listener = Class({
options: {
origins: '*:*',
resource: 'socket.io',
transports: ['websocket', 'server-events', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling'],
transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling'],
timeout: 8000,
log: function(message){
sys.log(message);
@@ -67,7 +67,7 @@ Listener = this.Listener = Class({
if (cn){
cn._onConnect(req, res);
} else {
req.connection.close();
req.connection.end();
sys.log('Couldnt find client with session id "' + parts[2] + '"');
}
} else {
@@ -107,7 +107,7 @@ Listener = this.Listener = Class({
// new connections (no session id)
_onConnection: function(transport, req, res){
if (this.options.transports.indexOf(transport) === -1){
req.connection.close();
req.connection.end();
return sys.log('Illegal transport "'+ transport +'"');
}
sys.log('Initializing client with transport "'+ transport +'"');

View File

@@ -1,5 +1,5 @@
var websocket = require('./websocket').websocket,
tcp = require('tcp'),
net = require('net'),
listeners = [];
this.flashsocket = websocket.extend({});
@@ -8,7 +8,7 @@ this.flashsocket.init = function(listener){
listeners.push(listener);
};
tcp.createServer(function(socket){
net.createServer(function(socket){
socket.write('<?xml version="1.0"?>\n');
socket.write('<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">\n');
socket.write('<cross-domain-policy>\n');
@@ -21,5 +21,5 @@ tcp.createServer(function(socket){
});
socket.write('</cross-domain-policy>\n');
socket.close();
socket.end();
}).listen(843);

View File

@@ -4,35 +4,30 @@ var Client = require('../client').Client,
this['htmlfile'] = Client.extend({
_onConnect: function(req, res){
var self = this, body = '';
switch (req.method){
case 'GET':
var self = this;
this.__super__(req, res);
this.request.addListener('end', function(){
if (!('hijack' in self.connection)){
throw new Error('You have to patch Node! Please refer to the README');
}
self.connection.addListener('end', function(){ self._onClose(); });
self.connection.hijack();
self.connection.setTimeout(0);
});
this.__super__(req, res);
this.request.connection.addListener('end', function(){ self._onClose(); });
this.response.useChunkedEncodingByDefault = false;
this.response.shouldKeepAlive = true;
this.response.writeHead(200, { 'Content-type': 'text/html' });
this.response.flush();
this._payload();
break;
case 'POST':
req.addListener('data', function(message){
body += message;
});
req.addListener('end', function(){
try {
var msg = qs.parse(message);
var msg = qs.parse(body);
self._onMessage(msg.data);
} catch(e){}
res.writeHead(200);
res.write('ok');
res.close();
res.end();
});
break;
}

View File

@@ -1,46 +0,0 @@
var Client = require('../client').Client,
qs = require('querystring');
this['server-events'] = Client.extend({
_onConnect: function(req, res){
switch (req.method){
case 'GET':
var self = this;
this.__super__(req, res);
this.request.addListener('end', function(){
if (!('hijack' in self.connection)){
throw new Error('You have to patch Node! Please refer to the README');
}
self.connection.addListener('end', function(){ self._onClose(); });
self.connection.hijack();
self.connection.setTimeout(0);
});
this.response.writeHead(200, { 'Content-type': 'application/x-dom-event-stream' });
this.response.flush();
this._payload();
break;
case 'POST':
req.addListener('data', function(message){
try {
var msg = qs.parse(message);
self._onMessage(msg.data);
} catch(e){}
res.writeHead(200);
res.write('ok');
res.close();
});
break;
}
},
_write: function(message){
this.response.write("Event: socket.io");
this.response.write("data: " + message);
}
});

View File

@@ -1,51 +1,51 @@
var Client = require('../client').Client,
url = require('url'),
sys = require('sys');
url = require('url');
this.websocket = Client.extend({
_onConnect: function(req, res){
_onConnect: function(req, res){
var self = this;
this.__super__(req, res);
this.__super__(req, res);
this.data = '';
if (this.request.headers['connection'] !== 'Upgrade'
|| this.request.headers['upgrade'] !== 'WebSocket'
|| !this._verifyOrigin(this.request.headers['origin'])){
if (!this.request.upgrade || this.request.headers['upgrade'] !== 'WebSocket' || !this._verifyOrigin(this.request.headers['origin'])){
this.listener.options.log('WebSocket connection invalid');
this.connection.close();
this.connection.end();
return;
}
this.request.addListener('end', function(){
if (!('hijack' in self.connection)){
throw new Error('You have to patch Node! Please refer to the README');
}
self.connection.hijack();
self.connection.setTimeout(0);
self.connection.setNoDelay(true);
self.connection.addListener('end', function(){ self._onClose(); });
self.connection.addListener('data', function(data){
if (data[0] !== '\u0000' && data[data.length - 1] !== '\ufffd'){
self.connection.close();
} else {
self._onMessage(data.substr(1, data.length - 2));
}
});
});
this.response.use_chunked_encoding_by_default = false;
this.response.writeHeader(101, 'Web Socket Protocol Handshake', {
'Upgrade': 'WebSocket',
'Connection': 'Upgrade',
'WebSocket-Origin': this.request.headers.origin,
'WebSocket-Location': 'ws://' + this.request.headers.host + this.request.url
});
this.response.flush();
this.connection.setTimeout(0);
this.connection.setEncoding('utf8');
this.connection.setNoDelay(true);
this.connection.write([
'HTTP/1.1 101 Web Socket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
'WebSocket-Origin: ' + this.request.headers.origin,
'WebSocket-Location: ws://' + this.request.headers.host + this.request.url,
'', ''
].join('\r\n'));
this.connection.addListener('end', function(){ self._onClose(); });
this.connection.addListener('data', function(data){ self._handle(data); });
this._payload();
},
_handle: function(data){
this.data += data;
chunks = this.data.split('\ufffd');
chunk_count = chunks.length - 1;
for (var i = 0; i < chunk_count; i++) {
chunk = chunks[i];
if (chunk[0] != '\u0000') {
this.listener.options.log('Data incorrectly framed by UA. Dropping connection');
this.connection.destroy();
return false;
}
this._onMessage(chunk.slice(1));
}
this.data = chunks[chunks.length - 1];
},
_verifyOrigin: function(origin){
var parts = url.parse(origin);
return this.listener.options.origins.indexOf('*:*') !== -1
@@ -55,7 +55,9 @@ this.websocket = Client.extend({
},
_write: function(message){
this.connection.write('\u0000' + message + '\uffff');
this.connection.write('\u0000', 'binary');
this.connection.write(message, 'utf8');
this.connection.write('\uffff', 'binary');
}
});

View File

@@ -4,41 +4,35 @@ var Client = require('../client').Client,
this['xhr-multipart'] = Client.extend({
_onConnect: function(req, res){
var self = this;
var self = this, body = '';
switch (req.method){
case 'GET':
var self = this;
this.__super__(req, res);
this.request.addListener('end', function(){
if (!('hijack' in self.connection)){
throw new Error('You have to patch Node! Please refer to the README');
}
self.connection.addListener('end', function(){ self._onClose(); });
self.connection.hijack();
self.connection.setTimeout(0);
});
this.response.use_chunked_encoding_by_default = false;
this.request.connection.addListener('end', function(){ self._onClose(); });
this.response.useChunkedEncodingByDefault = false;
this.response.shouldKeepAlive = true;
this.response.writeHead(200, {
'Content-Type': 'multipart/x-mixed-replace;boundary=socketio',
'Connection': 'keep-alive'
});
this.response.write("--socketio\n");
this.response.flush();
this._payload();
break;
case 'POST':
req.addListener('data', function(message){
body += message;
});
req.addListener('end', function(){
try {
var msg = qs.parse(message);
var msg = qs.parse(body);
self._onMessage(msg.data);
} catch(e){}
res.writeHead(200);
res.write('ok');
res.close();
res.end();
});
break;
}

View File

@@ -9,7 +9,7 @@ this['xhr-polling'] = Client.extend({
},
_onConnect: function(req, res){
var self = this;
var self = this, body = '';
switch (req.method){
case 'GET':
this.__super__(req, res);
@@ -21,13 +21,16 @@ this['xhr-polling'] = Client.extend({
case 'POST':
req.addListener('data', function(message){
body += message;
});
req.addListener('end', function(){
try {
var msg = qs.parse(message);
var msg = qs.parse(body);
self._onMessage(msg.data);
} catch(e){}
res.writeHead(200);
res.write('ok');
res.close();
res.end();
});
break;
}
@@ -37,7 +40,7 @@ this['xhr-polling'] = Client.extend({
if (this._closeTimeout) clearTimeout(this._closeTimeout);
this.response.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': message.length});
this.response.write(message);
this.response.close();
this.response.end();
this._onClose();
}

View File

@@ -1,83 +0,0 @@
diff -rup node-v0.1.32-orig/src/node_http.cc node-v0.1.32/src/node_http.cc
--- node-v0.1.32-orig/src/node_http.cc 2010-03-13 13:14:00.000000000 -0800
+++ node-v0.1.32/src/node_http.cc 2010-03-13 13:23:48.000000000 -0800
@@ -57,6 +57,7 @@ HTTPConnection::Initialize (Handle<Objec
client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
client_constructor_template->SetClassName(String::NewSymbol("Client"));
NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "resetParser", ResetParser);
+ NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "hijack", Hijack);
target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction());
t = FunctionTemplate::New(NewServer);
@@ -64,6 +65,7 @@ HTTPConnection::Initialize (Handle<Objec
server_constructor_template->Inherit(Connection::constructor_template);
server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "resetParser", ResetParser);
+ NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "hijack", Hijack);
server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection"));
end_symbol = NODE_PSYMBOL("end");
@@ -101,6 +103,14 @@ Handle<Value> HTTPConnection::ResetParse
}
+Handle<Value> HTTPConnection::Hijack(const Arguments& args) {
+ HandleScope scope;
+ HTTPConnection *connection = ObjectWrap::Unwrap<HTTPConnection>(args.Holder());
+ connection->Hijack();
+ return Undefined();
+}
+
+
void
HTTPConnection::OnReceive (const void *buf, size_t len)
{
@@ -109,6 +119,11 @@ HTTPConnection::OnReceive (const void *b
assert(refs_);
size_t nparsed;
+ if (hijacked) {
+ Connection::OnReceive(buf, len);
+ return;
+ }
+
nparsed = http_parser_execute(&parser_, static_cast<const char*>(buf), len);
if (nparsed != len) {
diff -rup node-v0.1.32-orig/src/node_http.h node-v0.1.32/src/node_http.h
--- node-v0.1.32-orig/src/node_http.h 2010-03-13 13:14:00.000000000 -0800
+++ node-v0.1.32/src/node_http.h 2010-03-13 13:25:05.000000000 -0800
@@ -12,17 +12,21 @@ public:
static void Initialize (v8::Handle<v8::Object> target);
static v8::Persistent<v8::FunctionTemplate> client_constructor_template;
- static v8::Persistent<v8::FunctionTemplate> server_constructor_template;
+ static v8::Persistent<v8::FunctionTemplate> server_constructor_template;
protected:
static v8::Handle<v8::Value> NewClient (const v8::Arguments& args);
static v8::Handle<v8::Value> NewServer (const v8::Arguments& args);
static v8::Handle<v8::Value> ResetParser(const v8::Arguments& args);
+ static v8::Handle<v8::Value> Hijack(const v8::Arguments& args);
+
+ bool hijacked;
HTTPConnection (enum http_parser_type t)
: Connection()
{
type_ = t;
+ hijacked = false;
ResetParser();
}
@@ -41,6 +45,10 @@ protected:
parser_.data = this;
}
+ void Hijack() {
+ hijacked = true;
+ }
+
void OnReceive (const void *buf, size_t len);
void OnEOF ();

View File

@@ -1,83 +0,0 @@
diff -rup node-v0.1.32-orig/src/node_http.cc node-v0.1.32/src/node_http.cc
--- node-v0.1.32-orig/src/node_http.cc 2010-03-13 13:14:00.000000000 -0800
+++ node-v0.1.32/src/node_http.cc 2010-03-13 13:23:48.000000000 -0800
@@ -57,6 +57,7 @@ HTTPConnection::Initialize (Handle<Objec
client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
client_constructor_template->SetClassName(String::NewSymbol("Client"));
NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "resetParser", ResetParser);
+ NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "hijack", Hijack);
target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction());
t = FunctionTemplate::New(NewServer);
@@ -64,6 +65,7 @@ HTTPConnection::Initialize (Handle<Objec
server_constructor_template->Inherit(Connection::constructor_template);
server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "resetParser", ResetParser);
+ NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "hijack", Hijack);
server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection"));
end_symbol = NODE_PSYMBOL("end");
@@ -101,6 +103,14 @@ Handle<Value> HTTPConnection::ResetParse
}
+Handle<Value> HTTPConnection::Hijack(const Arguments& args) {
+ HandleScope scope;
+ HTTPConnection *connection = ObjectWrap::Unwrap<HTTPConnection>(args.Holder());
+ connection->Hijack();
+ return Undefined();
+}
+
+
void
HTTPConnection::OnReceive (const void *buf, size_t len)
{
@@ -109,6 +119,11 @@ HTTPConnection::OnReceive (const void *b
assert(refs_);
size_t nparsed;
+ if (hijacked) {
+ Connection::OnReceive(buf, len);
+ return;
+ }
+
nparsed = http_parser_execute(&parser_, static_cast<const char*>(buf), len);
if (nparsed != len) {
diff -rup node-v0.1.32-orig/src/node_http.h node-v0.1.32/src/node_http.h
--- node-v0.1.32-orig/src/node_http.h 2010-03-13 13:14:00.000000000 -0800
+++ node-v0.1.32/src/node_http.h 2010-03-13 13:25:05.000000000 -0800
@@ -12,17 +12,21 @@ public:
static void Initialize (v8::Handle<v8::Object> target);
static v8::Persistent<v8::FunctionTemplate> client_constructor_template;
- static v8::Persistent<v8::FunctionTemplate> server_constructor_template;
+ static v8::Persistent<v8::FunctionTemplate> server_constructor_template;
protected:
static v8::Handle<v8::Value> NewClient (const v8::Arguments& args);
static v8::Handle<v8::Value> NewServer (const v8::Arguments& args);
static v8::Handle<v8::Value> ResetParser(const v8::Arguments& args);
+ static v8::Handle<v8::Value> Hijack(const v8::Arguments& args);
+
+ bool hijacked;
HTTPConnection (enum http_parser_type t)
: Connection()
{
type_ = t;
+ hijacked = false;
ResetParser();
}
@@ -41,6 +45,10 @@ protected:
parser_.data = this;
}
+ void Hijack() {
+ hijacked = true;
+ }
+
void OnReceive (const void *buf, size_t len);
void OnEOF ();

View File

@@ -28,7 +28,7 @@
var socket = new io.Socket('localhost', {rememberTransport: false, port: 8080});
socket.connect();
socket.addEvent('message', function(data){
var obj = io.util.JSON.decode(data);
var obj = JSON.parse(data);
if ('buffer' in obj){
document.getElementById('form').style.display='block';

View File

@@ -7,7 +7,7 @@ var http = require('http'),
send404 = function(res){
res.writeHead(404);
res.write('404');
res.close();
res.end();
},
server = http.createServer(function(req, res){
@@ -17,7 +17,7 @@ server = http.createServer(function(req, res){
case '/':
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<h1>Welcome. Try the <a href="/chat.html">chat</a> example.</h1>');
res.close();
res.end();
break;
default:
@@ -26,7 +26,7 @@ server = http.createServer(function(req, res){
var swf = path.substr(-4) == '.swf';
res.writeHead(200, {'Content-Type': swf ? 'application/x-shockwave-flash' : ('text/' + (path.substr(-3) == '.js' ? 'javascript' : 'html'))});
res.write(fs.readFileSync(__dirname + path, swf ? 'binary' : 'utf8'), swf ? 'binary' : 'utf8');
res.close();
res.end();
} catch(e){
send404(res);
}