initial import
Автор
einaros

Коммитер
einaros
14 лет назад 
Файлов изменено: 8
+231
–0
19093dc
Родители v1.x
.gitignore
0 100644
+5
–0
@@ -0,0 +1,5 @@ | ||
npm-debug.log | ||
node_modules | ||
history/ | ||
cache/ | ||
.*.swp |
Makefile
0 100644
+13
–0
@@ -0,0 +1,13 @@ | ||
ALL_TESTS = $(shell find test/ -name '*.test.js') | ||
run-tests: | ||
@./node_modules/.bin/expresso \ | ||
-t 2000 \ | ||
--serial \ | ||
$(TESTFLAGS) \ | ||
$(TESTS) | ||
test: | ||
@$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests | ||
README.md
0 100644
index.js
0 100644
+1
–0
@@ -0,0 +1 @@ | ||
module.exports = require('./lib/Wetsock'); | ||
No newline at end of file |
lib/Wetsock.js
0 100644
+68
–0
@@ -0,0 +1,68 @@ | ||
var util = require('util'); | ||
var events = require('events'); | ||
var http = require('http'); | ||
var crypto = require('crypto'); | ||
function Wetsock(server, port, options) { | ||
var serverPort = 80; | ||
if (typeof port === 'number') serverPort = port; | ||
else if (typeof port === 'object') options = port; | ||
options = options || {}; | ||
options.origin = options.origin || null; | ||
var key = 'dGhlIHNhbXBsZSBub25jZQ=='; | ||
var shasum = crypto.createHash('sha1'); | ||
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); | ||
var expectedServerKey = shasum.digest('base64'); | ||
var requestOptions = { | ||
port: serverPort, | ||
host: server, | ||
headers: { | ||
'Connection': 'Upgrade', | ||
'Upgrade': 'websocket', | ||
'Sec-WebSocket-Version': 13, | ||
'Sec-WebSocket-Key': key | ||
} | ||
}; | ||
if (options.origin) requestOptions.headers.origin = options.origin; | ||
var req = http.request(requestOptions); | ||
req.end(); | ||
this._socket = null; | ||
this._state = 'connecting'; | ||
var self = this; | ||
req.on('upgrade', function(res, socket, upgradeHead) { | ||
if (self._state == 'disconnected') { | ||
socket.end(); | ||
return; | ||
} | ||
var serverKey = res.headers['sec-websocket-accept']; | ||
if (typeof serverKey == 'undefined' || serverKey !== expectedServerKey) { | ||
self.emit('error', 'invalid server key'); | ||
socket.end(); | ||
return; | ||
} | ||
self._socket = socket; | ||
self._state = 'connected'; | ||
self.emit('connect'); | ||
}); | ||
} | ||
util.inherits(Wetsock, events.EventEmitter); | ||
Wetsock.prototype.close = function() { | ||
if (this._socket) { | ||
this._socket.end(); | ||
this._socket = null; | ||
} | ||
else if (this._state == 'connecting') { | ||
this._state = 'disconnected'; | ||
} | ||
} | ||
Wetsock.prototype.send = function(data, options) { | ||
if (this._state != 'connected') throw 'not connected'; | ||
} | ||
module.exports = Wetsock; | ||
No newline at end of file |
package.json
0 100644
+20
–0
@@ -0,0 +1,20 @@ | ||
{ | ||
"author":"Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)", | ||
"name":"wetsock", | ||
"description":"microscopic websocket client", | ||
"version":"0.0.1", | ||
"repository":{ | ||
"type":"git", | ||
"url":"git://github.com/einaros/wetsock.git" | ||
}, | ||
"scripts":{ | ||
"test":"make test" | ||
}, | ||
"engines":{ | ||
"node":"~0.6.0" | ||
}, | ||
"dependencies":{ | ||
"expresso":"latest" | ||
}, | ||
"devDependencies":{} | ||
} |
test/Wetsock.test.js
0 100644
+42
–0
@@ -0,0 +1,42 @@ | ||
var assert = require('assert'); | ||
var Wetsock = require('../'); | ||
var server = require('./server'); | ||
var port = 20000; | ||
module.exports = { | ||
'can connect to echo service': function() { | ||
var ws = new Wetsock('echo.websocket.org'); | ||
ws.on('connect', function() { | ||
ws.close(); | ||
}); | ||
}, | ||
'can disconnect before connection is established': function(done) { | ||
var ws = new Wetsock('echo.websocket.org'); | ||
ws.close(); | ||
ws.on('connect', function() { | ||
assert.fail('connect shouldnt be raised here'); | ||
}); | ||
ws.on('disconnect', function() { | ||
done(); | ||
}); | ||
}, | ||
'send before connect should fail': function(done) { | ||
var ws = new Wetsock('echo.websocket.org'); | ||
try { | ||
ws.send('hi'); | ||
} | ||
catch (e) { | ||
ws.close(); | ||
done(); | ||
} | ||
}, | ||
'invalid server key is denied': function(done) { | ||
var srv = server.listen(++port, server.handlers.invalidKey); | ||
var ws = new Wetsock('localhost', port); | ||
ws.on('error', function() { | ||
srv.close(); | ||
done(); | ||
}); | ||
}, | ||
} | ||
No newline at end of file |
test/server.js
0 100644
+82
–0
@@ -0,0 +1,82 @@ | ||
var http = require('http'); | ||
var crypto = require('crypto'); | ||
function validRequestHandler(req, socket) { | ||
if (typeof req.headers.upgrade === 'undefined' || | ||
req.headers.upgrade.toLowerCase() !== 'websocket') { | ||
throw 'invalid headers'; | ||
return; | ||
} | ||
if (!req.headers['sec-websocket-key']) { | ||
socket.end(); | ||
throw 'websocket key is missing'; | ||
} | ||
// calc key | ||
var key = req.headers['sec-websocket-key']; | ||
var shasum = crypto.createHash('sha1'); | ||
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); | ||
key = shasum.digest('base64'); | ||
var headers = [ | ||
'HTTP/1.1 101 Switching Protocols' | ||
, 'Upgrade: websocket' | ||
, 'Connection: Upgrade' | ||
, 'Sec-WebSocket-Accept: ' + key | ||
]; | ||
socket.write(headers.concat('', '').join('\r\n')); | ||
socket.end(); | ||
// socket.on('data', function (data) { | ||
// self.parser.add(data); | ||
// }); | ||
} | ||
function invalidRequestHandler(req, socket) { | ||
if (typeof req.headers.upgrade === 'undefined' || | ||
req.headers.upgrade.toLowerCase() !== 'websocket') { | ||
throw 'invalid headers'; | ||
return; | ||
} | ||
if (!req.headers['sec-websocket-key']) { | ||
socket.end(); | ||
throw 'websocket key is missing'; | ||
} | ||
// calc key | ||
var key = req.headers['sec-websocket-key']; | ||
var shasum = crypto.createHash('sha1'); | ||
shasum.update(key + "bogus"); | ||
key = shasum.digest('base64'); | ||
var headers = [ | ||
'HTTP/1.1 101 Switching Protocols' | ||
, 'Upgrade: websocket' | ||
, 'Connection: Upgrade' | ||
, 'Sec-WebSocket-Accept: ' + key | ||
]; | ||
socket.write(headers.concat('', '').join('\r\n')); | ||
socket.end(); | ||
// socket.on('data', function (data) { | ||
// self.parser.add(data); | ||
// }); | ||
} | ||
module.exports = { | ||
handlers: { | ||
valid: validRequestHandler, | ||
invalidKey: invalidRequestHandler, | ||
}, | ||
listen: function(port, handler) { | ||
var srv = http.createServer(function (req, res) { | ||
res.writeHead(200, {'Content-Type': 'text/plain'}); | ||
res.end('okay'); | ||
}); | ||
srv.on('upgrade', handler || validRequestHandler); | ||
srv.listen(port, '127.0.0.1'); | ||
return srv; | ||
} | ||
}; | ||
No newline at end of file |
Cherry-pick
Команда cherry-pick позволяет выбрать отдельные коммиты из одной ветки и применить их к другой.