Compare commits

...

11 Commits
0.6.6 ... 0.6.9

Author SHA1 Message Date
Guillermo Rauch
f3ba4173c7 Release 0.6.9 2011-02-06 10:09:13 -08:00
Guillermo Rauch
569103e19a Updated expresso 2011-02-06 09:34:16 -08:00
Guillermo Rauch
06445a0faa Added comments and version number to socket.io/index 2011-02-06 09:33:40 -08:00
Guillermo Rauch
2506b06961 Tests refactored for 0.3 and new expresso 2011-02-06 09:33:15 -08:00
Guillermo Rauch
992eda86b4 Updated socket.io client to 0.6.2 2011-02-05 11:40:39 -08:00
Guillermo Rauch
6fa8b1f051 Fixed Flash inline policy serving for Firefox 4 2011-02-05 11:40:14 -08:00
Guillermo Rauch
a91c6f26f4 Release 0.6.8 2011-01-10 01:50:26 -08:00
Guillermo Rauch
aa9f2596cb Fixed issue with terminating connection twice 2011-01-10 01:48:05 -08:00
Guillermo Rauch
e2a97588ef Removed unnecessary code 2011-01-09 19:07:11 -08:00
Guillermo Rauch
0b904d79c2 Release 0.6.7 2011-01-09 18:55:30 -08:00
Guillermo Rauch
f99ac54df5 Fixed situation where the connection drops but the client can still autoreconnect
through a different socket. In this case we still want to clear the FD but not call
onDisconnect immediately.
2011-01-09 18:53:40 -08:00
40 changed files with 797 additions and 629 deletions

View File

@@ -1,4 +1,25 @@
0.6.9 / 2011-02-06
==================
* 0.3 compatibility
* Updated socket.io client to 0.6.2
* Fixed Flash inline policy serving for Firefox 4
* Updated expresso
* Added comments and version number to socket.io/index
0.6.8 / 2011-01-10
==================
* Fixed issue with terminating connection twice
0.6.7 / 2011-01-09
==================
* Fixed situation where the connection drops but the client can still autoreconnect
through a different socket. In this case we still want to clear the FD but not
call onDisconnect immediately.
0.6.6 / 2011-01-09
==================

View File

@@ -69,6 +69,8 @@ Client.prototype._onConnect = function(req, res){
this.connection.addListener('end', function(){
self._onClose();
if (self.connection)
self.connection.destroy();
});
if (req){
@@ -145,11 +147,6 @@ Client.prototype._onClose = function(skipDisconnect){
Client.prototype._onDisconnect = function(){
if (this._open) this._onClose(true);
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
if (this.connection){
this.connection.end();
this.connection.destroy();
this.connection = null;
}
this._writeQueue = [];
this.connected = false;
if (this.handshaked){

View File

@@ -1,4 +1,26 @@
exports.Listener = require('./listener');
/**
* Listener creation shorcut
*
* @param {Server} node HTTP server
* @param {Object} options
* @api public
*/
exports.listen = function(server, options){
return new exports.Listener(server, options);
};
};
/**
* Listener constructor
*
* @api public
*/
exports.Listener = require('./listener');
/**
* Version
*/
exports.version = '0.6.9';

View File

@@ -45,8 +45,7 @@ Flashsocket.init = function(listener){
listener.options.log('Your node instance does not have root privileges. '
+ 'This means that the flash XML policy file will be '
+ 'served inline instead of on port 843. This will slow '
+ 'down initial connections slightly. NOTE: this fails '
+ 'with Firefox 4 betas.');
+ 'down initial connections slightly.');
netserver = null;
}
}

View File

@@ -1,6 +1,6 @@
{ "name" : "socket.io"
, "description" : "The cross-browser WebSocket"
, "version" : "0.6.6"
, "version" : "0.6.9"
, "author" : "LearnBoost"
, "licenses" :
[ { "type" : "MIT"

View File

@@ -1,4 +1,35 @@
0.7.2 / 2010-12-29
==================
* Fixed problem with `listen()` sometimes firing on the same tick [guillermo]
0.7.1 / 2010-12-28
==================
* Fixed `assert.request()` client logic into an issue() function, fired upon the `listen()` callback if the server doesn't have an assigned fd. [guillermo]
* Removed `--watch`
0.7.0 / 2010-11-19
==================
* Removed `assert` from test function signature
Just use `require('assert')` :) this will make integration
with libraries like [should](http://github.com/visionmedia/should) cleaner.
0.6.4 / 2010-11-02
==================
* Added regexp support to `assert.response()` headers
* Removed `waitForExit` code, causing issues
0.6.3 / 2010-11-02
==================
* Added `assert.response()` body RegExp support
* Fixed issue with _--serial_ not executing files sequentially. Closes #42
* Fixed hang when modules use `setInterval` - monitor running tests & force the process to quit after all have completed + timeout [Steve Mason]
0.6.2 / 2010-09-17
==================

View File

@@ -35,5 +35,27 @@ Install via npm:
$ npm install expresso
## License
(The MIT License)
Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node
/*!
/*
* Expresso
* Copyright(c) TJ Holowaychuk <tj@vision-media.ca>
* (MIT Licensed)
@@ -23,7 +23,7 @@ var assert = require('assert'),
* Expresso version.
*/
var version = '0.6.2';
var version = '0.7.2';
/**
* Failure count.
@@ -62,12 +62,6 @@ var growl = false;
var port = 5555;
/**
* Watch mode.
*/
var watch = false;
/**
* Execute serially.
*/
@@ -80,6 +74,12 @@ var serial = false;
var timeout = 2000;
/**
* Quiet output.
*/
var quiet = false;
/**
* Usage documentation.
*/
@@ -88,9 +88,9 @@ var usage = ''
+ '[bold]{Usage}: expresso [options] <file ...>'
+ '\n'
+ '\n[bold]{Options}:'
+ '\n -w, --watch Watch for modifications and re-execute tests'
+ '\n -g, --growl Enable growl notifications'
+ '\n -c, --coverage Generate and report test coverage'
+ '\n -q, --quiet Suppress coverage report if 100%'
+ '\n -t, --timeout MS Timeout in milliseconds, defaults to 2000'
+ '\n -r, --require PATH Require the given module path'
+ '\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)'
@@ -171,14 +171,14 @@ while (args.length) {
run(files);
})
break;
case '-q':
case '--quiet':
quiet = true;
break;
case '-b':
case '--boring':
boring = true;
break;
case '-w':
case '--watch':
watch = true;
break;
case '-g':
case '--growl':
growl = true;
@@ -339,6 +339,27 @@ assert.length = function(val, n, msg) {
*/
assert.response = function(server, req, res, msg){
// Check that the server is ready or defer
if (!server.fd) {
if (!('__deferred' in server)) {
server.__deferred = [];
}
server.__deferred.push(arguments);
if (!server.__started) {
server.listen(server.__port = port++, '127.0.0.1', function(){
if (server.__deferred) {
process.nextTick(function(){
server.__deferred.forEach(function(args){
assert.response.apply(assert, args);
});
});
}
});
server.__started = true;
}
return;
}
// Callback as third or fourth arg
var callback = typeof res === 'function'
? res
@@ -357,84 +378,92 @@ assert.response = function(server, req, res, msg){
// Create client
if (!server.fd) {
server.listen(server.__port = port++, '127.0.0.1');
server.client = http.createClient(server.__port);
server.listen(server.__port = port++, '127.0.0.1', issue);
} else {
issue();
}
// Issue request
var timer,
client = server.client,
method = req.method || 'GET',
status = res.status || res.statusCode,
data = req.data || req.body,
timeout = req.timeout || 0;
function issue(){
if (!server.client)
server.client = http.createClient(server.__port);
var request = client.request(method, req.url, req.headers);
// Issue request
var timer,
client = server.client,
method = req.method || 'GET',
status = res.status || res.statusCode,
data = req.data || req.body,
requestTimeout = req.timeout || 0;
// Timeout
if (timeout) {
timer = setTimeout(function(){
--server.__pending || server.close();
delete req.timeout;
assert.fail(msg + 'Request timed out after ' + timeout + 'ms.');
}, timeout);
}
var request = client.request(method, req.url, req.headers);
if (data) request.write(data);
request.addListener('response', function(response){
response.body = '';
response.setEncoding('utf8');
response.addListener('data', function(chunk){ response.body += chunk; });
response.addListener('end', function(){
--server.__pending || server.close();
if (timer) clearTimeout(timer);
// Timeout
if (requestTimeout) {
timer = setTimeout(function(){
--server.__pending || server.close();
delete req.timeout;
assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.');
}, requestTimeout);
}
// Assert response body
if (res.body !== undefined) {
var eql = res.body instanceof RegExp
? res.body.test(response.body)
: res.body === response.body;
assert.ok(
eql,
msg + 'Invalid response body.\n'
+ ' Expected: ' + sys.inspect(res.body) + '\n'
+ ' Got: ' + sys.inspect(response.body)
);
}
if (data) request.write(data);
request.on('response', function(response){
response.body = '';
response.setEncoding('utf8');
response.on('data', function(chunk){ response.body += chunk; });
response.on('end', function(){
--server.__pending || server.close();
if (timer) clearTimeout(timer);
// Assert response status
if (typeof status === 'number') {
assert.equal(
response.statusCode,
status,
msg + colorize('Invalid response status code.\n'
+ ' Expected: [green]{' + status + '}\n'
+ ' Got: [red]{' + response.statusCode + '}')
);
}
// Assert response headers
if (res.headers) {
var keys = Object.keys(res.headers);
for (var i = 0, len = keys.length; i < len; ++i) {
var name = keys[i],
actual = response.headers[name.toLowerCase()],
expected = res.headers[name];
assert.equal(
actual,
expected,
msg + colorize('Invalid response header [bold]{' + name + '}.\n'
+ ' Expected: [green]{' + expected + '}\n'
+ ' Got: [red]{' + actual + '}')
// Assert response body
if (res.body !== undefined) {
var eql = res.body instanceof RegExp
? res.body.test(response.body)
: res.body === response.body;
assert.ok(
eql,
msg + 'Invalid response body.\n'
+ ' Expected: ' + sys.inspect(res.body) + '\n'
+ ' Got: ' + sys.inspect(response.body)
);
}
}
// Callback
callback(response);
// Assert response status
if (typeof status === 'number') {
assert.equal(
response.statusCode,
status,
msg + colorize('Invalid response status code.\n'
+ ' Expected: [green]{' + status + '}\n'
+ ' Got: [red]{' + response.statusCode + '}')
);
}
// Assert response headers
if (res.headers) {
var keys = Object.keys(res.headers);
for (var i = 0, len = keys.length; i < len; ++i) {
var name = keys[i],
actual = response.headers[name.toLowerCase()],
expected = res.headers[name],
eql = expected instanceof RegExp
? expected.test(actual)
: expected == actual;
assert.ok(
eql,
msg + colorize('Invalid response header [bold]{' + name + '}.\n'
+ ' Expected: [green]{' + expected + '}\n'
+ ' Got: [red]{' + actual + '}')
);
}
}
// Callback
callback(response);
});
});
});
request.end();
request.end();
}
};
/**
@@ -476,7 +505,6 @@ function rpad(str, width) {
*/
function reportCoverage(cov) {
populateCoverage(cov);
// Stats
print('\n [bold]{Test Coverage}\n');
var sep = ' +------------------------------------------+----------+------+------+--------+',
@@ -507,9 +535,11 @@ function reportCoverage(cov) {
for (var name in cov) {
if (name.match(/\.js$/)) {
var file = cov[name];
print('\n [bold]{' + name + '}:');
print(file.source);
sys.print('\n');
if ((file.coverage < 100) || !quiet) {
print('\n [bold]{' + name + '}:');
print(file.source);
sys.print('\n');
}
}
}
}
@@ -574,6 +604,25 @@ function coverage(data, val) {
return n;
}
/**
* Test if all files have 100% coverage
*
* @param {Object} cov
* @return {Boolean}
*/
function hasFullCoverage(cov) {
for (var name in cov) {
var file = cov[name];
if (file instanceof Array) {
if (file.coverage !== 100) {
return false;
}
}
}
return true;
}
/**
* Run the given test `files`, or try _test/*_.
*
@@ -581,6 +630,7 @@ function coverage(data, val) {
*/
function run(files) {
cursor(false);
if (!files.length) {
try {
files = fs.readdirSync('test').map(function(file){
@@ -592,7 +642,6 @@ function run(files) {
process.exit(1);
}
}
if (watch) watchFiles(files);
runFiles(files);
}
@@ -617,16 +666,25 @@ function cursor(show) {
*/
function runFiles(files) {
files.forEach(runFile);
if (serial) {
(function next(){
if (files.length) {
runFile(files.shift(), next);
}
})();
} else {
files.forEach(runFile);
}
}
/**
* Run tests for the given `file`.
* Run tests for the given `file`, callback `fn()` when finished.
*
* @param {String} file
* @param {Function} fn
*/
function runFile(file) {
function runFile(file, fn) {
if (file.match(/\.js$/)) {
var title = path.basename(file),
file = path.join(cwd, file),
@@ -634,7 +692,7 @@ function runFile(file) {
(function check(){
var len = Object.keys(mod).length;
if (len) {
runSuite(title, mod);
runSuite(title, mod, fn);
} else {
setTimeout(check, 20);
}
@@ -642,49 +700,6 @@ function runFile(file) {
}
}
/**
* Clear the module cache for the given `file`.
*
* @param {String} file
*/
function clearCache(file) {
var keys = Object.keys(module.moduleCache);
for (var i = 0, len = keys.length; i < len; ++i) {
var key = keys[i];
if (key.indexOf(file) === key.length - file.length) {
delete module.moduleCache[key];
}
}
}
/**
* Watch the given `files` for changes.
*
* @param {Array} files
*/
function watchFiles(files) {
var p = 0,
c = ['▫ ', '▫▫ ', '▫▫▫ ', ' ▫▫▫',
' ▫▫', ' ▫', ' ▫', ' ▫▫',
'▫▫▫ ', '▫▫ ', '▫ '],
l = c.length;
cursor(false);
setInterval(function(){
sys.print(colorize(' [green]{' + c[p++ % l] + '} watching\r'));
}, 100);
files.forEach(function(file){
fs.watchFile(file, { interval: 100 }, function(curr, prev){
if (curr.mtime > prev.mtime) {
print(' [yellow]{◦} ' + file);
clearCache(file);
runFile(file);
}
});
});
}
/**
* Report `err` for the given `test` and `suite`.
*
@@ -696,23 +711,23 @@ function watchFiles(files) {
function error(suite, test, err) {
++failures;
var name = err.name,
stack = err.stack.replace(err.name, ''),
stack = err.stack ? err.stack.replace(err.name, '') : '',
label = test === 'uncaught'
? test
: suite + ' ' + test;
print('\n [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
if (watch) notify(label + ' failed');
}
/**
* Run the given tests.
* Run the given tests, callback `fn()` when finished.
*
* @param {String} title
* @param {Object} tests
* @param {Function} fn
*/
var dots = 0;
function runSuite(title, tests) {
function runSuite(title, tests, fn) {
// Keys
var keys = only.length
? only.slice(0)
@@ -720,7 +735,7 @@ function runSuite(title, tests) {
// Setup
var setup = tests.setup || function(fn){ fn(); };
// Iterate tests
(function next(){
if (keys.length) {
@@ -735,27 +750,25 @@ function runSuite(title, tests) {
++testcount;
assert.testTitle = key;
if (serial) {
if (!watch) {
sys.print('.');
if (++dots % 25 === 0) sys.print('\n');
}
sys.print('.');
if (++dots % 25 === 0) sys.print('\n');
setup(function(){
if (test.length < 2) {
test(assert);
if (test.length < 1) {
test();
next();
} else {
var id = setTimeout(function(){
throw new Error("'" + key + "' timed out");
}, timeout);
test(assert, function(){
test(function(){
clearTimeout(id);
next();
});
}
});
} else {
test(assert, function(fn){
process.addListener('beforeExit', function(){
test(function(fn){
process.on('beforeExit', function(){
try {
fn();
} catch (err) {
@@ -769,6 +782,8 @@ function runSuite(title, tests) {
}
}
if (!serial) next();
} else if (serial) {
fn();
}
})();
}
@@ -778,6 +793,7 @@ function runSuite(title, tests) {
*/
function report() {
cursor(true);
process.emit('beforeExit');
if (failures) {
print('\n [bold]{Failures}: [red]{' + failures + '}\n\n');
@@ -788,7 +804,10 @@ function report() {
notify('100% ok');
}
if (typeof _$jscoverage === 'object') {
reportCoverage(_$jscoverage);
populateCoverage(_$jscoverage);
if (!hasFullCoverage(_$jscoverage) || !quiet) {
reportCoverage(_$jscoverage);
}
}
}
@@ -806,14 +825,14 @@ function notify(msg) {
// Report uncaught exceptions
process.addListener('uncaughtException', function(err){
process.on('uncaughtException', function(err){
error('uncaught', 'uncaught', err);
});
// Show cursor
['INT', 'TERM', 'QUIT'].forEach(function(sig){
process.addListener('SIG' + sig, function(){
process.on('SIG' + sig, function(){
cursor(true);
process.exit(1);
});

View File

@@ -113,7 +113,7 @@ code .this { color: #19469D; }</style>
<h1>!/usr/bin/env node</h1>
</td>
<td class="code">
<pre><code>!
<pre><code>
* <span class="class">Expresso</span>
* <span class="class">Copyright</span>(<span class="variable">c</span>) <span class="class">TJ</span> <span class="class">Holowaychuk</span> &<span class="variable">lt</span>;<span class="variable">tj</span>@<span class="variable">vision</span>-<span class="variable">media</span>.<span class="variable">ca</span>&<span class="variable">gt</span>;
* (<span class="class">MIT</span> <span class="class">Licensed</span>)
@@ -142,7 +142,7 @@ code .this { color: #19469D; }</style>
</p>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="variable">version</span> = <span class="string">'0.6.1'</span>;</code></pre>
<pre><code><span class="keyword">var</span> <span class="variable">version</span> = <span class="string">'0.6.4'</span>;</code></pre>
</td>
</tr>
<tr class="code">
@@ -219,6 +219,15 @@ code .this { color: #19469D; }</style>
</tr>
<tr class="code">
<td class="docs">
<p>Default timeout.
</p>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="variable">timeout</span> = <span class="number integer">2000</span>;</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<p>Usage documentation.
</p>
</td>
@@ -230,6 +239,7 @@ code .this { color: #19469D; }</style>
+ <span class="string">'\n -w, --watch Watch for modifications and re-execute tests'</span>
+ <span class="string">'\n -g, --growl Enable growl notifications'</span>
+ <span class="string">'\n -c, --coverage Generate and report test coverage'</span>
+ <span class="string">'\n -t, --timeout MS Timeout in milliseconds, defaults to 2000'</span>
+ <span class="string">'\n -r, --require PATH Require the given module path'</span>
+ <span class="string">'\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)'</span>
+ <span class="string">'\n -I, --include PATH Unshift the given path to require.paths'</span>
@@ -291,6 +301,14 @@ code .this { color: #19469D; }</style>
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">Error</span>(<span class="string">'--require requires a path'</span>);
}
<span class="keyword">break</span>;
<span class="keyword">case</span> <span class="string">'-t'</span>:
<span class="keyword">case</span> <span class="string">'--timeout'</span>:
<span class="keyword">if</span> (<span class="variable">arg</span> = <span class="variable">args</span>.<span class="variable">shift</span>()) {
<span class="variable">timeout</span> = <span class="variable">parseInt</span>(<span class="variable">arg</span>, <span class="number integer">10</span>);
} <span class="keyword">else</span> {
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">Error</span>(<span class="string">'--timeout requires an argument'</span>);
}
<span class="keyword">break</span>;
<span class="keyword">case</span> <span class="string">'-c'</span>:
<span class="keyword">case</span> <span class="string">'--cov'</span>:
<span class="keyword">case</span> <span class="string">'--coverage'</span>:
@@ -525,17 +543,17 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
<span class="variable">method</span> = <span class="variable">req</span>.<span class="variable">method</span> || <span class="string">'GET'</span>,
<span class="variable">status</span> = <span class="variable">res</span>.<span class="variable">status</span> || <span class="variable">res</span>.<span class="variable">statusCode</span>,
<span class="variable">data</span> = <span class="variable">req</span>.<span class="variable">data</span> || <span class="variable">req</span>.<span class="variable">body</span>,
<span class="variable">timeout</span> = <span class="variable">req</span>.<span class="variable">timeout</span> || <span class="number integer">0</span>;
<span class="variable">requestTimeout</span> = <span class="variable">req</span>.<span class="variable">timeout</span> || <span class="number integer">0</span>;
<span class="keyword">var</span> <span class="variable">request</span> = <span class="variable">client</span>.<span class="variable">request</span>(<span class="variable">method</span>, <span class="variable">req</span>.<span class="variable">url</span>, <span class="variable">req</span>.<span class="variable">headers</span>);
<span class="comment">// Timeout</span>
<span class="keyword">if</span> (<span class="variable">timeout</span>) {
<span class="keyword">if</span> (<span class="variable">requestTimeout</span>) {
<span class="variable">timer</span> = <span class="variable">setTimeout</span>(<span class="keyword">function</span>(){
--<span class="variable">server</span>.<span class="variable">__pending</span> || <span class="variable">server</span>.<span class="variable">close</span>();
<span class="keyword">delete</span> <span class="variable">req</span>.<span class="variable">timeout</span>;
<span class="variable">assert</span>.<span class="variable">fail</span>(<span class="variable">msg</span> + <span class="string">'Request timed out after '</span> + <span class="variable">timeout</span> + <span class="string">'ms.'</span>);
}, <span class="variable">timeout</span>);
<span class="variable">assert</span>.<span class="variable">fail</span>(<span class="variable">msg</span> + <span class="string">'Request timed out after '</span> + <span class="variable">requestTimeout</span> + <span class="string">'ms.'</span>);
}, <span class="variable">requestTimeout</span>);
}
<span class="keyword">if</span> (<span class="variable">data</span>) <span class="variable">request</span>.<span class="variable">write</span>(<span class="variable">data</span>);
@@ -549,9 +567,11 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
<span class="comment">// Assert response body</span>
<span class="keyword">if</span> (<span class="variable">res</span>.<span class="variable">body</span> !== <span class="variable">undefined</span>) {
<span class="variable">assert</span>.<span class="variable">equal</span>(
<span class="variable">response</span>.<span class="variable">body</span>,
<span class="variable">res</span>.<span class="variable">body</span>,
<span class="keyword">var</span> <span class="variable">eql</span> = <span class="variable">res</span>.<span class="variable">body</span> <span class="variable">instanceof</span> <span class="class">RegExp</span>
? <span class="variable">res</span>.<span class="variable">body</span>.<span class="variable">test</span>(<span class="variable">response</span>.<span class="variable">body</span>)
: <span class="variable">res</span>.<span class="variable">body</span> === <span class="variable">response</span>.<span class="variable">body</span>;
<span class="variable">assert</span>.<span class="variable">ok</span>(
<span class="variable">eql</span>,
<span class="variable">msg</span> + <span class="string">'Invalid response body.\n'</span>
+ <span class="string">' Expected: '</span> + <span class="variable">sys</span>.<span class="variable">inspect</span>(<span class="variable">res</span>.<span class="variable">body</span>) + <span class="string">'\n'</span>
+ <span class="string">' Got: '</span> + <span class="variable">sys</span>.<span class="variable">inspect</span>(<span class="variable">response</span>.<span class="variable">body</span>)
@@ -575,10 +595,12 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
<span class="keyword">for</span> (<span class="keyword">var</span> <span class="variable">i</span> = <span class="number integer">0</span>, <span class="variable">len</span> = <span class="variable">keys</span>.<span class="variable">length</span>; <span class="variable">i</span> &<span class="variable">lt</span>; <span class="variable">len</span>; ++<span class="variable">i</span>) {
<span class="keyword">var</span> <span class="variable">name</span> = <span class="variable">keys</span>[<span class="variable">i</span>],
<span class="variable">actual</span> = <span class="variable">response</span>.<span class="variable">headers</span>[<span class="variable">name</span>.<span class="variable">toLowerCase</span>()],
<span class="variable">expected</span> = <span class="variable">res</span>.<span class="variable">headers</span>[<span class="variable">name</span>];
<span class="variable">assert</span>.<span class="variable">equal</span>(
<span class="variable">actual</span>,
<span class="variable">expected</span>,
<span class="variable">expected</span> = <span class="variable">res</span>.<span class="variable">headers</span>[<span class="variable">name</span>],
<span class="variable">eql</span> = <span class="variable">expected</span> <span class="variable">instanceof</span> <span class="class">RegExp</span>
? <span class="variable">expected</span>.<span class="variable">test</span>(<span class="variable">actual</span>)
: <span class="variable">expected</span> == <span class="variable">actual</span>;
<span class="variable">assert</span>.<span class="variable">ok</span>(
<span class="variable">eql</span>,
<span class="variable">msg</span> + <span class="variable">colorize</span>(<span class="string">'Invalid response header [bold]{'</span> + <span class="variable">name</span> + <span class="string">'}.\n'</span>
+ <span class="string">' Expected: [green]{'</span> + <span class="variable">expected</span> + <span class="string">'}\n'</span>
+ <span class="string">' Got: [red]{'</span> + <span class="variable">actual</span> + <span class="string">'}'</span>)
@@ -800,20 +822,28 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
</td>
<td class="code">
<pre><code><span class="keyword">function</span> <span class="variable">runFiles</span>(<span class="variable">files</span>) {
<span class="variable">files</span>.<span class="variable">forEach</span>(<span class="variable">runFile</span>);
<span class="keyword">if</span> (<span class="variable">serial</span>) {
(<span class="keyword">function</span> <span class="variable">next</span>(){
<span class="keyword">if</span> (<span class="variable">files</span>.<span class="variable">length</span>) {
<span class="variable">runFile</span>(<span class="variable">files</span>.<span class="variable">shift</span>(), <span class="variable">next</span>);
}
})();
} <span class="keyword">else</span> {
<span class="variable">files</span>.<span class="variable">forEach</span>(<span class="variable">runFile</span>);
}
}</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<p>Run tests for the given <code>file</code>.</p>
<p>Run tests for the given <code>file</code>, callback <code>fn()</code> when finished.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>String</em> file</p></li></ul>
<ul><li><p><strong>param</strong>: <em>String</em> file</p></li><li><p><strong>param</strong>: <em>Function</em> fn</p></li></ul>
</td>
<td class="code">
<pre><code><span class="keyword">function</span> <span class="variable">runFile</span>(<span class="variable">file</span>) {
<pre><code><span class="keyword">function</span> <span class="variable">runFile</span>(<span class="variable">file</span>, <span class="variable">fn</span>) {
<span class="keyword">if</span> (<span class="variable">file</span>.<span class="variable">match</span>(<span class="regexp">/\.js$/</span>)) {
<span class="keyword">var</span> <span class="variable">title</span> = <span class="variable">path</span>.<span class="variable">basename</span>(<span class="variable">file</span>),
<span class="variable">file</span> = <span class="variable">path</span>.<span class="variable">join</span>(<span class="variable">cwd</span>, <span class="variable">file</span>),
@@ -821,7 +851,7 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
(<span class="keyword">function</span> <span class="variable">check</span>(){
<span class="keyword">var</span> <span class="variable">len</span> = <span class="class">Object</span>.<span class="variable">keys</span>(<span class="variable">mod</span>).<span class="variable">length</span>;
<span class="keyword">if</span> (<span class="variable">len</span>) {
<span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">mod</span>);
<span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">mod</span>, <span class="variable">fn</span>);
} <span class="keyword">else</span> {
<span class="variable">setTimeout</span>(<span class="variable">check</span>, <span class="number integer">20</span>);
}
@@ -904,15 +934,15 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
</tr>
<tr class="code">
<td class="docs">
<p>Run the given tests.</p>
<p>Run the given tests, callback <code>fn()</code> when finished.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>String</em> title</p></li><li><p><strong>param</strong>: <em>Object</em> tests</p></li></ul>
<ul><li><p><strong>param</strong>: <em>String</em> title</p></li><li><p><strong>param</strong>: <em>Object</em> tests</p></li><li><p><strong>param</strong>: <em>Function</em> fn</p></li></ul>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="variable">dots</span> = <span class="number integer">0</span>;
<span class="keyword">function</span> <span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">tests</span>) {
<span class="keyword">function</span> <span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">tests</span>, <span class="variable">fn</span>) {
<span class="comment">// Keys</span>
<span class="keyword">var</span> <span class="variable">keys</span> = <span class="variable">only</span>.<span class="variable">length</span>
? <span class="variable">only</span>.<span class="variable">slice</span>(<span class="number integer">0</span>)
@@ -920,7 +950,7 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
<span class="comment">// Setup</span>
<span class="keyword">var</span> <span class="variable">setup</span> = <span class="variable">tests</span>.<span class="variable">setup</span> || <span class="keyword">function</span>(<span class="variable">fn</span>){ <span class="variable">fn</span>(); };
<span class="comment">// Iterate tests</span>
(<span class="keyword">function</span> <span class="variable">next</span>(){
<span class="keyword">if</span> (<span class="variable">keys</span>.<span class="variable">length</span>) {
@@ -940,21 +970,21 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
<span class="keyword">if</span> (++<span class="variable">dots</span> % <span class="number integer">25</span> === <span class="number integer">0</span>) <span class="variable">sys</span>.<span class="variable">print</span>(<span class="string">'\n'</span>);
}
<span class="variable">setup</span>(<span class="keyword">function</span>(){
<span class="keyword">if</span> (<span class="variable">test</span>.<span class="variable">length</span> &<span class="variable">lt</span>; <span class="number integer">2</span>) {
<span class="variable">test</span>(<span class="variable">assert</span>);
<span class="keyword">if</span> (<span class="variable">test</span>.<span class="variable">length</span> &<span class="variable">lt</span>; <span class="number integer">1</span>) {
<span class="variable">test</span>();
<span class="variable">next</span>();
} <span class="keyword">else</span> {
<span class="keyword">var</span> <span class="variable">id</span> = <span class="variable">setTimeout</span>(<span class="keyword">function</span>(){
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">Error</span>(&<span class="variable">quot</span>;<span class="string">'&quot; + key + &quot;'</span> <span class="variable">timed</span> <span class="variable">out</span>&<span class="variable">quot</span>;);
}, <span class="number integer">2000</span>);
<span class="variable">test</span>(<span class="variable">assert</span>, <span class="keyword">function</span>(){
}, <span class="variable">timeout</span>);
<span class="variable">test</span>(<span class="keyword">function</span>(){
<span class="variable">clearTimeout</span>(<span class="variable">id</span>);
<span class="variable">next</span>();
});
}
});
} <span class="keyword">else</span> {
<span class="variable">test</span>(<span class="variable">assert</span>, <span class="keyword">function</span>(<span class="variable">fn</span>){
<span class="variable">test</span>(<span class="keyword">function</span>(<span class="variable">fn</span>){
<span class="variable">process</span>.<span class="variable">addListener</span>(<span class="string">'beforeExit'</span>, <span class="keyword">function</span>(){
<span class="keyword">try</span> {
<span class="variable">fn</span>();
@@ -969,6 +999,8 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
}
}
<span class="keyword">if</span> (!<span class="variable">serial</span>) <span class="variable">next</span>();
} <span class="keyword">else</span> <span class="keyword">if</span> (<span class="variable">serial</span>) {
<span class="variable">fn</span>();
}
})();
}</code></pre>

View File

@@ -41,6 +41,10 @@
<div id="wrapper">
<h1>Expresso</h1>
<div class='mp'>
<h2 id="NAME">NAME</h2>
<p class="man-name">
<code>index</code>
</p>
<p><a href="http://github.com/visionmedia/expresso">Expresso</a> is a JavaScript <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> framework written for <a href="http://nodejs.org">nodejs</a>. Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more.</p>
<h2 id="Features">Features</h2>
@@ -85,7 +89,7 @@ the command below, which will first compile node-jscoverage:</p>
<p>To define tests we simply export several functions:</p>
<pre><code>exports['test String#length'] = function(assert){
<pre><code>exports['test String#length'] = function(){
assert.equal(6, 'foobar'.length);
};
</code></pre>
@@ -95,7 +99,7 @@ export your own object containing the tests, however this
is essentially the as above:</p>
<pre><code>module.exports = {
'test String#length': function(assert){
'test String#length': function(){
assert.equal(6, 'foobar'.length);
}
};
@@ -103,16 +107,16 @@ is essentially the as above:</p>
<p>If you prefer not to use quoted keys:</p>
<pre><code>exports.testsStringLength = function(assert){
<pre><code>exports.testsStringLength = function(){
assert.equal(6, 'foobar'.length);
};
</code></pre>
<p>The second argument passed to each callback is <em>beforeExit</em>,
<p>The argument passed to each callback is <em>beforeExit</em>,
which is typically used to assert that callbacks have been
invoked.</p>
<pre><code>exports.testAsync = function(assert, beforeExit){
<pre><code>exports.testAsync = function(beforeExit){
var n = 0;
setTimeout(function(){
++n;
@@ -229,9 +233,9 @@ which is then used to perform several assertions
on the response with the following properties:</p>
<ul>
<li><em>body</em> assert response body</li>
<li><em>body</em> assert response body (regexp or string)</li>
<li><em>status</em> assert response status code</li>
<li><em>header</em> assert that all given headers match (unspecified are ignored)</li>
<li><em>header</em> assert that all given headers match (unspecified are ignored, use a regexp or string)</li>
</ul>
@@ -361,7 +365,7 @@ future <code>--cov</code> will most likely accept a path.</p>
<p>Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the <em>exports.foo = function(){};</em> syntax is supported for this:</p>
<pre><code>setTimeout(function(){
exports['test async exports'] = function(assert){
exports['test async exports'] = function(){
assert.ok('wahoo');
};
}, 100);

View File

@@ -37,7 +37,7 @@ Install via npm:
To define tests we simply export several functions:
exports['test String#length'] = function(assert){
exports['test String#length'] = function(){
assert.equal(6, 'foobar'.length);
};
@@ -46,22 +46,22 @@ export your own object containing the tests, however this
is essentially the as above:
module.exports = {
'test String#length': function(assert){
'test String#length': function(){
assert.equal(6, 'foobar'.length);
}
};
If you prefer not to use quoted keys:
exports.testsStringLength = function(assert){
exports.testsStringLength = function(){
assert.equal(6, 'foobar'.length);
};
The second argument passed to each callback is _beforeExit_,
The argument passed to each callback is _beforeExit_,
which is typically used to assert that callbacks have been
invoked.
exports.testAsync = function(assert, beforeExit){
exports.testAsync = function(beforeExit){
var n = 0;
setTimeout(function(){
++n;
@@ -164,9 +164,9 @@ receives the response for assertions, or an object
which is then used to perform several assertions
on the response with the following properties:
- _body_ assert response body
- _body_ assert response body (regexp or string)
- _status_ assert response status code
- _header_ assert that all given headers match (unspecified are ignored)
- _header_ assert that all given headers match (unspecified are ignored, use a regexp or string)
When providing _res_ you may then also pass a callback function
as the fourth argument for additional assertions.
@@ -284,7 +284,7 @@ future `--cov` will most likely accept a path.
Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the _exports.foo = function(){};_ syntax is supported for this:
setTimeout(function(){
exports['test async exports'] = function(assert){
exports['test async exports'] = function(){
assert.ok('wahoo');
};
}, 100);

View File

@@ -1,5 +1,5 @@
{ "name": "expresso",
"version": "0.6.2",
"version": "0.7.2",
"description": "TDD framework, light-weight, fast, CI-friendly",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"bin": {

View File

@@ -1,9 +1,16 @@
/**
* Module dependencies.
*/
var assert = require('assert');
module.exports = {
'assert.eql()': function(assert){
'assert.eql()': function(){
assert.equal(assert.deepEqual, assert.eql);
},
'assert.type()': function(assert){
'assert.type()': function(){
assert.type('foobar', 'string');
assert.type(2, 'number');
assert.throws(function(){
@@ -11,7 +18,7 @@ module.exports = {
});
},
'assert.includes()': function(assert){
'assert.includes()': function(){
assert.includes('some random string', 'dom');
assert.throws(function(){
assert.include('some random string', 'foobar');
@@ -31,7 +38,7 @@ module.exports = {
});
},
'assert.isNull()': function(assert){
'assert.isNull()': function(){
assert.isNull(null);
assert.throws(function(){
assert.isNull(undefined);
@@ -41,7 +48,7 @@ module.exports = {
});
},
'assert.isUndefined()': function(assert){
'assert.isUndefined()': function(){
assert.isUndefined(undefined);
assert.throws(function(){
assert.isUndefined(null);
@@ -51,7 +58,7 @@ module.exports = {
});
},
'assert.isNotNull()': function(assert){
'assert.isNotNull()': function(){
assert.isNotNull(false);
assert.isNotNull(undefined);
assert.throws(function(){
@@ -59,7 +66,7 @@ module.exports = {
});
},
'assert.isDefined()': function(assert){
'assert.isDefined()': function(){
assert.isDefined(false);
assert.isDefined(null);
assert.throws(function(){
@@ -67,14 +74,14 @@ module.exports = {
});
},
'assert.match()': function(assert){
'assert.match()': function(){
assert.match('foobar', /foo(bar)?/);
assert.throws(function(){
assert.match('something', /rawr/);
});
},
'assert.length()': function(assert){
'assert.length()': function(){
assert.length('test', 4);
assert.length([1,2,3,4], 4);
assert.throws(function(){

View File

@@ -1,6 +1,12 @@
/**
* Module dependencies.
*/
var assert = require('assert');
setTimeout(function(){
exports['test async exports'] = function(assert){
exports['test async exports'] = function(){
assert.ok('wahoo');
};
}, 100);

View File

@@ -3,10 +3,11 @@
* Module dependencies.
*/
var bar = require('bar');
var assert = require('assert')
, bar = require('bar');
module.exports = {
'bar()': function(assert){
'bar()': function(){
assert.equal('bar', bar.bar());
}
};

View File

@@ -3,10 +3,11 @@
* Module dependencies.
*/
var foo = require('foo');
var assert = require('assert')
, foo = require('foo');
module.exports = {
'foo()': function(assert){
'foo()': function(){
assert.equal('foo', foo.foo());
assert.equal('foo', foo.foo());
}

View File

@@ -3,80 +3,144 @@
* Module dependencies.
*/
var http = require('http');
var assert = require('assert')
, http = require('http');
var server = http.createServer(function(req, res){
if (req.method === 'GET') {
if (req.url === '/delay') {
setTimeout(function(){
res.writeHead(200, {});
res.end('delayed');
}, 200);
} else {
var body = JSON.stringify({ name: 'tj' });
res.writeHead(200, {
'Content-Type': 'application/json; charset=utf8',
'Content-Length': body.length
});
res.end(body);
}
if (req.method === 'GET') {
if (req.url === '/delay') {
setTimeout(function(){
res.writeHead(200, {});
res.end('delayed');
}, 200);
} else {
var body = '';
req.setEncoding('utf8');
req.addListener('data', function(chunk){ body += chunk });
req.addListener('end', function(){
res.writeHead(200, {});
res.end(req.url + ' ' + body);
});
var body = JSON.stringify({ name: 'tj' });
res.writeHead(200, {
'Content-Type': 'application/json; charset=utf8',
'Content-Length': body.length
});
res.end(body);
}
} else {
var body = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ body += chunk });
req.on('end', function(){
res.writeHead(200, {});
res.end(req.url + ' ' + body);
});
}
});
module.exports = {
'test assert.response()': function(assert, beforeExit){
var called = 0;
var delayedServer = http.createServer(function(req, res){
res.writeHead(200);
res.end('it worked');
});
assert.response(server, {
url: '/',
method: 'GET'
},{
body: '{"name":"tj"}',
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf8'
}
});
assert.response(server, {
url: '/foo',
method: 'POST',
data: 'bar baz'
},{
body: '/foo bar baz',
status: 200
}, function(res){
++called;
assert.ok(res);
});
assert.response(server, {
url: '/foo'
}, function(res){
++called;
assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
});
assert.response(server,
{ url: '/delay', timeout: 300 },
{ body: 'delayed' });
beforeExit(function(){
assert.equal(2, called);
});
},
var oldListen = delayedServer.listen;
delayedServer.listen = function(){
var args = arguments;
setTimeout(function(){
oldListen.apply(delayedServer, args);
}, 100);
};
module.exports = {
'test assert.response(req, res, fn)': function(beforeExit){
var calls = 0;
assert.response(server, {
url: '/',
method: 'GET'
},{
body: '{"name":"tj"}',
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf8'
}
}, function(res){
++calls;
assert.ok(res);
});
'test assert.response() regexp': function(assert){
assert.response(server,
{ url: '/foo', method: 'POST', data: 'foobar' },
{ body: /^\/foo foo(bar)?/ });
}
};
beforeExit(function(){
assert.equal(1, calls);
})
},
'test assert.response(req, fn)': function(beforeExit){
var calls = 0;
assert.response(server, {
url: '/foo'
}, function(res){
++calls;
assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
});
beforeExit(function(){
assert.equal(1, calls);
});
},
'test assert.response() delay': function(beforeExit){
var calls = 0;
assert.response(server,
{ url: '/delay', timeout: 1500 },
{ body: 'delayed' },
function(){
++calls;
});
beforeExit(function(){
assert.equal(1, calls);
});
},
'test assert.response() regexp': function(beforeExit){
var calls = 0;
assert.response(server,
{ url: '/foo', method: 'POST', data: 'foobar' },
{ body: /^\/foo foo(bar)?/ },
function(){
++calls;
});
beforeExit(function(){
assert.equal(1, calls);
});
},
'test assert.response() regexp headers': function(beforeExit){
var calls = 0;
assert.response(server,
{ url: '/' },
{ body: '{"name":"tj"}', headers: { 'Content-Type': /^application\/json/ } },
function(){
++calls;
});
beforeExit(function(){
assert.equal(1, calls);
});
},
// [!] if this test doesn't pass, an uncaught ECONNREFUSED will display
'test assert.response() with deferred listen()': function(beforeExit){
var calls = 0;
assert.response(delayedServer,
{ url: '/' },
{ body: 'it worked' },
function(){
++calls;
});
beforeExit(function(){
assert.equal(1, calls);
});
}
};

View File

@@ -1,6 +1,7 @@
var setup = 0,
order = [];
var assert = require('assert')
, setup = 0
, order = [];
module.exports = {
setup: function(done){
@@ -8,7 +9,7 @@ module.exports = {
done();
},
a: function(assert, done){
a: function(done){
assert.equal(1, setup);
order.push('a');
setTimeout(function(){
@@ -16,7 +17,7 @@ module.exports = {
}, 500);
},
b: function(assert, done){
b: function(done){
assert.equal(2, setup);
order.push('b');
setTimeout(function(){
@@ -24,7 +25,7 @@ module.exports = {
}, 200);
},
c: function(assert, done){
c: function(done){
assert.equal(3, setup);
order.push('c');
setTimeout(function(){
@@ -32,7 +33,7 @@ module.exports = {
}, 1000);
},
d: function(assert){
d: function(){
assert.eql(order, ['a', 'b', 'c']);
}
};

View File

@@ -3,7 +3,8 @@
* Module dependencies.
*/
var http = require('http');
var assert = require('assert')
, http = require('http');
var server = http.createServer(function(req, res){
if (req.method === 'GET') {
@@ -32,7 +33,7 @@ var server = http.createServer(function(req, res){
});
module.exports = {
'test assert.response()': function(assert, done){
'test assert.response()': function(done){
assert.response(server, {
url: '/',
method: 'GET'

View File

@@ -1,3 +0,0 @@
[submodule "lib/vendor/web-socket-js"]
path = lib/vendor/web-socket-js
url = git://github.com/gimite/web-socket-js.git

View File

@@ -46,14 +46,6 @@ The `socket.io` client is basically a simple HTTP Socket interface implementatio
- Easy to use! See [socket.io-node](http://github.com/LearnBoost/Socket.IO-node) for the server to connect to.
### How to use
The recommended way of including the Socket.IO client is through the Socket.IO CDN:
In your &lt;head&gt;
<script src="http://cdn.socket.io/stable/socket.io.js"></script>
Then, in your code
socket = new io.Socket('localhost');
socket.connect();
@@ -163,6 +155,17 @@ Events:
Fired when the connection is established and the handshake successful
- *connecting(transport_type)*
Fired when a connection is attempted, passing the transport name
- *connect_failed*
Fired when the connection timeout occurs after the last connection attempt.
This only fires if the `connectTimeout` option is set.
If the `tryTransportsOnConnectTimeout` option is set, this only fires once all
possible transports have been tried.
- *message(message)*
Fired when a message arrives from the server
@@ -175,14 +178,6 @@ Events:
Fired when the connection is considered disconnected.
### Changelog
2010 08 02 - **0.5.4** (9.95KB)
* Added io.util.load as a reusable onload handler
* Added io.util.ios which reports if the UA is running on iPhone or iPad
* No more loading bar on iPhone: XHR-Polling now connects `onload` for the iOS WebKit, and waits 10 ms to launch the initial connection.
### Credits
Guillermo Rauch &lt;guillermo@learnboost.com&gt;
@@ -210,4 +205,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -7,7 +7,7 @@
*/
this.io = {
version: '0.6.1',
version: '0.6.2',
setPath: function(path){
if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf');

View File

@@ -59,6 +59,7 @@
if (this.transport && !this.connected){
if (this.connecting) this.disconnect();
this.connecting = true;
this.emit('connecting', [this.transport.type]);
this.transport.connect();
if (this.options.connectTimeout){
var self = this;
@@ -66,16 +67,17 @@
if (!self.connected){
self.disconnect();
if (self.options.tryTransportsOnConnectTimeout && !self._rememberedTransport){
var remainingTransports = [], transports = self.options.transports;
for (var i = 0, transport; transport = transports[i]; i++){
if (transport != self.transport.type) remainingTransports.push(transport);
}
if (remainingTransports.length){
self.transport = self.getTransport(remainingTransports);
if(!self._remainingTransports) self._remainingTransports = self.options.transports.slice(0);
var transports = self._remainingTransports;
while(transports.length > 0 && transports.splice(0,1)[0] != self.transport.type){}
if(transports.length){
self.transport = self.getTransport(transports);
self.connect();
}
}
if(!self._remainingTransports || self._remainingTransports.length == 0) self.emit('connect_failed');
}
if(self._remainingTransports && self._remainingTransports.length == 0) delete self._remainingTransports;
}, this.options.connectTimeout);
}
}

View File

@@ -20,7 +20,7 @@
var self = this;
this._xhr = this._request('', 'GET', true);
this._xhr.onreadystatechange = function(){
if (self._xhr.readyState == 3) self._onData(self._xhr.responseText);
if (self._xhr.readyState == 4) self._onData(self._xhr.responseText);
};
this._xhr.send(null);
};

View File

@@ -22,11 +22,7 @@ import com.hurlant.crypto.tls.TLSEngine;
import com.hurlant.crypto.tls.TLSSecurityParameters;
import com.gsolo.encryption.MD5;
[Event(name="message", type="flash.events.Event")]
[Event(name="open", type="flash.events.Event")]
[Event(name="close", type="flash.events.Event")]
[Event(name="error", type="flash.events.Event")]
[Event(name="stateChange", type="WebSocketStateEvent")]
[Event(name="event", type="flash.events.Event")]
public class WebSocket extends EventDispatcher {
private static var CONNECTING:int = 0;
@@ -47,10 +43,9 @@ public class WebSocket extends EventDispatcher {
private var origin:String;
private var protocol:String;
private var buffer:ByteArray = new ByteArray();
private var dataQueue:Array;
private var eventQueue:Array = [];
private var headerState:int = 0;
private var readyState:int = CONNECTING;
private var bufferedAmount:int = 0;
private var headers:String;
private var noiseChars:Array;
private var expectedDigest:String;
@@ -115,23 +110,19 @@ public class WebSocket extends EventDispatcher {
socket.flush();
main.log("sent: " + data);
return -1;
} else if (readyState == CLOSED) {
} else if (readyState == CLOSING || readyState == CLOSED) {
var bytes:ByteArray = new ByteArray();
bytes.writeUTFBytes(data);
bufferedAmount += bytes.length; // not sure whether it should include \x00 and \xff
// We use return value to let caller know bufferedAmount because we cannot fire
// stateChange event here which causes weird error:
// > You are trying to call recursively into the Flash Player which is not allowed.
return bufferedAmount;
return bytes.length; // not sure whether it should include \x00 and \xff
} else {
main.fatal("INVALID_STATE_ERR: invalid state");
main.fatal("invalid state");
return 0;
}
}
public function close():void {
main.log("close");
dataQueue = [];
eventQueue = [];
try {
if (readyState == OPEN) {
socket.writeByte(0xff);
@@ -146,14 +137,6 @@ public class WebSocket extends EventDispatcher {
// We do something equivalent in JavaScript WebSocket#close instead.
}
public function getReadyState():int {
return readyState;
}
public function getBufferedAmount():int {
return bufferedAmount;
}
private function onSocketConnect(event:Event):void {
main.log("connected");
@@ -162,7 +145,6 @@ public class WebSocket extends EventDispatcher {
tlsSocket.startTLS(rawSocket, host, tlsConfig);
}
dataQueue = [];
var hostValue:String = host + (port == 80 ? "" : ":" + port);
var cookie:String = "";
if (main.getCallerHost() == host) {
@@ -199,8 +181,7 @@ public class WebSocket extends EventDispatcher {
private function onSocketClose(event:Event):void {
main.log("closed");
readyState = CLOSED;
notifyStateChange();
dispatchEvent(new Event("close"));
fireEvent({type: "close"}, true);
}
private function onSocketIoError(event:IOErrorEvent):void {
@@ -230,8 +211,7 @@ public class WebSocket extends EventDispatcher {
if (state == CLOSED) return;
main.error(message);
close();
notifyStateChange();
dispatchEvent(new Event(state == CONNECTING ? "close" : "error"));
fireEvent({type: state == CONNECTING ? "close" : "error"}, true);
}
private function onSocketData(event:ProgressEvent):void {
@@ -248,8 +228,7 @@ public class WebSocket extends EventDispatcher {
headerState = 0;
}
if (headerState == 4) {
buffer.position = 0;
var headerStr:String = buffer.readUTFBytes(pos + 1);
var headerStr:String = readUTFBytes(buffer, 0, pos + 1);
main.log("response header:\n" + headerStr);
if (!validateHeader(headerStr)) return;
removeBufferBefore(pos + 1);
@@ -257,8 +236,7 @@ public class WebSocket extends EventDispatcher {
}
} else if (headerState == 4) {
if (pos == 15) {
buffer.position = 0;
var replyDigest:String = readBytes(buffer, 16);
var replyDigest:String = readBytes(buffer, 0, 16);
main.log("reply digest: " + replyDigest);
if (replyDigest != expectedDigest) {
onError("digest doesn't match: " + replyDigest + " != " + expectedDigest);
@@ -268,8 +246,7 @@ public class WebSocket extends EventDispatcher {
removeBufferBefore(pos + 1);
pos = -1;
readyState = OPEN;
notifyStateChange();
dispatchEvent(new Event("open"));
fireEvent({type: "open"}, true);
}
} else {
if (buffer[pos] == 0xff && pos > 0) {
@@ -277,11 +254,9 @@ public class WebSocket extends EventDispatcher {
onError("data must start with \\x00");
return;
}
buffer.position = 1;
var data:String = buffer.readUTFBytes(pos - 1);
var data:String = readUTFBytes(buffer, 1, pos - 1);
main.log("received: " + data);
dataQueue.push(encodeURIComponent(data));
dispatchEvent(new Event("message"));
fireEvent({type: "message", data: encodeURIComponent(data)}, false);
removeBufferBefore(pos + 1);
pos = -1;
} else if (pos == 1 && buffer[0] == 0xff && buffer[1] == 0x00) { // closing
@@ -289,18 +264,15 @@ public class WebSocket extends EventDispatcher {
removeBufferBefore(pos + 1);
pos = -1;
close();
notifyStateChange();
dispatchEvent(new Event("close"));
fireEvent({type: "close"}, true);
}
}
}
}
public function readSocketData():Array {
var q:Array = dataQueue;
if (dataQueue.length > 0) {
dataQueue = [];
}
public function receiveEvents():Array {
var q:Array = eventQueue;
eventQueue = [];
return q;
}
@@ -363,8 +335,12 @@ public class WebSocket extends EventDispatcher {
buffer = nextBuffer;
}
private function notifyStateChange():void {
dispatchEvent(new WebSocketStateEvent("stateChange", readyState, bufferedAmount));
private function fireEvent(event:Object, stateChanged:Boolean):void {
if (stateChanged) {
event.readyState = readyState;
}
eventQueue.push(event);
dispatchEvent(new Event("event"));
}
private function initNoiseChars():void {
@@ -434,7 +410,8 @@ public class WebSocket extends EventDispatcher {
// Reads specified number of bytes from buffer, and returns it as special format String
// where bytes[i] is i-th byte (not i-th character).
private function readBytes(buffer:ByteArray, numBytes:int):String {
private function readBytes(buffer:ByteArray, start:int, numBytes:int):String {
buffer.position = start;
var bytes:String = "";
for (var i:int = 0; i < numBytes; ++i) {
// & 0xff is to make \x80-\xff positive number.
@@ -443,6 +420,20 @@ public class WebSocket extends EventDispatcher {
return bytes;
}
private function readUTFBytes(buffer:ByteArray, start:int, numBytes:int):String {
buffer.position = start;
var data:String = "";
for(var i:int = start; i < start + numBytes; ++i) {
// Workaround of a bug of ByteArray#readUTFBytes() that bytes after "\x00" is discarded.
if (buffer[i] == 0x00) {
data += buffer.readUTFBytes(i - buffer.position) + "\x00";
buffer.position = i + 1;
}
}
data += buffer.readUTFBytes(start + numBytes - buffer.position);
return data;
}
private function randomInt(min:uint, max:uint):uint {
return min + Math.floor(Math.random() * (Number(max) - min + 1));
}

View File

@@ -19,24 +19,14 @@ import bridge.FABridge;
public class WebSocketMain extends Sprite {
private var policyLoaded:Boolean = false;
private var callerUrl:String;
private var debug:Boolean = false;
private var manualPolicyFileLoaded:Boolean = false;
public function WebSocketMain() {
// This is to avoid "You are trying to call recursively into the Flash Player ..."
// error which (I heard) happens when you pass bunch of messages.
// This workaround was written here:
// http://www.themorphicgroup.com/blog/2009/02/14/fabridge-error-you-are-trying-to-call-recursively-into-the-flash-player-which-is-not-allowed/
FABridge.EventsToCallLater["flash.events::Event"] = "true";
FABridge.EventsToCallLater["WebSocketMessageEvent"] = "true";
FABridge.EventsToCallLater["WebSocketStateEvent"] = "true";
var fab:FABridge = new FABridge();
fab.rootObject = this;
//log("Flash initialized");
}
public function setCallerUrl(url:String):void {
@@ -51,7 +41,9 @@ public class WebSocketMain extends Sprite {
url:String, protocol:String,
proxyHost:String = null, proxyPort:int = 0,
headers:String = null):WebSocket {
loadPolicyFile(null);
if (!manualPolicyFileLoaded) {
loadDefaultPolicyFile(url);
}
return new WebSocket(this, url, protocol, proxyHost, proxyPort, headers);
}
@@ -64,14 +56,16 @@ public class WebSocketMain extends Sprite {
return URLUtil.getServerName(this.callerUrl);
}
public function loadPolicyFile(url:String):void {
if (policyLoaded && !url) return;
if (!url) {
url = "xmlsocket://" + URLUtil.getServerName(this.callerUrl) + ":843";
}
log("policy file: " + url);
Security.loadPolicyFile(url);
policyLoaded = true;
private function loadDefaultPolicyFile(wsUrl:String):void {
var policyUrl:String = "xmlsocket://" + URLUtil.getServerName(wsUrl) + ":843";
log("policy file: " + policyUrl);
Security.loadPolicyFile(policyUrl);
}
public function loadManualPolicyFile(policyUrl:String):void {
log("policy file: " + policyUrl);
Security.loadPolicyFile(policyUrl);
manualPolicyFileLoaded = true;
}
public function log(message:String):void {

View File

@@ -1,32 +0,0 @@
// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-31
package {
import flash.display.*;
import flash.events.*;
import flash.external.*;
import flash.net.*;
import flash.system.*;
import flash.utils.*;
import mx.core.*;
import mx.controls.*;
import mx.events.*;
import mx.utils.*;
public class WebSocketStateEvent extends Event {
public var readyState:int;
public var bufferedAmount:int;
public function WebSocketStateEvent(type:String, readyState:int, bufferedAmount:int) {
super(type);
this.readyState = readyState;
this.bufferedAmount = bufferedAmount;
}
}
}

View File

@@ -8,8 +8,10 @@
if (window.WebSocket) return;
var console = window.console;
if (!console) console = {log: function(){ }, error: function(){ }};
if (!console || !console.log || !console.error) {
console = {log: function(){ }, error: function(){ }};
}
if (!swfobject.hasFlashPlayerVersion("9.0.0")) {
console.error("Flash Player is not installed.");
return;
@@ -31,73 +33,22 @@
WebSocket.__addTask(function() {
self.__createFlash(url, protocol, proxyHost, proxyPort, headers);
});
}, 1);
}
}, 0);
};
WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) {
var self = this;
self.__flash =
WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
self.__flash.addEventListener("open", function(fe) {
try {
self.readyState = self.__flash.getReadyState();
if (self.__timer) clearInterval(self.__timer);
if (window.opera) {
// Workaround for weird behavior of Opera which sometimes drops events.
self.__timer = setInterval(function () {
self.__handleMessages();
}, 500);
}
if (self.onopen) self.onopen();
} catch (e) {
console.error(e.toString());
}
self.__flash.addEventListener("event", function(fe) {
// Uses setTimeout() to workaround the error:
// > You are trying to call recursively into the Flash Player which is not allowed.
setTimeout(function() { self.__handleEvents(); }, 0);
});
self.__flash.addEventListener("close", function(fe) {
try {
self.readyState = self.__flash.getReadyState();
if (self.__timer) clearInterval(self.__timer);
if (self.onclose) self.onclose();
} catch (e) {
console.error(e.toString());
}
});
self.__flash.addEventListener("message", function() {
try {
self.__handleMessages();
} catch (e) {
console.error(e.toString());
}
});
self.__flash.addEventListener("error", function(fe) {
try {
if (self.__timer) clearInterval(self.__timer);
if (self.onerror) self.onerror();
} catch (e) {
console.error(e.toString());
}
});
self.__flash.addEventListener("stateChange", function(fe) {
try {
self.readyState = self.__flash.getReadyState();
self.bufferedAmount = fe.getBufferedAmount();
} catch (e) {
console.error(e.toString());
}
});
//console.log("[WebSocket] Flash object is ready");
};
WebSocket.prototype.send = function(data) {
if (this.__flash) {
this.readyState = this.__flash.getReadyState();
}
if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
}
@@ -111,7 +62,7 @@
if (result < 0) { // success
return true;
} else {
this.bufferedAmount = result;
this.bufferedAmount += result;
return false;
}
};
@@ -119,7 +70,6 @@
WebSocket.prototype.close = function() {
var self = this;
if (!self.__flash) return;
self.readyState = self.__flash.getReadyState();
if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return;
self.__flash.close();
// Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
@@ -130,7 +80,7 @@
if (self.onclose) {
// Make it asynchronous so that it looks more like an actual
// close event
setTimeout(self.onclose, 1);
setTimeout(self.onclose, 0);
}
};
@@ -199,30 +149,62 @@
}
};
WebSocket.prototype.__handleMessages = function() {
// Gets data using readSocketData() instead of getting it from event object
WebSocket.prototype.__handleEvents = function() {
// Gets events using receiveEvents() instead of getting it from event object
// of Flash event. This is to make sure to keep message order.
// It seems sometimes Flash events don't arrive in the same order as they are sent.
var arr = this.__flash.readSocketData();
for (var i = 0; i < arr.length; i++) {
var data = decodeURIComponent(arr[i]);
var events = this.__flash.receiveEvents();
for (var i = 0; i < events.length; i++) {
try {
if (this.onmessage) {
var e;
if (window.MessageEvent) {
e = document.createEvent("MessageEvent");
e.initMessageEvent("message", false, false, data, null, null, window, null);
} else { // IE
e = {data: data};
var event = events[i];
if ("readyState" in event) {
this.readyState = event.readyState;
}
if (event.type == "open") {
if (this.__timer) clearInterval(this.__timer);
if (window.opera) {
// Workaround for weird behavior of Opera which sometimes drops events.
this.__timer = setInterval(function () {
this.__handleEvents();
}, 500);
}
this.onmessage(e);
if (this.onopen) this.onopen();
} else if (event.type == "close") {
if (this.__timer) clearInterval(this.__timer);
if (this.onclose) this.onclose();
} else if (event.type == "message") {
if (this.onmessage) {
var data = decodeURIComponent(event.data);
var e;
if (window.MessageEvent && !window.opera) {
e = document.createEvent("MessageEvent");
e.initMessageEvent("message", false, false, data, null, null, window, null);
} else {
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
e = {data: data};
}
this.onmessage(e);
}
} else if (event.type == "error") {
if (this.__timer) clearInterval(this.__timer);
if (this.onerror) this.onerror();
} else {
throw "unknown event type: " + event.type;
}
} catch (e) {
console.error(e.toString());
}
}
};
/**
* @param {object} object
* @param {string} type
@@ -237,7 +219,7 @@
}
object.dispatchEvent(event, arguments);
};
}
};
/**
* Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
@@ -298,6 +280,12 @@
WebSocket.__tasks = [];
WebSocket.loadFlashPolicyFile = function(url) {
WebSocket.__addTask(function() {
WebSocket.__flash.loadManualPolicyFile(url);
});
}
WebSocket.__initialize = function() {
if (WebSocket.__swfLocation) {
// For backword compatibility.

View File

@@ -1,4 +1,4 @@
/** Socket.IO 0.6.1 - Built with build.js */
/** Socket.IO 0.6.2 - Built with build.js */
/**
* Socket.IO client
*
@@ -8,7 +8,7 @@
*/
this.io = {
version: '0.6.1',
version: '0.6.2',
setPath: function(path){
if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf');
@@ -577,7 +577,7 @@ if (typeof window != 'undefined'){
var self = this;
this._xhr = this._request('', 'GET', true);
this._xhr.onreadystatechange = function(){
if (self._xhr.readyState == 3) self._onData(self._xhr.responseText);
if (self._xhr.readyState == 4) self._onData(self._xhr.responseText);
};
this._xhr.send(null);
};
@@ -831,6 +831,7 @@ JSONPPolling.xdomainCheck = function(){
if (this.transport && !this.connected){
if (this.connecting) this.disconnect();
this.connecting = true;
this.emit('connecting', [this.transport.type]);
this.transport.connect();
if (this.options.connectTimeout){
var self = this;
@@ -838,16 +839,17 @@ JSONPPolling.xdomainCheck = function(){
if (!self.connected){
self.disconnect();
if (self.options.tryTransportsOnConnectTimeout && !self._rememberedTransport){
var remainingTransports = [], transports = self.options.transports;
for (var i = 0, transport; transport = transports[i]; i++){
if (transport != self.transport.type) remainingTransports.push(transport);
}
if (remainingTransports.length){
self.transport = self.getTransport(remainingTransports);
if(!self._remainingTransports) self._remainingTransports = self.options.transports.slice(0);
var transports = self._remainingTransports;
while(transports.length > 0 && transports.splice(0,1)[0] != self.transport.type){}
if(transports.length){
self.transport = self.getTransport(transports);
self.connect();
}
}
if(!self._remainingTransports || self._remainingTransports.length == 0) self.emit('connect_failed');
}
if(self._remainingTransports && self._remainingTransports.length == 0) delete self._remainingTransports;
}, this.options.connectTimeout);
}
}
@@ -1551,8 +1553,10 @@ ASProxy.prototype =
if (window.WebSocket) return;
var console = window.console;
if (!console) console = {log: function(){ }, error: function(){ }};
if (!console || !console.log || !console.error) {
console = {log: function(){ }, error: function(){ }};
}
if (!swfobject.hasFlashPlayerVersion("9.0.0")) {
console.error("Flash Player is not installed.");
return;
@@ -1574,73 +1578,22 @@ ASProxy.prototype =
WebSocket.__addTask(function() {
self.__createFlash(url, protocol, proxyHost, proxyPort, headers);
});
}, 1);
}
}, 0);
};
WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) {
var self = this;
self.__flash =
WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
self.__flash.addEventListener("open", function(fe) {
try {
self.readyState = self.__flash.getReadyState();
if (self.__timer) clearInterval(self.__timer);
if (window.opera) {
// Workaround for weird behavior of Opera which sometimes drops events.
self.__timer = setInterval(function () {
self.__handleMessages();
}, 500);
}
if (self.onopen) self.onopen();
} catch (e) {
console.error(e.toString());
}
self.__flash.addEventListener("event", function(fe) {
// Uses setTimeout() to workaround the error:
// > You are trying to call recursively into the Flash Player which is not allowed.
setTimeout(function() { self.__handleEvents(); }, 0);
});
self.__flash.addEventListener("close", function(fe) {
try {
self.readyState = self.__flash.getReadyState();
if (self.__timer) clearInterval(self.__timer);
if (self.onclose) self.onclose();
} catch (e) {
console.error(e.toString());
}
});
self.__flash.addEventListener("message", function() {
try {
self.__handleMessages();
} catch (e) {
console.error(e.toString());
}
});
self.__flash.addEventListener("error", function(fe) {
try {
if (self.__timer) clearInterval(self.__timer);
if (self.onerror) self.onerror();
} catch (e) {
console.error(e.toString());
}
});
self.__flash.addEventListener("stateChange", function(fe) {
try {
self.readyState = self.__flash.getReadyState();
self.bufferedAmount = fe.getBufferedAmount();
} catch (e) {
console.error(e.toString());
}
});
//console.log("[WebSocket] Flash object is ready");
};
WebSocket.prototype.send = function(data) {
if (this.__flash) {
this.readyState = this.__flash.getReadyState();
}
if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
}
@@ -1654,7 +1607,7 @@ ASProxy.prototype =
if (result < 0) { // success
return true;
} else {
this.bufferedAmount = result;
this.bufferedAmount += result;
return false;
}
};
@@ -1662,7 +1615,6 @@ ASProxy.prototype =
WebSocket.prototype.close = function() {
var self = this;
if (!self.__flash) return;
self.readyState = self.__flash.getReadyState();
if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return;
self.__flash.close();
// Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
@@ -1673,7 +1625,7 @@ ASProxy.prototype =
if (self.onclose) {
// Make it asynchronous so that it looks more like an actual
// close event
setTimeout(self.onclose, 1);
setTimeout(self.onclose, 0);
}
};
@@ -1742,30 +1694,62 @@ ASProxy.prototype =
}
};
WebSocket.prototype.__handleMessages = function() {
// Gets data using readSocketData() instead of getting it from event object
WebSocket.prototype.__handleEvents = function() {
// Gets events using receiveEvents() instead of getting it from event object
// of Flash event. This is to make sure to keep message order.
// It seems sometimes Flash events don't arrive in the same order as they are sent.
var arr = this.__flash.readSocketData();
for (var i = 0; i < arr.length; i++) {
var data = decodeURIComponent(arr[i]);
var events = this.__flash.receiveEvents();
for (var i = 0; i < events.length; i++) {
try {
if (this.onmessage) {
var e;
if (window.MessageEvent) {
e = document.createEvent("MessageEvent");
e.initMessageEvent("message", false, false, data, null, null, window, null);
} else { // IE
e = {data: data};
var event = events[i];
if ("readyState" in event) {
this.readyState = event.readyState;
}
if (event.type == "open") {
if (this.__timer) clearInterval(this.__timer);
if (window.opera) {
// Workaround for weird behavior of Opera which sometimes drops events.
this.__timer = setInterval(function () {
this.__handleEvents();
}, 500);
}
this.onmessage(e);
if (this.onopen) this.onopen();
} else if (event.type == "close") {
if (this.__timer) clearInterval(this.__timer);
if (this.onclose) this.onclose();
} else if (event.type == "message") {
if (this.onmessage) {
var data = decodeURIComponent(event.data);
var e;
if (window.MessageEvent && !window.opera) {
e = document.createEvent("MessageEvent");
e.initMessageEvent("message", false, false, data, null, null, window, null);
} else {
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
e = {data: data};
}
this.onmessage(e);
}
} else if (event.type == "error") {
if (this.__timer) clearInterval(this.__timer);
if (this.onerror) this.onerror();
} else {
throw "unknown event type: " + event.type;
}
} catch (e) {
console.error(e.toString());
}
}
};
/**
* @param {object} object
* @param {string} type
@@ -1780,7 +1764,7 @@ ASProxy.prototype =
}
object.dispatchEvent(event, arguments);
};
}
};
/**
* Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
@@ -1841,6 +1825,12 @@ ASProxy.prototype =
WebSocket.__tasks = [];
WebSocket.loadFlashPolicyFile = function(url) {
WebSocket.__addTask(function() {
WebSocket.__flash.loadManualPolicyFile(url);
});
}
WebSocket.__initialize = function() {
if (WebSocket.__swfLocation) {
// For backword compatibility.

View File

@@ -1,9 +1,10 @@
var io = require('socket.io')
, assert = require('assert')
, Listener = io.Listener;
module.exports = {
'test server initialization': function(assert){
'test server initialization': function(){
var _server = require('http').createServer(function(){})
, _socket = io.listen(_server, { log: null });
assert.ok(_socket instanceof Listener);
@@ -14,4 +15,4 @@ module.exports = {
})
}
};
};

View File

@@ -1,6 +1,7 @@
var http = require('http')
, net = require('net')
, io = require('socket.io')
, assert = require('assert')
, decode = require('socket.io/utils').decode
, port = 7100
, Listener = io.Listener
@@ -30,7 +31,7 @@ function client(server, sessid){
module.exports = {
'test serving static javascript client': function(assert){
'test serving static javascript client': function(){
var _server = server()
, _socket = socket(_server);
assert.response(_server
@@ -50,7 +51,7 @@ module.exports = {
, { headers: { 'Content-Type': 'application/x-shockwave-flash' }});
},
'test serving non-socket.io requests': function(assert){
'test serving non-socket.io requests': function(){
var _server = server()
, _socket = socket(_server);
_server.on('request', function(req, res){
@@ -64,8 +65,9 @@ module.exports = {
, { body: 'Hello world' });
},
'test destroying an upgrade connection that is not WebSocket': function(assert){
'test destroying an upgrade connection that is not WebSocket': function(){
var _server = server()
, _socket = socket(_server);
listen(_server, function(){
var client = http.createClient(_server._port)
@@ -80,12 +82,15 @@ module.exports = {
client.addListener('end', function(){
assert.ok(! upgraded);
_server.close();
})
});
client.on('error', function (e) {
// ignore errors
});
request.end();
});
},
'test broadcasting to clients': function(assert){
'test broadcasting to clients': function(){
var _server = server()
, _socket = socket(_server);
listen(_server, function(){
@@ -123,7 +128,7 @@ module.exports = {
})
},
'test connecting with an invalid sessionid': function(assert){
'test connecting with an invalid sessionid': function(){
var _server = server()
, _socket = socket(_server);
listen(_server, function(){
@@ -139,7 +144,7 @@ module.exports = {
});
},
'test connecting to an invalid transport': function(assert){
'test connecting to an invalid transport': function(){
var _server = server(function(req, res){
res.writeHead(200);
res.end(req.url == '/socket.io/inexistent' ? 'All cool' : '');
@@ -149,4 +154,4 @@ module.exports = {
assert.response(_server, { url: '/socket.io/inexistent' }, { body: 'All cool' });
}
};
};

View File

@@ -1,6 +1,7 @@
var io = require('socket.io')
, net = require('net')
, http = require('http')
, assert = require('assert')
, querystring = require('querystring')
, port = 7700
, encode = require('socket.io/utils').encode
@@ -31,7 +32,7 @@ function listen(s, callback){
module.exports = {
'test xml policy added to connection': function(assert){
'test xml policy added to connection': function(){
var _server = server()
, _socket = socket(_server);
listen(_server, function(){
@@ -45,4 +46,4 @@ module.exports = {
});
}
}
}

View File

@@ -1,5 +1,6 @@
var io = require('socket.io')
, net = require('net')
, assert = require('assert')
, http = require('http')
, querystring = require('querystring')
, port = 7600
@@ -62,7 +63,10 @@ function get(server, url, assert, callback){
});
client.end = function(){
request.connection.destroy();
if (request.abort)
request.abort();
else
request.connection.destroy();
};
return client;
@@ -77,7 +81,7 @@ function post(client, url, data, callback){
module.exports = {
'test connection and handshake': function(assert){
'test connection and handshake': function(){
var _server = server()
, _socket = socket(_server)
, trips = 2;
@@ -105,7 +109,6 @@ module.exports = {
_socket.on('connection', function(client){
assert.ok(client instanceof HTMLFile);
client.on('message', function(msg){
assert.ok(msg == 'from client');
--trips || close();
});
});
@@ -117,7 +120,7 @@ module.exports = {
});
},
'test clients tracking': function(assert){
'test clients tracking': function(){
var _server = server()
, _socket = socket(_server);
@@ -142,7 +145,7 @@ module.exports = {
});
},
'test buffered messages': function(assert){
'test buffered messages': function(){
var _server = server()
, _socket = socket(_server, { transportOptions: {
'htmlfile': {
@@ -181,7 +184,7 @@ module.exports = {
});
},
'test hearbeat timeout': function(assert){
'test hearbeat timeout': function(){
var _server = server()
, _socket = socket(_server, {
transportOptions: {
@@ -211,4 +214,4 @@ module.exports = {
});
}
};
};

View File

@@ -1,6 +1,7 @@
var io = require('socket.io')
, http = require('http')
, querystring = require('querystring')
, assert = require('assert')
, port = 7500
, encode = require('socket.io/utils').encode
, _decode = require('socket.io/utils').decode
@@ -66,7 +67,7 @@ function post(client, url, data, callback){
module.exports = {
'test connection and handshake': function(assert){
'test connection and handshake': function(){
var _server = server()
, _socket = socket(_server)
, trips = 2;
@@ -98,7 +99,7 @@ module.exports = {
});
},
'test clients tracking': function(assert){
'test clients tracking': function(){
var _server = server()
, _socket = socket(_server);
@@ -113,7 +114,7 @@ module.exports = {
});
},
'test buffered messages': function(assert){
'test buffered messages': function(){
var _server = server()
, _socket = socket(_server, { transportOptions: {
'jsonp-polling': {
@@ -145,4 +146,4 @@ module.exports = {
});
}
};
};

View File

@@ -1,4 +1,5 @@
var io = require('socket.io')
, assert = require('assert')
, encode = require('socket.io/utils').encode
, decode = require('socket.io/utils').decode
, port = 7200
@@ -30,7 +31,7 @@ function client(server, sessid){
module.exports = {
'test connection and handshake': function(assert){
'test connection and handshake': function(){
var _server = server()
, _socket = socket(_server)
, _client
@@ -66,7 +67,7 @@ module.exports = {
});
},
'test clients tracking': function(assert){
'test clients tracking': function(){
var _server = server()
, _socket = socket(_server);
@@ -87,7 +88,7 @@ module.exports = {
});
},
'test buffered messages': function(assert){
'test buffered messages': function(){
var _server = server()
, _socket = socket(_server, {
transportOptions: {
@@ -128,7 +129,7 @@ module.exports = {
});
},
'test json encoding': function(assert){
'test json encoding': function(){
var _server = server()
, _socket = socket(_server)
, _client
@@ -162,7 +163,7 @@ module.exports = {
});
},
'test hearbeat timeout': function(assert){
'test hearbeat timeout': function(){
var _server = server()
, _socket = socket(_server, {
transportOptions: {
@@ -191,7 +192,7 @@ module.exports = {
});
},
'test client broadcast': function(assert){
'test client broadcast': function(){
var _server = server()
, _socket = socket(_server);
@@ -242,4 +243,4 @@ module.exports = {
});
}
};
};

View File

@@ -1,6 +1,7 @@
var io = require('socket.io')
, net = require('net')
, http = require('http')
, assert = require('assert')
, querystring = require('querystring')
, port = 7300
, encode = require('socket.io/utils').encode
@@ -78,7 +79,7 @@ function post(client, url, data, callback){
module.exports = {
'test connection and handshake': function(assert){
'test connection and handshake': function(){
var _server = server()
, _socket = socket(_server)
, trips = 2;
@@ -118,7 +119,7 @@ module.exports = {
});
},
'test clients tracking': function(assert){
'test clients tracking': function(){
var _server = server()
, _socket = socket(_server);
@@ -143,7 +144,7 @@ module.exports = {
});
},
'test buffered messages': function(assert){
'test buffered messages': function(){
var _server = server()
, _socket = socket(_server, { transportOptions: {
'xhr-multipart': {
@@ -182,7 +183,7 @@ module.exports = {
});
},
'test hearbeat timeout': function(assert){
'test hearbeat timeout': function(){
var _server = server()
, _socket = socket(_server, {
transportOptions: {
@@ -212,4 +213,4 @@ module.exports = {
});
}
};
};

View File

@@ -1,5 +1,6 @@
var io = require('socket.io')
, http = require('http')
, assert = require('assert')
, querystring = require('querystring')
, port = 7400
, encode = require('socket.io/utils').encode
@@ -56,7 +57,7 @@ function post(client, url, data, callback){
module.exports = {
'test connection and handshake': function(assert){
'test connection and handshake': function(){
var _server = server()
, _socket = socket(_server)
, trips = 2;
@@ -88,7 +89,7 @@ module.exports = {
});
},
'test clients tracking': function(assert){
'test clients tracking': function(){
var _server = server()
, _socket = socket(_server);
@@ -103,7 +104,7 @@ module.exports = {
});
},
'test buffered messages': function(assert){
'test buffered messages': function(){
var _server = server()
, _socket = socket(_server, { transportOptions: {
'xhr-polling': {
@@ -135,4 +136,4 @@ module.exports = {
});
}
};
};

View File

@@ -1,25 +1,26 @@
var encode = require('socket.io/utils').encode,
var assert = require('assert')
encode = require('socket.io/utils').encode,
decode = require('socket.io/utils').decode;
module.exports = {
'test decoding': function(assert){
'test decoding': function(){
var decoded = decode('~m~5~m~abcde' + '~m~9~m~123456789');
assert.equal(decoded.length, 2);
assert.equal(decoded[0], 'abcde');
assert.equal(decoded[1], '123456789');
},
'test decoding of bad framed messages': function(assert){
'test decoding of bad framed messages': function(){
var decoded = decode('~m~5~m~abcde' + '~m\uffsdaasdfd9~m~1aaa23456789');
assert.equal(decoded.length, 1);
assert.equal(decoded[0], 'abcde');
assert.equal(decoded[1], undefined);
},
'test encoding': function(assert){
'test encoding': function(){
assert.equal(encode(['abcde', '123456789']), '~m~5~m~abcde' + '~m~9~m~123456789');
assert.equal(encode('asdasdsad'), '~m~9~m~asdasdsad');
assert.equal(encode(''), '~m~0~m~');
assert.equal(encode(null), '~m~0~m~');
}
};
};