- prepare session for profiler
This commit is contained in:
Danny Coates 2010-11-28 22:40:31 -07:00
Родитель 23812b3855
Коммит 1e2b66fc70
13 изменённых файлов: 558 добавлений и 476 удалений

Просмотреть файл

@ -13,6 +13,8 @@ WebInspector.loaded = function() {
// enable LiveEdit
Preferences.canEditScriptSource = true;
// enable heap profiler
Preferences.heapProfilerPresent = true;
// patch new watch expression (default crashes node)
WebInspector.WatchExpressionsSection.NewWatchExpression = "''";

Просмотреть файл

@ -1,7 +1,7 @@
var Http = require('http'),
EventEmitter = require('events').EventEmitter,
path = require('path'),
WebSocket = require('../vendor/websockets/ws/server'),
WebSocket = require('../vendor/ws'),
paperboy = require('../vendor/paperboy'),
Session = require('./session');

Просмотреть файл

@ -15,7 +15,9 @@ exports.create = function (conn, debuggerPort, config) {
//milliseconds to wait for a lookup
LOOKUP_TIMEOUT = 2500,
//node function wrapper
FUNC_WRAP = /^\(function \(exports, require, module, __filename, __dirname\) \{ ([\s\S]*)\n\}\);$/;
FUNC_WRAP = /^\(function \(exports, require, module, __filename, __dirname\) \{ ([\s\S]*)\n\}\);$/,
//store of the last profile taken
lastProfile;
function wrapperObject(type, description, hasChildren, frame, scope, ref) {
return {
@ -109,7 +111,7 @@ exports.create = function (conn, debuggerPort, config) {
}
function evaluate(expr, frame, andThen) {
var args = { expression: expr, disable_break: true, global: true };
var args = { expression: expr, disable_break: true, global: true, maxStringLength:100000 };
if (frame != null) {
args.frame = frame;
args.global = false;
@ -461,7 +463,8 @@ exports.create = function (conn, debuggerPort, config) {
},
enableProfiler: {
value: function(always) {
// TODO: evaluate if profiling is enabled
sendEvent('profilerWasEnabled');
}
},
disableProfiler: {
@ -707,8 +710,17 @@ exports.create = function (conn, debuggerPort, config) {
}
},
getProfile: {
value: function(type, uid) {
value: function(type, uid, seq) {
evaluate('process.profiler.findSnapshot(' + uid + ').stringify()', null, function(msg) {
sendResponse(seq, true, {
profile: {
title: "org.webkit.profiles.user-initiated." + lastProfile.uid,
uid: parseInt(lastProfile.uid, 10),
typeId: "HEAP",
head: JSON.parse(msg.body.value)
}
});
})
}
},
removeProfile: {
@ -723,7 +735,28 @@ exports.create = function (conn, debuggerPort, config) {
},
takeHeapSnapshot: {
value: function() {
evaluate('process.profiler.takeSnapshot()', null, function(msg){
if (msg.success) {
var refs = {};
lastProfile = {};
if (msg.refs && Array.isArray(msg.refs)) {
var obj = msg.body;
var objProps = obj.properties;
msg.refs.forEach(function(r) {
refs[r.handle] = r;
});
objProps.forEach(function(p) {
lastProfile[String(p.name)] = refToObject(refs[p.ref]).description;
});
}
sendEvent('addProfileHeader', {
header: {
title: "org.webkit.profiles.user-initiated." + lastProfile.uid,
uid: parseInt(lastProfile.uid, 10),
typeId: "HEAP"
}});
}
});
}
},

30
vendor/websockets/_events.js поставляемый
Просмотреть файл

@ -1,30 +0,0 @@
var util = require("./_util")
, events = require("events")
EventEmitter = exports.EventEmitter = function(){
events.EventEmitter.call(this);
};
util.inherits(EventEmitter, events.EventEmitter);
EventEmitter.prototype.emit = function(type) {
if (type !== "newListener"
&& (!this._events || !this._events[type])
&& this._bubbleTarget && this._bubbleTarget[type]
) {
// util.error("\033[31mEvent: "+type+", source: "+this.constructor.name+", target: "+this._bubbleTarget[type].constructor.name+"\033[39m");
this._bubbleTarget[type].emit.apply(this._bubbleTarget[type], arguments);
} else {
// util.error("\033[31mEvent: "+type+", source: "+this.constructor.name+"\033[39m");
events.EventEmitter.prototype.emit.apply(this, arguments);
}
};
EventEmitter.prototype.bubbleEvent = function(type, target){
if(!this._bubbleTarget) this._bubbleTarget = {};
this._bubbleTarget[type] = target;
};
EventEmitter.prototype.removeBubbleEvent = function(type) {
delete this._bubbleTarget[type];
};

1
vendor/websockets/_util.js поставляемый
Просмотреть файл

@ -1 +0,0 @@
module.exports = require(process.binding("natives").util ? "util" : "sys")

13
vendor/websockets/lang/mixin.js поставляемый
Просмотреть файл

@ -1,13 +0,0 @@
module.exports = function Mixin(target, source) {
if (source) {
for(var key, keys = Object.keys(source), l = keys.length; l--; ) {
key = keys[l];
if(source.hasOwnProperty(key)){
target[key] = source[key];
}
}
}
return target;
};

153
vendor/websockets/ws/manager.js поставляемый
Просмотреть файл

@ -1,153 +0,0 @@
var debug = function(){};
var util = require("../_util")
, events = require("../_events");
/*-----------------------------------------------
Connection Manager
-----------------------------------------------*/
module.exports = Manager;
function Manager(options) {
events.EventEmitter.call(this);
if(options.debug) {
var self = this;
debug = function(msg, connection) {
if(connection && connection.id) {
util.error('\033[31mManager: ' +msg+ ": <Connection "+connection.id+"> ("+self._length+")\033[39m");
} else {
util.error('\033[31mManager: ' +Array.prototype.join.call(arguments, " ")+" ("+self._length+")\033[39m");
}
};
}
this._head = null;
this._tail = null;
this._length = 0;
this._counter = 0;
};
util.inherits(Manager, events.EventEmitter);
Object.defineProperty(Manager.prototype, "length", {
get: function() {
return this._length;
}
});
Manager.prototype.createId = function(remotePort) {
return process.pid + "" + remotePort + "" + (this._counter++);
};
Manager.prototype.inspect = function() {
return "<WS:Manager "+this._length+" (total: "+this._counter+")>";
};
Manager.prototype.attach = function(connection) {
var client = {
id: connection.id,
_next: null,
connection: connection
};
if(this._length == 0) {
this._head = client;
this._tail = client;
} else {
this._tail._next = client;
this._tail = client;
}
++this._length;
this.emit("attach", connection);
debug("Attached", connection);
};
Manager.prototype.detach = function(connection) {
var previous = current = this._head
, id = connection.id;
while(current !== null) {
if(current.id === id) {
previous._next = current._next;
if(current.id === this._head.id) {
this._head = current._next;
}
if(current.id === this._tail.id) {
this._tail = previous;
}
this._length--;
this.emit("detach", connection);
debug("Detached", connection);
break;
} else {
previous = current;
current = current._next;
}
}
if(current === null) {
debug("Detach Failed", connection);
}
delete current, previous;
};
Manager.prototype.find = function(id, callback, thisArg) {
var current = this._head;
while(current !== null) {
if(current.id === id) {
callback.call(thisArg, current.connection);
break;
} else {
current = current._next;
}
}
};
Manager.prototype.forEach = function(callback, thisArg){
var current = this._head;
while(current !== null) {
callback.call(thisArg, current.connection);
current = current._next;
}
};
Manager.prototype.map = function(callback, thisArg){
var current = this._head
, result = []
, len = 0;
while(current !== null) {
result.push(callback.call(thisArg, current.connection, len, this._head));
current = current._next;
len++;
}
return result;
};
Manager.prototype.filter = function(callback, thisArg){
var current = this._head
, result = []
, len = 0;
while(current !== null) {
if( Boolean(callback.call(thisArg, current.connection, len, this._head)) ) {
result.push(current.connection);
}
current = current._next;
len++;
}
return result;
};

102
vendor/websockets/ws/server.js поставляемый
Просмотреть файл

@ -1,102 +0,0 @@
/*-----------------------------------------------
Requirements:
-----------------------------------------------*/
var http = require("http")
, path = require("path");
var util = require("../_util")
, events = require("../_events");
var Manager = require("./manager")
, Connection = require("./connection")
, Mixin = require("../lang/mixin");
/*-----------------------------------------------
Reflectors:
-----------------------------------------------*/
function reflectEvent(sEmitter, sType, tEmitter, tType) {
sEmitter.addListener(sType, function(){
tEmitter.emit.apply(tEmitter, [tType || sType].concat(Array.prototype.slice.call(arguments)));
});
};
function reflectMethod(sObject, sMeth, tObject, tMeth) {
tObject[tMeth || sMeth] = function(){
return sObject[sMeth].apply(sObject, arguments);
};
};
function clientWrite(client, data) {
if(client && client._state === 4){
client.write(data);
}
};
/*-----------------------------------------------
WebSocket Server Exports:
-----------------------------------------------*/
exports.Server = Server;
exports.createServer = function(options){
return new Server(options);
};
/*-----------------------------------------------
WebSocket Server Implementation:
-----------------------------------------------*/
function Server(o){
events.EventEmitter.call(this);
var options = Mixin({
debug: false,
server: new http.Server()
}, o);
var manager = new Manager(options)
, server = options.server;
if(options.datastore){
throw new Error("Built-in DataStore has been removed, see: http://github.com/miksago/nws-memstore");
}
server.on("upgrade", function(req, socket, upgradeHead){
if( req.method == "GET" && ( req.headers["upgrade"] && req.headers["connection"] ) &&
req.headers.upgrade.toLowerCase() == "websocket" && req.headers.connection.toLowerCase() == "upgrade"
){
new Connection(manager, options, req, socket, upgradeHead);
}
});
manager.bubbleEvent("error", this);
reflectEvent( manager, "attach", this, "connection");
reflectEvent( manager, "detach", this, "disconnect");
reflectEvent( server, "listening", this);
reflectEvent( server, "request", this);
reflectEvent( server, "stream", this);
reflectEvent( server, "close", this);
reflectEvent( server, "clientError", this);
reflectEvent( server, "error", this);
reflectMethod( server, "listen", this);
reflectMethod( server, "close", this);
this.send = function(id, data){
manager.find(id, function(client){
clientWrite(client, data);
});
};
this.broadcast = function(data){
manager.forEach(function(client){
clientWrite(client, data);
});
};
this.server = server;
this.manager = manager;
this.options = options;
};
util.inherits(Server, events.EventEmitter);

136
vendor/ws.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,136 @@
/*-----------------------------------------------
Requirements:
-----------------------------------------------*/
var sys = require("sys")
, http = require("http")
, events = require("events")
, path = require("path");
var Manager = require("./ws/manager")
, Connection = require("./ws/connection");
/*-----------------------------------------------
Mixin:
-----------------------------------------------*/
var mixin = function(target, source) {
for(var i = 0, keys = Object.keys(source), l = keys.length; i < l; ++i) {
if(source.hasOwnProperty(keys[i])){
target[keys[i]] = source[keys[i]];
}
}
return target;
};
/*-----------------------------------------------
WebSocket Server Exports:
-----------------------------------------------*/
exports.Server = Server;
exports.createServer = function(options){
return new Server(options);
};
exports._Manager = Manager;
exports._Connection = Connection;
/*-----------------------------------------------
WebSocket Server Implementation:
-----------------------------------------------*/
function Server(options){
var ws = this;
events.EventEmitter.call(this);
this.options = mixin({
debug: false, // Boolean: Show debug information.
version: "auto", // String: Value must be either: draft75, draft76, auto
origin: "*", // String, Array: A match for a valid connection origin
subprotocol: "*", // String, Array: A match for a valid connection subprotocol.
datastore: true, // Object, Function, Boolean: If === true, then it is the default mem-store.
server: new http.Server()
}, options || {});
this.manager = new Manager(this.options.debug);
this.server = this.options.server
this.debug = this.options.debug;
this.server.addListener("upgrade", function(req, socket, upgradeHead){
if( req.method == "GET" && ( "upgrade" in req.headers && "connection" in req.headers) &&
req.headers.upgrade.toLowerCase() == "websocket" && req.headers.connection.toLowerCase() == "upgrade"
){
// create a new connection, it'll handle everything else.
new Connection(ws, req, socket, upgradeHead);
} else {
// Close the socket, it wasn't a valid connection.
socket.end();
socket.destroy();
}
});
this.server.addListener("connection", function(socket){
socket.setTimeout(0);
socket.setNoDelay(true);
socket.setKeepAlive(true, 0);
});
this.server.addListener("listening", function(req, res){
ws.emit("listening");
});
this.server.addListener("close", function(errno){
ws.emit("shutdown", errno);
});
this.server.addListener("request", function(req, res){
ws.emit("request", req, res);
});
this.server.addListener("stream", function(stream){
ws.emit("stream", stream);
});
this.server.addListener("clientError", function(e){
ws.emit("clientError", e);
});
};
sys.inherits(Server, events.EventEmitter);
/*-----------------------------------------------
Public API
-----------------------------------------------*/
Server.prototype.setSecure = function (credentials) {
this.server.setSecure.call(this.server, credentials);
}
Server.prototype.listen = function(){
this.server.listen.apply(this.server, arguments);
};
Server.prototype.close = function(){
this.server.close();
};
Server.prototype.send = function(id, data){
this.manager.find(id, function(client){
if(client && client._state === 4){
client.write(data);
}
});
};
Server.prototype.broadcast = function(data){
this.manager.forEach(function(client){
if(client && client._state === 4){
client.write(data);
}
});
};
Server.prototype.use = function(module){
module.call(this, this.options);
};

Просмотреть файл

@ -1,124 +1,149 @@
/*-----------------------------------------------
Requirements:
-----------------------------------------------*/
var debug = function(){};
var util = require("../_util")
, events = require("events")
var sys = require("sys")
, Url = require("url")
, Events = require("events")
, Buffer = require("buffer").Buffer
, Crypto = require("crypto");
var _events = require("../_events")
var Mixin = require("../lang/mixin");
/*-----------------------------------------------
The Connection:
-----------------------------------------------*/
module.exports = Connection;
// Our connection instance:
function Connection(manager, options, req, socket, upgradeHead){
var _firstFrame
, connection = this;
function Connection(server, req, socket, data){
this.debug = server.debug;
_events.EventEmitter.call(this);
if (this.debug) {
debug = function (id, data) { sys.error('\033[90mWS: ' + Array.prototype.join.call(arguments, ", ") + "\033[39m"); };
} else {
debug = function (id, data) { };
}
Events.EventEmitter.call(this);
this._req = req;
this._socket = socket;
this._manager = manager;
this.id = manager.createId(socket.remotePort);
this._server = server;
this.headers = this._req.headers;
this.id = server.manager.createId(this._req.socket.remotePort);
this._options = Mixin({
version: "auto", // String: Value must be either: draft75, draft76, auto
origin: "*", // String, Array: A match for a valid connection origin
subprotocol: "*", // String, Array: A match for a valid connection subprotocol.
debug: true
}, options);
if(connection._options.debug){
debug = function () {
util.error('\033[90mWS: ' + Array.prototype.join.call(arguments, ", ") + "\033[39m");
process.stdout.flush();
};
}
var _firstFrame = false;
Object.defineProperties(this, {
version: {
get: function(){
return req.headers["sec-websocket-key1"] && req.headers["sec-websocket-key2"]
? "draft76"
: "draft75";
if(this._req.headers["sec-websocket-key1"] && this._req.headers["sec-websocket-key2"]){
return "draft76";
} else {
return "draft75";
}
}
}
});
// Set the initial connecting state.
connection.state(1);
// Setup the connection manager's state change listeners:
connection.on("stateChange", function(state, laststate){
if(state === 4) {
manager.attach(connection);
// Handle first frame breakages.
if(_firstFrame){
parser.write(_firstFrame);
delete _firstFrame;
}
} else if(state === 5) {
close(connection);
} else if(state === 6 && laststate === 5) {
manager.detach(connection);
connection.emit("close");
}
});
if(server.options.datastore){
var storage;
if(typeof server.options.datastore === "object" || typeof server.options.datastore === "function"){
storage = server.options.datastore;
} else if(server.options.datastore === true){
storage = require("./mem-store");
} else {
storage = false;
}
}
// Start to process the connection
if( !checkVersion(this)) {
this.reject("Invalid version.");
} else {
var connection = this
, parser;
// Let the debug mode know that we have a connection:
debug(this.id, this.version+" connection");
socket.setTimeout(0);
socket.setNoDelay(true);
socket.setKeepAlive(true, 0);
this.debug && debug(this.id, this.version+" connection");
// Set the initial connecting state.
this.state(1);
// Handle incoming data:
var parser = new Parser(this);
parser = new Parser(this);
parser.on("message", function(message){
debug(connection.id, "recv: " + message);
connection.emit("message", message);
});
socket.on("data", function(data){
parser.write(data);
socket.addListener("data", function(data){
if(data.length == 2 && data[0] == 0xFF && data[1] == 0x00){
connection.state(5);
} else {
parser.write(data);
}
});
// Handle the end of the stream, and set the state
// appropriately to notify the correct events.
socket.on("end", function(){
debug(connection.id, "end");
socket.addListener("end", function(){
connection.state(5);
});
socket.on('timeout', function () {
socket.addListener('timeout', function () {
debug(connection.id, "timed out");
server.emit("timeout", connection);
connection.emit("timeout");
});
socket.on("error", function(e){
debug(connection.id, "error", e);
if(e.errno != 32){
socket.addListener("error", function(e){
if(e.errno == 32){
connection.state(5);
closeClient(connection);
connection.state(6);
} else {
manager.emit("error", connection, e);
connection.emit("error", e);
connection.state(5);
}
connection.state(5);
});
// Bubble errors up to the manager.
connection.bubbleEvent("error", manager);
// Setup the connection manager's state change listeners:
this.addListener("stateChange", function(state, laststate){
//debug(connection.id, "Change state: "+laststate+" => "+state);
if(state === 4){
if(storage && storage.create){
connection.storage = storage.create();
} else if(storage){
connection.storage = storage;
}
server.manager.attach(connection.id, connection);
server.emit("connection", connection);
if(_firstFrame){
parser.write(_firstFrame);
delete _firstFrame;
}
} else if(state === 5){
connection.close();
} else if(state === 6 && laststate === 5){
if(connection.storage && connection.storage.disconnect){
connection.storage.disconnect(connection.id);
}
server.manager.detach(connection.id, function(){
server.emit("close", connection);
connection.emit("close");
});
}
});
// Let us see the messages when in debug mode.
if(this.debug){
this.addListener("message", function(msg){
debug(connection.id, "recv: " + msg);
});
}
// Carry out the handshaking.
// - Draft75: There's no upgradeHead, goto Then.
@ -129,60 +154,54 @@ function Connection(manager, options, req, socket, upgradeHead){
// but in the case it does happen, then the state is set to waiting for
// the upgradeHead.
//
// This switch is sorted in order of probably of occurence.
switch(this.version) {
case "draft76":
if(upgradeHead.length >= 8) {
if(upgradeHead.length > 8){
_firstFrame = upgradeHead.slice(8, upgradeHead.length);
}
if(this.version == "draft75"){
this.handshake();
}
handshakes.draft76(connection, upgradeHead.slice(0, 8));
} else {
connection.reject("Missing key3");
}
break;
if(this.version == "draft76"){
if(data.length >= 8){
this._upgradeHead = data.slice(0, 8);
case "draft75":
handshakes.draft75(connection);
break;
_firstFrame = data.slice(8, data.length);
default:
connection.reject("Unknown version: "+this.version);
break;
this.handshake();
} else {
this.reject("Missing key3");
}
}
}
};
util.inherits(Connection, _events.EventEmitter);
sys.inherits(Connection, Events.EventEmitter);
/*-----------------------------------------------
Various utility style functions:
-----------------------------------------------*/
var write = function(connection, data, encoding) {
if(connection._socket.writable){
var writeSocket = function(socket, data, encoding) {
if(socket.writable){
try {
connection._socket.write(data, encoding);
socket.write(data, encoding);
return true;
} catch(e){
debug(null, "Error on write: "+e.toString());
return false;
}
}
return false;
};
var close = function(connection) {
//connection._socket.flush();
connection._socket.end();
connection._socket.destroy();
debug(connection.id, "socket closed");
connection.state(6);
var closeClient = function(client){
client._req.socket.flush();
client._req.socket.end();
client._req.socket.destroy();
debug(client.id, "socket closed");
client.state(6);
};
function checkVersion(connection) {
var server_version = connection._options.version.toLowerCase();
function checkVersion(client){
var server_version = client._server.options.version.toLowerCase();
return (server_version == "auto" || server_version == connection.version);
return (server_version == "auto" || server_version == client.version);
};
@ -199,27 +218,23 @@ function pack(num) {
/*-----------------------------------------------
Formatters for the urls
-----------------------------------------------*/
// TODO: Properly handle origin headers.
function websocket_origin(connection) {
var origin = connection._options.origin || "*";
function websocket_origin(){
var origin = this._server.options.origin || "*";
if(origin == "*" || Array.isArray(origin)){
origin = connection._req.headers.origin;
origin = this._req.headers.origin;
}
return origin;
};
function websocket_location(connection){
if(connection._req.headers["host"] === undefined){
connection.reject("Missing host header");
function websocket_location(){
if(this._req.headers["host"] === undefined){
this.reject("Missing host header");
return;
}
var location = ""
, secure = connection._socket.secure
, host = connection._req.headers.host.split(":")
, secure = this._req.socket.secure
, host = this._req.headers.host.split(":")
, port = host[1] !== undefined ? host[1] : (secure ? 443 : 80);
location += secure ? "wss://" : "ws://";
@ -229,7 +244,7 @@ function websocket_location(connection){
location += ":"+port;
}
location += connection._req.url;
location += this._req.url;
return location;
};
@ -258,19 +273,17 @@ Connection.prototype.state = function(state){
}
};
Connection.prototype.inspect = function(){
return "<WS:Connection "+this.id+">";
};
Connection.prototype.write = function(data){
var socket = this._req.socket;
Connection.prototype.write = function(data) {
if(this._state === 4) {
if(this._state == 4){
debug(this.id, "write: "+data);
if(
write(this, "\x00", "binary") &&
write(this, data, "utf8") &&
write(this, "\xff", "binary")
) {
writeSocket(socket, "\x00", "binary") &&
writeSocket(socket, data, "utf8") &&
writeSocket(socket, "\xff", "binary")
){
return true;
} else {
debug(this.id, "\033[31mERROR: write: "+data);
@ -284,88 +297,86 @@ Connection.prototype.write = function(data) {
Connection.prototype.send = Connection.prototype.write;
Connection.prototype.broadcast = function(data){
this._manager.forEach(function(client){
if(client && client._state === 4 && client.id != this.id){
var conn = this;
this._server.manager.forEach(function(client){
if(client && client._state === 4 && client.id != conn.id){
client.write(data);
}
}, this);
});
};
Connection.prototype.close = function(){
if(this._state == 4 && this._socket.writable){
write(this, "\xff", "binary");
write(this, "\x00", "binary");
}
var socket = this._req.socket;
this.state(5);
if(this._state == 4 && socket.writable){
writeSocket(socket, "\xff", "binary");
writeSocket(socket, "\x00", "binary");
}
closeClient(this);
};
Connection.prototype.reject = function(reason){
debug(this.id, "rejected. Reason: "+reason);
this.state(5);
this.debug && debug(this.id, "rejected. Reason: "+reason);
this.emit("rejected");
closeClient(this);
};
Connection.prototype.handshake = function(){
if(this._state < 3){
debug(this.id, this.version+" handshake");
this.debug && debug(this.id, this.version+" handshake");
this.state(3);
doHandshake[this.version].call(this);
} else {
debug(this.id, "Already handshaked.");
this.debug && debug(this.id, "Already handshaked.");
}
};
/*-----------------------------------------------
Do the handshake.
-----------------------------------------------*/
var handshakes = {
var doHandshake = {
// Using draft75, work out and send the handshake.
draft75: function(connection){
connection.state(3);
var location = websocket_location(connection)
, res;
draft75: function(){
var location = websocket_location.call(this), res;
if(location){
res = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: Upgrade\r\n"
+ "WebSocket-Origin: "+websocket_origin(connection)+"\r\n"
+ "WebSocket-Origin: "+websocket_origin.call(this)+"\r\n"
+ "WebSocket-Location: "+location;
if(connection._options.subprotocol && typeof connection._options.subprotocol == "string") {
res += "\r\nWebSocket-Protocol: "+connection._options.subprotocol;
if(this._server.options.subprotocol && typeof this._server.options.subprotocol == "string") {
res += "\r\nWebSocket-Protocol: "+this._server.options.subprotocol;
}
write(connection, res+"\r\n\r\n", "ascii");
connection.state(4);
writeSocket(this._req.socket, res+"\r\n\r\n", "ascii");
this.state(4);
}
},
// Using draft76 (security model), work out and send the handshake.
draft76: function(connection, upgradeHead){
connection.state(3);
var location = websocket_location(connection)
, res;
draft76: function(){
var location = websocket_location.call(this), res;
if(location){
res = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Origin: "+websocket_origin(connection)+"\r\n"
+ "Sec-WebSocket-Origin: "+websocket_origin.call(this)+"\r\n"
+ "Sec-WebSocket-Location: "+location;
if(connection._options.subprotocol && typeof connection._options.subprotocol == "string") {
res += "\r\nSec-WebSocket-Protocol: "+connection._options.subprotocol;
if(this._server.options.subprotocol && typeof this._server.options.subprotocol == "string") {
res += "\r\nSec-WebSocket-Protocol: "+this._server.options.subprotocol;
}
var strkey1 = connection._req.headers['sec-websocket-key1']
, strkey2 = connection._req.headers['sec-websocket-key2']
var strkey1 = this._req.headers['sec-websocket-key1']
, strkey2 = this._req.headers['sec-websocket-key2']
, numkey1 = parseInt(strkey1.replace(/[^\d]/g, ""), 10)
, numkey2 = parseInt(strkey2.replace(/[^\d]/g, ""), 10)
@ -375,7 +386,7 @@ var handshakes = {
if (spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0) {
connection.reject("WebSocket contained an invalid key -- closing connection.");
this.reject("WebSocket contained an invalid key -- closing connection.");
} else {
var hash = Crypto.createHash("md5")
, key1 = pack(parseInt(numkey1/spaces1))
@ -383,14 +394,13 @@ var handshakes = {
hash.update(key1);
hash.update(key2);
hash.update(upgradeHead.toString("binary"));
hash.update(this._upgradeHead.toString("binary"));
res += "\r\n\r\n";
res += hash.digest("binary");
write(connection, res, "binary");
connection.state(4);
writeSocket(this._req.socket, res, "binary");
this.state(4);
}
}
}
@ -400,15 +410,12 @@ var handshakes = {
The new onData callback for
http.Server IncomingMessage
-----------------------------------------------*/
function Parser(){
events.EventEmitter.call(this);
var Parser = function(client){
this.frameData = [];
this.order = 0;
this.client = client;
};
util.inherits(Parser, events.EventEmitter);
Parser.prototype.write = function(data){
var pkt, msg;
for(var i = 0, len = data.length; i<len; i++){
@ -424,12 +431,12 @@ Parser.prototype.write = function(data){
this.order = 0;
this.frameData = [];
this.emit("message", pkt.toString("utf8", 0, pkt.length));
this.client.emit("message", pkt.toString("utf8", 0, pkt.length));
} else {
this.frameData.push(data[i]);
}
} else if(this.order == 1){
debug("High Order packet handling is not yet implemented.");
debug(this.client.id, "High Order packet handling is not yet implemented.");
this.order = 0;
}
}

131
vendor/ws/manager.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,131 @@
var debug, sys;
/*-----------------------------------------------
Connection Manager
-----------------------------------------------*/
module.exports = Manager;
function Manager(showDebug){
if(showDebug) {
sys = require("sys");
debug = function(){sys.error('\033[31mManager: ' + Array.prototype.join.call(arguments, ", ") + "\033[39m"); };
} else {
debug = function(){};
}
this._head = null;
this._tail = null;
this._length = 0;
this._counter = 0;
};
Object.defineProperty(Manager.prototype, "length", {
get: function(){
return this._length;
}
});
Manager.prototype.createId = function(remotePort) {
return process.pid + "" + remotePort + "" + (this._counter++);
};
Manager.prototype.attach = function(id, client){
var connection = {
id: id,
_next: null,
client: client
};
if(this._length == 0) {
this._head = connection;
this._tail = connection;
} else {
this._tail._next = connection;
this._tail = connection;
}
++this._length;
debug("Attached: "+id, this._length);
};
Manager.prototype.detach = function(id, callback){
var previous = current = this._head;
while(current !== null){
if(current.id === id){
previous._next = current._next;
this._length--;
if(current.id === this._head.id){
this._head = current._next;
}
if(current.id === this._tail.id){
this._tail = previous;
}
break;
} else {
previous = current;
current = current._next;
}
}
delete current, previous;
debug("Detached: "+id, this._length);
callback();
};
Manager.prototype.find = function(id, callback, thisArg){
var current = this._head;
while(current !== null){
if(current.id === id){
callback.call(thisArg, current.client);
break;
} else {
current = current._next;
}
}
};
Manager.prototype.forEach = function(callback, thisArg){
var current = this._head;
while(current !== null){
callback.call(thisArg, current.client);
current = current._next;
}
};
Manager.prototype.map = function(callback, thisArg){
var current = this._head
, len = 0
, result = new Array(this._length);
while(current !== null){
result[len] = callback.call(thisArg, current.client, len, this._head);
current = current._next;
++len;
}
return result;
};
Manager.prototype.filter = function(callback, thisArg){
var current = this._head
, len = 0
, result = new Array(this._length);
while(current !== null){
if( Boolean(callback.call(thisArg, current.client, len, this._head)) ){
result[len] = current.client;
++len;
}
current = current._next;
}
return result;
};

72
vendor/ws/mem-store.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,72 @@
/*-----------------------------------------------
Storage is a simple in memory storage object.
In otherwords, don't run your website off it.
-----------------------------------------------*/
module.exports = {
create: function(){
return new memStore();
}
};
function memStore(){
var data = {};
return {
set: function(key, value){
return data[key] = value;
},
get: function(key, def){
if(data[key] !== undefined){
return data[key];
} else {
return def;
}
},
exists: function(key){
return data[key] !== undefined;
},
incr: function(key){
if(data[key] === undefined){
data[key] = 0;
}
if(typeof(data[key]) === "number"){
return data[key]++;
}
},
decr: function(key){
if(typeof(data[key]) === "number"){
return data[key]--;
}
},
push: function(key, value){
if(data[key] === undefined){
data[key] = [];
}
if(Array.isArray(data[key])){
data[key].push(value);
}
},
pop: function(key){
if(data[key] !== undefined && Array.isArray(data[key])){
return data[key].pop();
}
},
del: function(key){
data[key] = undefined;
},
to_json: function(){
return JSON.stringify(data);
}
};
};

Просмотреть файл