eventsource
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -0,1 +1,9 @@ | ||
# [0.0.7](https://github.com/aslakhellesoy/eventsource-node/compare/v0.0.6...v0.0.7) | ||
* Explicitly raise an error when server returns http 403 and dont continue ([#20](https://github.com/aslakhellesoy/eventsource-node/pull/20) Scott Moak) | ||
* Added ability to send custom http headers to server ([#21](https://github.com/aslakhellesoy/eventsource-node/pull/21), [#9](https://github.com/aslakhellesoy/eventsource-node/issues/9) Scott Moak) | ||
* Fix Unicode support to cope with Javascript Unicode size limitations ([#23](https://github.com/aslakhellesoy/eventsource-node/pull/23), [#22](https://github.com/aslakhellesoy/eventsource-node/issues/22) Devon Adkisson) | ||
* Graceful handling of parse errors ([#19](https://github.com/aslakhellesoy/eventsource-node/issues/19) Aslak Hellesøy) | ||
* Switched from testing with Nodeunit to Mocha (Aslak Hellesøy) | ||
# [0.0.6](https://github.com/aslakhellesoy/eventsource-node/compare/v0.0.5...v0.0.6) | ||
@@ -2,0 +10,0 @@ |
@@ -7,2 +7,6 @@ var http = require('http') | ||
function isPlainObject(obj) { | ||
return Object.getPrototypeOf(obj) === Object.prototype; | ||
} | ||
/** | ||
@@ -12,5 +16,6 @@ * Creates a new EventSource object | ||
* @param {String} url the URL to which to connect | ||
* @param {Object} headers headers to use | ||
* @api public | ||
**/ | ||
function EventSource(url) { | ||
function EventSource(url, eventSourceInitDict) { | ||
var readyState = EventSource.CONNECTING; | ||
@@ -59,2 +64,8 @@ Object.defineProperty(this, 'readyState', { | ||
if (lastEventId) options.headers['last-event-id'] = lastEventId; | ||
if (eventSourceInitDict && eventSourceInitDict.headers && isPlainObject(eventSourceInitDict.headers)) { | ||
for (var i in eventSourceInitDict.headers) { | ||
var header = eventSourceInitDict.headers[i]; | ||
options.headers[i] = header; | ||
} | ||
} | ||
@@ -76,2 +87,7 @@ req = (isSecure ? https : http).request(options, function(res) { | ||
if (res.statusCode == 403) { | ||
_emit('error', 'Access denied'); | ||
return self.close(); | ||
} | ||
readyState = EventSource.OPEN; | ||
@@ -89,12 +105,16 @@ res.on('close', onConnectionClosed); | ||
buf = buf.slice(messages.length); | ||
messages = eventstream.parse(messages); | ||
if (!messages) return; | ||
messages.forEach(function(message) { | ||
var data = message.data.replace(/\n$/, ''); | ||
if (data == '' || (message.event != null && message.event == '')) { | ||
return; | ||
} | ||
if (message.id) lastEventId = message.id; | ||
_emit(message.event || 'message', new MessageEvent(data)); | ||
}); | ||
try { | ||
messages = eventstream.parse(messages); | ||
if (!messages) return; | ||
messages.forEach(function(message) { | ||
var data = message.data.replace(/\n$/, ''); | ||
if (data == '' || (message.event != null && message.event == '')) { | ||
return; | ||
} | ||
if (message.id) lastEventId = message.id; | ||
_emit(message.event || 'message', new MessageEvent(data)); | ||
}); | ||
} catch(e) { | ||
_emit('error', e); | ||
} | ||
}); | ||
@@ -101,0 +121,0 @@ }); |
@@ -1,2 +0,74 @@ | ||
/* Jison generated parser */ | ||
/* parser generated by jison 0.4.4 */ | ||
/* | ||
Returns a Parser object of the following structure: | ||
Parser: { | ||
yy: {} | ||
} | ||
Parser.prototype: { | ||
yy: {}, | ||
trace: function(), | ||
symbols_: {associative list: name ==> number}, | ||
terminals_: {associative list: number ==> name}, | ||
productions_: [...], | ||
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), | ||
table: [...], | ||
defaultActions: {...}, | ||
parseError: function(str, hash), | ||
parse: function(input), | ||
lexer: { | ||
EOF: 1, | ||
parseError: function(str, hash), | ||
setInput: function(input), | ||
input: function(), | ||
unput: function(str), | ||
more: function(), | ||
less: function(n), | ||
pastInput: function(), | ||
upcomingInput: function(), | ||
showPosition: function(), | ||
test_match: function(regex_match_array, rule_index), | ||
next: function(), | ||
lex: function(), | ||
begin: function(condition), | ||
popState: function(), | ||
_currentRules: function(), | ||
topState: function(), | ||
pushState: function(condition), | ||
options: { | ||
ranges: boolean (optional: true ==> token location info will include a .range[] member) | ||
flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) | ||
backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) | ||
}, | ||
performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), | ||
rules: [...], | ||
conditions: {associative list: name ==> set}, | ||
} | ||
} | ||
token location info (@$, _$, etc.): { | ||
first_line: n, | ||
last_line: n, | ||
first_column: n, | ||
last_column: n, | ||
range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) | ||
} | ||
the parseError function receives a 'hash' object with these members for lexer and parser errors: { | ||
text: (matched text) | ||
token: (the produced terminal token, if any) | ||
line: (yylineno) | ||
} | ||
while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { | ||
loc: (yylloc) | ||
expected: (string describing the set of expected tokens) | ||
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) | ||
} | ||
*/ | ||
var eventstream = (function(){ | ||
@@ -8,3 +80,4 @@ var parser = {trace: function trace() { }, | ||
productions_: [0,[3,2],[4,3],[4,2],[6,2],[6,1],[8,1],[8,1],[10,3],[10,2],[9,4],[9,3],[9,2],[12,1],[12,2],[13,1],[13,2],[14,1],[14,1],[14,1],[15,1],[15,1]], | ||
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { | ||
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { | ||
/* this == yyval */ | ||
@@ -59,6 +132,10 @@ var $0 = $$.length - 1; | ||
parseError: function parseError(str, hash) { | ||
throw new Error(str); | ||
if (hash.recoverable) { | ||
this.trace(str); | ||
} else { | ||
throw new Error(str); | ||
} | ||
}, | ||
parse: function parse(input) { | ||
var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; | ||
var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; | ||
this.lexer.setInput(input); | ||
@@ -68,9 +145,13 @@ this.lexer.yy = this.yy; | ||
this.yy.parser = this; | ||
if (typeof this.lexer.yylloc == "undefined") | ||
if (typeof this.lexer.yylloc == 'undefined') { | ||
this.lexer.yylloc = {}; | ||
} | ||
var yyloc = this.lexer.yylloc; | ||
lstack.push(yyloc); | ||
var ranges = this.lexer.options && this.lexer.options.ranges; | ||
if (typeof this.yy.parseError === "function") | ||
if (typeof this.yy.parseError === 'function') { | ||
this.parseError = this.yy.parseError; | ||
} else { | ||
this.parseError = Object.getPrototypeOf(this).parseError; | ||
} | ||
function popStack(n) { | ||
@@ -83,4 +164,4 @@ stack.length = stack.length - 2 * n; | ||
var token; | ||
token = self.lexer.lex() || 1; | ||
if (typeof token !== "number") { | ||
token = self.lexer.lex() || EOF; | ||
if (typeof token !== 'number') { | ||
token = self.symbols_[token] || token; | ||
@@ -96,3 +177,3 @@ } | ||
} else { | ||
if (symbol === null || typeof symbol == "undefined") { | ||
if (symbol === null || typeof symbol == 'undefined') { | ||
symbol = lex(); | ||
@@ -102,20 +183,25 @@ } | ||
} | ||
if (typeof action === "undefined" || !action.length || !action[0]) { | ||
var errStr = ""; | ||
if (!recovering) { | ||
if (typeof action === 'undefined' || !action.length || !action[0]) { | ||
var errStr = ''; | ||
expected = []; | ||
for (p in table[state]) | ||
if (this.terminals_[p] && p > 2) { | ||
expected.push("'" + this.terminals_[p] + "'"); | ||
for (p in table[state]) { | ||
if (this.terminals_[p] && p > TERROR) { | ||
expected.push('\'' + this.terminals_[p] + '\''); | ||
} | ||
} | ||
if (this.lexer.showPosition) { | ||
errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; | ||
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + this.lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; | ||
} else { | ||
errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); | ||
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); | ||
} | ||
this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); | ||
this.parseError(errStr, { | ||
text: this.lexer.match, | ||
token: this.terminals_[symbol] || symbol, | ||
line: this.lexer.yylineno, | ||
loc: yyloc, | ||
expected: expected | ||
}); | ||
} | ||
} | ||
if (action[0] instanceof Array && action.length > 1) { | ||
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); | ||
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); | ||
} | ||
@@ -134,4 +220,5 @@ switch (action[0]) { | ||
yyloc = this.lexer.yylloc; | ||
if (recovering > 0) | ||
if (recovering > 0) { | ||
recovering--; | ||
} | ||
} else { | ||
@@ -145,8 +232,16 @@ symbol = preErrorSymbol; | ||
yyval.$ = vstack[vstack.length - len]; | ||
yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; | ||
yyval._$ = { | ||
first_line: lstack[lstack.length - (len || 1)].first_line, | ||
last_line: lstack[lstack.length - 1].last_line, | ||
first_column: lstack[lstack.length - (len || 1)].first_column, | ||
last_column: lstack[lstack.length - 1].last_column | ||
}; | ||
if (ranges) { | ||
yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; | ||
yyval._$.range = [ | ||
lstack[lstack.length - (len || 1)].range[0], | ||
lstack[lstack.length - 1].range[1] | ||
]; | ||
} | ||
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); | ||
if (typeof r !== "undefined") { | ||
if (typeof r !== 'undefined') { | ||
return r; | ||
@@ -170,7 +265,9 @@ } | ||
return true; | ||
} | ||
}; | ||
/* Jison generated lexer */ | ||
}}; | ||
/* generated by jison-lex 0.2.0 */ | ||
var lexer = (function(){ | ||
var lexer = ({EOF:1, | ||
var lexer = { | ||
EOF:1, | ||
parseError:function parseError(str, hash) { | ||
@@ -183,13 +280,24 @@ if (this.yy.parser) { | ||
}, | ||
// resets the lexer, sets new input | ||
setInput:function (input) { | ||
this._input = input; | ||
this._more = this._less = this.done = false; | ||
this._more = this._backtrack = this.done = false; | ||
this.yylineno = this.yyleng = 0; | ||
this.yytext = this.matched = this.match = ''; | ||
this.conditionStack = ['INITIAL']; | ||
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; | ||
if (this.options.ranges) this.yylloc.range = [0,0]; | ||
this.yylloc = { | ||
first_line: 1, | ||
first_column: 0, | ||
last_line: 1, | ||
last_column: 0 | ||
}; | ||
if (this.options.ranges) { | ||
this.yylloc.range = [0,0]; | ||
} | ||
this.offset = 0; | ||
return this; | ||
}, | ||
// consumes and returns one char from the input | ||
input:function () { | ||
@@ -209,3 +317,5 @@ var ch = this._input[0]; | ||
} | ||
if (this.options.ranges) this.yylloc.range[1]++; | ||
if (this.options.ranges) { | ||
this.yylloc.range[1]++; | ||
} | ||
@@ -215,2 +325,4 @@ this._input = this._input.slice(1); | ||
}, | ||
// unshifts one char (or a string) into the input | ||
unput:function (ch) { | ||
@@ -221,19 +333,23 @@ var len = ch.length; | ||
this._input = ch + this._input; | ||
this.yytext = this.yytext.substr(0, this.yytext.length-len-1); | ||
this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); | ||
//this.yyleng -= len; | ||
this.offset -= len; | ||
var oldLines = this.match.split(/(?:\r\n?|\n)/g); | ||
this.match = this.match.substr(0, this.match.length-1); | ||
this.matched = this.matched.substr(0, this.matched.length-1); | ||
this.match = this.match.substr(0, this.match.length - 1); | ||
this.matched = this.matched.substr(0, this.matched.length - 1); | ||
if (lines.length-1) this.yylineno -= lines.length-1; | ||
if (lines.length - 1) { | ||
this.yylineno -= lines.length - 1; | ||
} | ||
var r = this.yylloc.range; | ||
this.yylloc = {first_line: this.yylloc.first_line, | ||
last_line: this.yylineno+1, | ||
first_column: this.yylloc.first_column, | ||
last_column: lines ? | ||
(lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: | ||
this.yylloc = { | ||
first_line: this.yylloc.first_line, | ||
last_line: this.yylineno + 1, | ||
first_column: this.yylloc.first_column, | ||
last_column: lines ? | ||
(lines.length === oldLines.length ? this.yylloc.first_column : 0) | ||
+ oldLines[oldLines.length - lines.length].length - lines[0].length : | ||
this.yylloc.first_column - len | ||
}; | ||
}; | ||
@@ -243,4 +359,7 @@ if (this.options.ranges) { | ||
} | ||
this.yyleng = this.yytext.length; | ||
return this; | ||
}, | ||
// When called from action, caches matched text and appends it on next action | ||
more:function () { | ||
@@ -250,5 +369,24 @@ this._more = true; | ||
}, | ||
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. | ||
reject:function () { | ||
if (this.options.backtrack_lexer) { | ||
this._backtrack = true; | ||
} else { | ||
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { | ||
text: "", | ||
token: null, | ||
line: this.yylineno | ||
}); | ||
} | ||
return this; | ||
}, | ||
// retain first n characters of the match | ||
less:function (n) { | ||
this.unput(this.match.slice(n)); | ||
}, | ||
// displays already matched input, i.e. for error messages | ||
pastInput:function () { | ||
@@ -258,2 +396,4 @@ var past = this.matched.substr(0, this.matched.length - this.match.length); | ||
}, | ||
// displays upcoming input, i.e. for error messages | ||
upcomingInput:function () { | ||
@@ -264,9 +404,91 @@ var next = this.match; | ||
} | ||
return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); | ||
return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); | ||
}, | ||
// displays the character position where the lexing error occurred, i.e. for error messages | ||
showPosition:function () { | ||
var pre = this.pastInput(); | ||
var c = new Array(pre.length + 1).join("-"); | ||
return pre + this.upcomingInput() + "\n" + c+"^"; | ||
return pre + this.upcomingInput() + "\n" + c + "^"; | ||
}, | ||
// test the lexed token: return FALSE when not a match, otherwise return token | ||
test_match:function (match, indexed_rule) { | ||
var token, | ||
lines, | ||
backup; | ||
if (this.options.backtrack_lexer) { | ||
// save context | ||
backup = { | ||
yylineno: this.yylineno, | ||
yylloc: { | ||
first_line: this.yylloc.first_line, | ||
last_line: this.last_line, | ||
first_column: this.yylloc.first_column, | ||
last_column: this.yylloc.last_column | ||
}, | ||
yytext: this.yytext, | ||
match: this.match, | ||
matches: this.matches, | ||
matched: this.matched, | ||
yyleng: this.yyleng, | ||
offset: this.offset, | ||
_more: this._more, | ||
_input: this._input, | ||
yy: this.yy, | ||
conditionStack: this.conditionStack.slice(0), | ||
done: this.done | ||
}; | ||
if (this.options.ranges) { | ||
backup.yylloc.range = this.yylloc.range.slice(0); | ||
} | ||
} | ||
lines = match[0].match(/(?:\r\n?|\n).*/g); | ||
if (lines) { | ||
this.yylineno += lines.length; | ||
} | ||
this.yylloc = { | ||
first_line: this.yylloc.last_line, | ||
last_line: this.yylineno + 1, | ||
first_column: this.yylloc.last_column, | ||
last_column: lines ? | ||
lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : | ||
this.yylloc.last_column + match[0].length | ||
}; | ||
this.yytext += match[0]; | ||
this.match += match[0]; | ||
this.matches = match; | ||
this.yyleng = this.yytext.length; | ||
if (this.options.ranges) { | ||
this.yylloc.range = [this.offset, this.offset += this.yyleng]; | ||
} | ||
this._more = false; | ||
this._backtrack = false; | ||
this._input = this._input.slice(match[0].length); | ||
this.matched += match[0]; | ||
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); | ||
if (this.done && this._input) { | ||
this.done = false; | ||
} | ||
if (token) { | ||
if (this.options.backtrack_lexer) { | ||
delete backup; | ||
} | ||
return token; | ||
} else if (this._backtrack) { | ||
// recover context | ||
for (var k in backup) { | ||
this[k] = backup[k]; | ||
} | ||
return false; // rule action called reject() implying the next rule should be tested instead. | ||
} | ||
if (this.options.backtrack_lexer) { | ||
delete backup; | ||
} | ||
return false; | ||
}, | ||
// return next match in input | ||
next:function () { | ||
@@ -276,3 +498,5 @@ if (this.done) { | ||
} | ||
if (!this._input) this.done = true; | ||
if (!this._input) { | ||
this.done = true; | ||
} | ||
@@ -282,5 +506,3 @@ var token, | ||
tempMatch, | ||
index, | ||
col, | ||
lines; | ||
index; | ||
if (!this._more) { | ||
@@ -291,3 +513,3 @@ this.yytext = ''; | ||
var rules = this._currentRules(); | ||
for (var i=0;i < rules.length; i++) { | ||
for (var i = 0; i < rules.length; i++) { | ||
tempMatch = this._input.match(this.rules[rules[i]]); | ||
@@ -297,26 +519,25 @@ if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { | ||
index = i; | ||
if (!this.options.flex) break; | ||
if (this.options.backtrack_lexer) { | ||
token = this.test_match(tempMatch, rules[i]); | ||
if (token !== false) { | ||
return token; | ||
} else if (this._backtrack) { | ||
match = false; | ||
continue; // rule action called reject() implying a rule MISmatch. | ||
} else { | ||
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) | ||
return false; | ||
} | ||
} else if (!this.options.flex) { | ||
break; | ||
} | ||
} | ||
} | ||
if (match) { | ||
lines = match[0].match(/(?:\r\n?|\n).*/g); | ||
if (lines) this.yylineno += lines.length; | ||
this.yylloc = {first_line: this.yylloc.last_line, | ||
last_line: this.yylineno+1, | ||
first_column: this.yylloc.last_column, | ||
last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; | ||
this.yytext += match[0]; | ||
this.match += match[0]; | ||
this.matches = match; | ||
this.yyleng = this.yytext.length; | ||
if (this.options.ranges) { | ||
this.yylloc.range = [this.offset, this.offset += this.yyleng]; | ||
token = this.test_match(match, rules[index]); | ||
if (token !== false) { | ||
return token; | ||
} | ||
this._more = false; | ||
this._input = this._input.slice(match[0].length); | ||
this.matched += match[0]; | ||
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); | ||
if (this.done && this._input) this.done = false; | ||
if (token) return token; | ||
else return; | ||
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) | ||
return false; | ||
} | ||
@@ -326,9 +547,14 @@ if (this._input === "") { | ||
} else { | ||
return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), | ||
{text: "", token: null, line: this.yylineno}); | ||
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { | ||
text: "", | ||
token: null, | ||
line: this.yylineno | ||
}); | ||
} | ||
}, | ||
// return next match that has a token | ||
lex:function lex() { | ||
var r = this.next(); | ||
if (typeof r !== 'undefined') { | ||
if (r) { | ||
return r; | ||
@@ -339,21 +565,50 @@ } else { | ||
}, | ||
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) | ||
begin:function begin(condition) { | ||
this.conditionStack.push(condition); | ||
}, | ||
// pop the previously active lexer condition state off the condition stack | ||
popState:function popState() { | ||
return this.conditionStack.pop(); | ||
var n = this.conditionStack.length - 1; | ||
if (n > 0) { | ||
return this.conditionStack.pop(); | ||
} else { | ||
return this.conditionStack[0]; | ||
} | ||
}, | ||
// produce the lexer rule set which is active for the currently active lexer condition state | ||
_currentRules:function _currentRules() { | ||
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; | ||
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { | ||
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; | ||
} else { | ||
return this.conditions["INITIAL"].rules; | ||
} | ||
}, | ||
topState:function () { | ||
return this.conditionStack[this.conditionStack.length-2]; | ||
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available | ||
topState:function topState(n) { | ||
n = this.conditionStack.length - 1 - Math.abs(n || 0); | ||
if (n >= 0) { | ||
return this.conditionStack[n]; | ||
} else { | ||
return "INITIAL"; | ||
} | ||
}, | ||
pushState:function begin(condition) { | ||
// alias for begin(condition) | ||
pushState:function pushState(condition) { | ||
this.begin(condition); | ||
}}); | ||
lexer.options = {}; | ||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { | ||
}, | ||
var YYSTATE=YY_START | ||
// return the number of states currently on the stack | ||
stateStackSize:function stateStackSize() { | ||
return this.conditionStack.length; | ||
}, | ||
options: {}, | ||
performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { | ||
var YYSTATE=YY_START; | ||
switch($avoiding_name_collisions) { | ||
@@ -375,28 +630,32 @@ case 0:/* skip leading byte order mark */ | ||
} | ||
}, | ||
rules: [/^(?:^\uFEFF)/,/^(?:\u0020)/,/^(?::)/,/^(?:(\u000D\u000A|\u000D|\u000A))/,/^(?:[\u0000-\u0009\u000B-\u000C\u000E-\u0019\u0021-\u0039\u003B-\uFFFFF])/,/^(?:$)/,/^(?:.)/], | ||
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6],"inclusive":true}} | ||
}; | ||
lexer.rules = [/^(?:^\uFEFF)/,/^(?:\u0020)/,/^(?::)/,/^(?:(\u000D\u000A|\u000D|\u000A))/,/^(?:[\u0000-\u0009\u000B-\u000C\u000E-\u0019\u0021-\u0039\u003B-\u10FFFF])/,/^(?:$)/,/^(?:.)/]; | ||
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6],"inclusive":true}}; | ||
return lexer;})() | ||
return lexer; | ||
})(); | ||
parser.lexer = lexer; | ||
function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; | ||
function Parser () { | ||
this.yy = {}; | ||
} | ||
Parser.prototype = parser;parser.Parser = Parser; | ||
return new Parser; | ||
})(); | ||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') { | ||
exports.parser = eventstream; | ||
exports.Parser = eventstream.Parser; | ||
exports.parse = function () { return eventstream.parse.apply(eventstream, arguments); } | ||
exports.parse = function () { return eventstream.parse.apply(eventstream, arguments); }; | ||
exports.main = function commonjsMain(args) { | ||
if (!args[1]) | ||
throw new Error('Usage: '+args[0]+' FILE'); | ||
var source, cwd; | ||
if (typeof process !== 'undefined') { | ||
source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8"); | ||
} else { | ||
source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"}); | ||
if (!args[1]) { | ||
console.log('Usage: '+args[0]+' FILE'); | ||
process.exit(1); | ||
} | ||
var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); | ||
return exports.parser.parse(source); | ||
} | ||
}; | ||
if (typeof module !== 'undefined' && require.main === module) { | ||
exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); | ||
exports.main(process.argv.slice(1)); | ||
} | ||
} |
{ | ||
"name": "eventsource", | ||
"version": "0.0.6", | ||
"description": "EventSource client for Node.js", | ||
"keywords": [ "eventsource", "http", "streaming", "sse" ], | ||
"homepage": "http://github.com/aslakhellesoy/eventsource-node", | ||
"author": "Aslak Hellesøy <aslak.hellesoy@gmail.com>", | ||
"contributors": [ | ||
"Aslak Hellesøy <aslak.hellesoy@gmail.com>", | ||
"Einar Otto Stangvik <einaros+gh@gmail.com>", | ||
"Dan North <tastapod@gmail.com>" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/aslakhellesoy/eventsource-node.git" | ||
}, | ||
"bugs": { | ||
"url": "http://github.com/aslakhellesoy/eventsource-node/issues" | ||
}, | ||
"directories": { | ||
"lib" : "./lib" | ||
}, | ||
"main": "./lib/eventsource", | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "http://github.com/aslakhellesoy/eventsource-node/raw/master/LICENSE" | ||
} | ||
], | ||
"devDependencies": { | ||
"nodeunit" : "0.6.x", | ||
"dox" : "0.1.x", | ||
"jison": "0.3.x" | ||
}, | ||
"scripts": { | ||
"test": "make run-tests" | ||
}, | ||
"engines": { | ||
"node" : ">=0.6.0" | ||
"name": "eventsource", | ||
"version": "0.0.7", | ||
"description": "W3C compliant EventSource client for Node.js", | ||
"keywords": [ | ||
"eventsource", | ||
"http", | ||
"streaming", | ||
"sse" | ||
], | ||
"homepage": "http://github.com/aslakhellesoy/eventsource-node", | ||
"author": "Aslak Hellesøy <aslak.hellesoy@gmail.com>", | ||
"contributors": [ | ||
"Aslak Hellesøy <aslak.hellesoy@gmail.com>", | ||
"Einar Otto Stangvik <einaros+gh@gmail.com>", | ||
"Dan North <tastapod@gmail.com>", | ||
"Scott Moak <scott.moak@mybrainoncode.com>", | ||
"William Wicks", | ||
"Devon Adkisson" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/aslakhellesoy/eventsource-node.git" | ||
}, | ||
"bugs": { | ||
"url": "http://github.com/aslakhellesoy/eventsource-node/issues" | ||
}, | ||
"directories": { | ||
"lib": "./lib" | ||
}, | ||
"main": "./lib/eventsource", | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "http://github.com/aslakhellesoy/eventsource-node/raw/master/LICENSE" | ||
} | ||
], | ||
"devDependencies": { | ||
"mocha": "~1.9.0", | ||
"jison": "~0.4.4" | ||
}, | ||
"scripts": { | ||
"test": "make run-tests" | ||
}, | ||
"engines": { | ||
"node": ">=0.6.0" | ||
} | ||
} |
@@ -16,3 +16,3 @@ [![Build Status](https://secure.travis-ci.org/aslakhellesoy/eventsource-node.png)](http://travis-ci.org/aslakhellesoy/eventsource-node) | ||
es = new EventSource('http://googlecodesamples.com/html5/sse/sse.php'); | ||
var es = new EventSource('http://googlecodesamples.com/html5/sse/sse.php'); | ||
es.onmessage = function(e) { | ||
@@ -31,1 +31,13 @@ console.log(e.data); | ||
See https://github.com/einaros/sse-example | ||
## Extensions to the W3C API | ||
### Setting HTTP request headers | ||
You can define custom HTTP headers for the initial HTTP request. This can be useful for e.g. sending cookies. | ||
This is done by assigning a `header` attribute to the optional `eventSourceInitDict` argument: | ||
```javascript | ||
var eventSourceInitDict = {headers: {'Cookie': 'test=test'}}; | ||
var es = new EventSource(url, eventSourceInitDict); | ||
``` |
@@ -1,5 +0,6 @@ | ||
var EventSource = require('eventsource') | ||
var EventSource = require('../lib/eventsource') | ||
, http = require('http') | ||
, https = require('https') | ||
, fs = require('fs'); | ||
, fs = require('fs') | ||
, assert = require('assert'); | ||
@@ -39,42 +40,57 @@ var port = 20000; | ||
exports['Messages'] = { | ||
setUp: function(done) { | ||
describe('Parser', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'issue-18': function(test) { | ||
createServer(["id: 1\ndata: hello world\n\n"], function(close) { | ||
it('parses multibyte characters', function(done) { | ||
createServer(["id: 1\ndata: €豆腐\n\n"], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("hello world", m.data); | ||
assert.equal("€豆腐", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}); | ||
'one one-line message in one chunk': function(test) { | ||
it('raises error when it fails to parse', function(done) { | ||
createServer(["\n\n\n\nid: 1\ndata: hello world\n\n"], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
assert.equal("hello world", m.data); | ||
es.close(); | ||
close(done); | ||
}; | ||
es.onerror = function(e) { | ||
es.close(); | ||
close(done); | ||
}; | ||
}); | ||
}); | ||
it('parses one one-line message in one chunk', function(done) { | ||
createServer(["data: Hello\n\n"], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}); | ||
'one one-line message in two chunks': function(test) { | ||
it('parses one one-line message in two chunks', function(done) { | ||
createServer(["data: Hel", "lo\n\n"], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}); | ||
'two one-line messages in one chunk': function(test) { | ||
it('parses two one-line messages in one chunk', function(done) { | ||
createServer(["data: Hello\n\n", "data: World\n\n"], function(close) { | ||
@@ -85,3 +101,3 @@ var es = new EventSource('http://localhost:' + port); | ||
function first(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.onmessage = second; | ||
@@ -91,21 +107,21 @@ } | ||
function second(m) { | ||
test.equal("World", m.data); | ||
assert.equal("World", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'one two-line message in one chunk': function(test) { | ||
it('parses one two-line message in one chunk', function(done) { | ||
createServer(["data: Hello\ndata:World\n\n"], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("Hello\nWorld", m.data); | ||
assert.equal("Hello\nWorld", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}); | ||
'really chopped up unicode data': function(test) { | ||
it('parses really chopped up unicode data', function(done) { | ||
var chopped = "data: Aslak\n\ndata: Hellesøy\n\n".split(""); | ||
@@ -117,3 +133,3 @@ createServer(chopped, function(close) { | ||
function first(m) { | ||
test.equal("Aslak", m.data); | ||
assert.equal("Aslak", m.data); | ||
es.onmessage = second; | ||
@@ -123,10 +139,10 @@ } | ||
function second(m) { | ||
test.equal("Hellesøy", m.data); | ||
assert.equal("Hellesøy", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'accepts CRLF as separator': function(test) { | ||
it('accepts CRLF as separator', function(done) { | ||
var chopped = "data: Aslak\r\n\r\ndata: Hellesøy\r\n\r\n".split(""); | ||
@@ -138,3 +154,3 @@ createServer(chopped, function(close) { | ||
function first(m) { | ||
test.equal("Aslak", m.data); | ||
assert.equal("Aslak", m.data); | ||
es.onmessage = second; | ||
@@ -144,10 +160,10 @@ } | ||
function second(m) { | ||
test.equal("Hellesøy", m.data); | ||
assert.equal("Hellesøy", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'accepts CR as separator': function(test) { | ||
it('accepts CR as separator', function(done) { | ||
var chopped = "data: Aslak\r\rdata: Hellesøy\r\r".split(""); | ||
@@ -159,3 +175,3 @@ createServer(chopped, function(close) { | ||
function first(m) { | ||
test.equal("Aslak", m.data); | ||
assert.equal("Aslak", m.data); | ||
es.onmessage = second; | ||
@@ -165,21 +181,21 @@ } | ||
function second(m) { | ||
test.equal("Hellesøy", m.data); | ||
assert.equal("Hellesøy", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'delivers message with explicit event': function(test) { | ||
it('delivers message with explicit event', function(done) { | ||
createServer(["event: greeting\ndata: Hello\n\n"], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.addEventListener('greeting', function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}); | ||
}); | ||
}, | ||
}); | ||
'comments are ignored': function(test) { | ||
it('ignores comments', function(done) { | ||
createServer(["data: Hello\n\n:nothing to see here\n\ndata: World\n\n"], function(close) { | ||
@@ -190,3 +206,3 @@ var es = new EventSource('http://localhost:' + port); | ||
function first(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.onmessage = second; | ||
@@ -196,10 +212,10 @@ } | ||
function second(m) { | ||
test.equal("World", m.data); | ||
assert.equal("World", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'empty comments are ignored': function(test) { | ||
it('ignores empty comments', function(done) { | ||
createServer(["data: Hello\n\n:\n\ndata: World\n\n"], function(close) { | ||
@@ -210,3 +226,3 @@ var es = new EventSource('http://localhost:' + port); | ||
function first(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.onmessage = second; | ||
@@ -216,10 +232,10 @@ } | ||
function second(m) { | ||
test.equal("World", m.data); | ||
assert.equal("World", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'empty data field causes entire event to be ignored': function(test) { | ||
it('causes entire event to be ignored for empty data fields', function(done) { | ||
createServer(["data:\n\ndata: Hello\n\n"], function(close) { | ||
@@ -229,14 +245,14 @@ var es = new EventSource('http://localhost:' + port); | ||
es.emit = function(event) { | ||
test.ok(event === 'message' || event === 'newListener'); | ||
assert.ok(event === 'message' || event === 'newListener'); | ||
return originalEmit.apply(this, arguments); | ||
} | ||
es.onmessage = function(m) { | ||
test.equal('Hello', m.data); | ||
assert.equal('Hello', m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}); | ||
'empty event field causes entire event to be ignored': function(test) { | ||
it('causes entire event to be ignored for empty event field', function(done) { | ||
createServer(["event:\n\ndata: Hello\n\n"], function(close) { | ||
@@ -246,21 +262,21 @@ var es = new EventSource('http://localhost:' + port); | ||
es.emit = function(event) { | ||
test.ok(event === 'message' || event === 'newListener'); | ||
assert.ok(event === 'message' || event === 'newListener'); | ||
return originalEmit.apply(this, arguments); | ||
} | ||
es.onmessage = function(m) { | ||
test.equal('Hello', m.data); | ||
assert.equal('Hello', m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}; | ||
}); | ||
}); | ||
exports['HTTP Request'] = { | ||
setUp: function(done) { | ||
describe('HTTP Request', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'passes cache-control: no-cache to server': function(test) { | ||
it('passes cache-control: no-cache to server', function(done) { | ||
var headers; | ||
@@ -271,10 +287,33 @@ createServer([], function(close) { | ||
es.onopen = function() { | ||
test.equal('no-cache', headers['cache-control']); | ||
assert.equal('no-cache', headers['cache-control']); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
}, function(req) { headers = req.headers; }); | ||
}, | ||
}); | ||
'follows http 301 redirect': function(test) { | ||
it('sets headers by user', function(done) { | ||
var url = 'http://localhost:' + port; | ||
var headers = { | ||
'User-Agent': 'test', | ||
'Cookie': 'test=test' | ||
}; | ||
createServer([], | ||
function(close) { | ||
var es = new EventSource(url, {headers: headers}); | ||
es.onopen = function() { | ||
es.close(); | ||
close(done); | ||
}; | ||
}, | ||
function(req, res) { | ||
assert.equal(req.headers['user-agent'], headers['User-Agent']); | ||
assert.equal(req.headers['cookie'], headers['Cookie']); | ||
res.writeHead(200); | ||
res.end(); | ||
return true; | ||
}); | ||
}); | ||
it('follows http 301 redirect', function(done) { | ||
var headers; | ||
@@ -288,6 +327,6 @@ var url = 'http://localhost:' + port; | ||
es.onopen = function() { | ||
test.ok(clientRequestedRedirectUrl); | ||
test.equal(url + redirectSuffix, es.url); | ||
assert.ok(clientRequestedRedirectUrl); | ||
assert.equal(url + redirectSuffix, es.url); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
@@ -307,7 +346,25 @@ }, | ||
}); | ||
}, | ||
}); | ||
'http 301 with missing location causes error event': function(test) { | ||
it('causes error event when response is 403', function(done) { | ||
var headers; | ||
var url = 'http://localhost:' + port; | ||
createServer(["id: 1\ndata: hello world\n\n"], | ||
function(close) { | ||
var es = new EventSource(url); | ||
es.onerror = function() { | ||
assert.ok(true, 'got error'); | ||
es.close(); | ||
close(done); | ||
}; | ||
}, | ||
function(req, res) { | ||
res.writeHead(403, {'Content-Type': 'text/html'}); | ||
res.end(); | ||
}); | ||
}); | ||
it('causes error event when response is 301 with missing location', function(done) { | ||
var headers; | ||
var url = 'http://localhost:' + port; | ||
createServer([], | ||
@@ -318,3 +375,3 @@ function(close) { | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
@@ -330,5 +387,5 @@ }, | ||
}); | ||
}, | ||
}); | ||
'follows http 307 redirect': function(test) { | ||
it('follows http 307 redirect', function(done) { | ||
var headers; | ||
@@ -342,6 +399,6 @@ var url = 'http://localhost:' + port; | ||
es.onopen = function() { | ||
test.ok(clientRequestedRedirectUrl); | ||
test.equal(url + redirectSuffix, es.url); | ||
assert.ok(clientRequestedRedirectUrl); | ||
assert.equal(url + redirectSuffix, es.url); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
@@ -361,5 +418,5 @@ }, | ||
}); | ||
}, | ||
}); | ||
'http 307 with missing location causes error event': function(test) { | ||
it('causes error event for 307 response with with missing location', function(done) { | ||
var headers; | ||
@@ -372,3 +429,3 @@ var url = 'http://localhost:' + port; | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
@@ -383,14 +440,13 @@ }, | ||
return true; | ||
} | ||
); | ||
} | ||
}; | ||
}); | ||
}); | ||
}); | ||
exports['HTTPS Support'] = { | ||
setUp: function(done) { | ||
describe('HTTPS Support', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'uses https for https urls': function(test) { | ||
it('uses https for https urls', function(done) { | ||
var chopped = "data: Aslak\n\ndata: Hellesøy\n\n".split(""); | ||
@@ -402,3 +458,3 @@ createServer(chopped, function(close) { | ||
function first(m) { | ||
test.equal("Aslak", m.data); | ||
assert.equal("Aslak", m.data); | ||
es.onmessage = second; | ||
@@ -408,17 +464,17 @@ } | ||
function second(m) { | ||
test.equal("Hellesøy", m.data); | ||
assert.equal("Hellesøy", m.data); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}, true); | ||
}, | ||
}; | ||
}); | ||
}); | ||
exports['Reconnect'] = { | ||
setUp: function(done) { | ||
describe('Reconnection', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'when server is down': function(test) { | ||
it('is attempted when server is down', function(done) { | ||
var es = new EventSource('http://localhost:' + port); | ||
@@ -436,9 +492,9 @@ es.reconnectInterval = 0; | ||
es.onmessage = function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
es.close(); | ||
theClose(test.done); | ||
theClose(done); | ||
}; | ||
}, | ||
}); | ||
'when server goes down after connection': function(test) { | ||
it('is attempted when server goes down after connection', function(done) { | ||
createServer(["data: Hello\n\n"], function(closeFirstServer) { | ||
@@ -449,3 +505,3 @@ var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
closeFirstServer(function() { | ||
@@ -456,5 +512,5 @@ createServer(["data: World\n\n"], function(closeSecondServer) { | ||
function second(m) { | ||
test.equal("World", m.data); | ||
assert.equal("World", m.data); | ||
es.close(); | ||
closeSecondServer(test.done); | ||
closeSecondServer(done); | ||
} | ||
@@ -465,5 +521,5 @@ }); | ||
}); | ||
}, | ||
}); | ||
'stop reconnecting when server responds with HTTP 204': function(test) { | ||
it('is not attempted when server responds with HTTP 204', function(done) { | ||
createServer(["data: Hello\n\n"], function(closeFirstServer) { | ||
@@ -474,3 +530,3 @@ var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
closeFirstServer(function() { | ||
@@ -487,3 +543,3 @@ createServer([], function(closeSecondServer) { | ||
clearInterval(ival); | ||
closeSecondServer(test.done); | ||
closeSecondServer(done); | ||
} | ||
@@ -495,5 +551,5 @@ }, 5); | ||
}); | ||
}, | ||
}); | ||
'send Last-Event-ID http header when id has previously been passed in an event from the server': function(test) { | ||
it('sends Last-Event-ID http header when it has previously been passed in an event from the server', function(done) { | ||
createServer(['id: 10\ndata: Hello\n\n'], function(closeFirstServer) { | ||
@@ -508,5 +564,5 @@ var headers = null; | ||
es.onopen = function() { | ||
test.equal('10', headers['last-event-id']); | ||
assert.equal('10', headers['last-event-id']); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
@@ -517,5 +573,5 @@ }, function(req) { headers = req.headers; }); | ||
}); | ||
}, | ||
}); | ||
'does not send Last-Event-ID http header when id has not been previously sent by the server': function(test) { | ||
it('does not send Last-Event-ID http header when it has not been previously sent by the server', function(done) { | ||
createServer(['data: Hello\n\n'], function(closeFirstServer) { | ||
@@ -530,5 +586,5 @@ var headers = null; | ||
es.onopen = function() { | ||
test.equal('undefined', typeof headers['last-event-id']); | ||
assert.equal('undefined', typeof headers['last-event-id']); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}; | ||
@@ -539,5 +595,5 @@ }, function(req) { headers = req.headers; }); | ||
}); | ||
}, | ||
}); | ||
'reconnect after http 301 redirect uses new url': function(test) { | ||
it('is attempted after http 301 redirect uses new url', function(done) { | ||
var headers; | ||
@@ -555,7 +611,7 @@ var url = 'http://localhost:' + port; | ||
es.onopen = function() { | ||
test.equal(url + redirectSuffix, es.url); | ||
assert.equal(url + redirectSuffix, es.url); | ||
es.close(); | ||
closeSecondServer(test.done); | ||
closeSecondServer(done); | ||
}; | ||
}, function(req, res) { test.equal(redirectSuffix, req.url); }); | ||
}, function(req, res) { assert.equal(redirectSuffix, req.url); }); | ||
}); | ||
@@ -573,5 +629,5 @@ }; | ||
}); | ||
}, | ||
}); | ||
'reconnect after http 307 redirect uses original url': function(test) { | ||
it('is attempted after http 307 redirect uses original url', function(done) { | ||
var headers; | ||
@@ -589,7 +645,7 @@ var url = 'http://localhost:' + port; | ||
es.onopen = function() { | ||
test.equal(url, es.url); | ||
assert.equal(url, es.url); | ||
es.close(); | ||
closeSecondServer(test.done); | ||
closeSecondServer(done); | ||
}; | ||
}, function(req, res) { test.equal('/', req.url); }); | ||
}, function(req, res) { assert.equal('/', req.url); }); | ||
}); | ||
@@ -607,38 +663,38 @@ }; | ||
}); | ||
}, | ||
}; | ||
}); | ||
}); | ||
exports['readyState'] = { | ||
setUp: function(done) { | ||
describe('readyState', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'has CONNECTING constant': function(test) { | ||
test.equal(0, EventSource.CONNECTING); | ||
test.done(); | ||
}, | ||
it('has CONNECTING constant', function(done) { | ||
assert.equal(0, EventSource.CONNECTING); | ||
done(); | ||
}); | ||
'has OPEN constant': function(test) { | ||
test.equal(1, EventSource.OPEN); | ||
test.done(); | ||
}, | ||
it('has OPEN constant', function(done) { | ||
assert.equal(1, EventSource.OPEN); | ||
done(); | ||
}); | ||
'has CLOSED constant': function(test) { | ||
test.equal(2, EventSource.CLOSED); | ||
test.done(); | ||
}, | ||
it('has CLOSED constant', function(done) { | ||
assert.equal(2, EventSource.CLOSED); | ||
done(); | ||
}); | ||
'readyState is CONNECTING before connection has been established': function(test) { | ||
it('is CONNECTING before connection has been established', function(done) { | ||
createServer([], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
test.equal(EventSource.CONNECTING, es.readyState); | ||
assert.equal(EventSource.CONNECTING, es.readyState); | ||
es.onopen = function() { | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'readyState is CONNECTING when server has closed the connection': function(test) { | ||
it('is CONNECTING when server has closed the connection', function(done) { | ||
createServer(["data: Hello\n\n"], function(closeFirstServer) { | ||
@@ -649,8 +705,8 @@ var es = new EventSource('http://localhost:' + port); | ||
es.onmessage = function(m) { | ||
test.equal("Hello", m.data); | ||
assert.equal("Hello", m.data); | ||
closeFirstServer(function() { | ||
createServer([], function(closeSecondServer) { | ||
test.equal(EventSource.CONNECTING, es.readyState); | ||
assert.equal(EventSource.CONNECTING, es.readyState); | ||
es.close(); | ||
closeSecondServer(test.done); | ||
closeSecondServer(done); | ||
}); | ||
@@ -660,16 +716,16 @@ }); | ||
}); | ||
}, | ||
}); | ||
'readyState is OPEN when connection has been established': function(test) { | ||
it('is OPEN when connection has been established', function(done) { | ||
createServer([], function(close) { | ||
var es = new EventSource('http://localhost:' + port); | ||
es.onopen = function() { | ||
test.equal(EventSource.OPEN, es.readyState); | ||
assert.equal(EventSource.OPEN, es.readyState); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'readyState is CLOSED after connection has been closed': function(test) { | ||
it('is CLOSED after connection has been closed', function(done) { | ||
createServer([], function(close) { | ||
@@ -679,16 +735,16 @@ var es = new EventSource('http://localhost:' + port); | ||
es.close(); | ||
test.equal(EventSource.CLOSED, es.readyState); | ||
close(test.done); | ||
assert.equal(EventSource.CLOSED, es.readyState); | ||
close(done); | ||
}; | ||
}); | ||
}, | ||
}; | ||
}); | ||
}); | ||
exports['Properties'] = { | ||
setUp: function(done) { | ||
describe('Properties', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'url exposes original request url': function(test) { | ||
it('url exposes original request url', function(done) { | ||
createServer([], function(close) { | ||
@@ -698,17 +754,17 @@ var url = 'http://localhost:' + port; | ||
es.onopen = function() { | ||
test.equal(url, es.url); | ||
assert.equal(url, es.url); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}; | ||
}); | ||
}); | ||
exports['Events'] = { | ||
setUp: function(done) { | ||
describe('Events', function() { | ||
beforeEach(function(done) { | ||
port++; | ||
done(); | ||
}, | ||
}); | ||
'calls onopen when connection is established': function(test) { | ||
it('calls onopen when connection is established', function(done) { | ||
createServer([], function(close) { | ||
@@ -718,8 +774,8 @@ var es = new EventSource('http://localhost:' + port); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
} | ||
}); | ||
}, | ||
}); | ||
'emits open event when connection is established': function(test) { | ||
it('emits open event when connection is established', function(done) { | ||
createServer([], function(close) { | ||
@@ -729,8 +785,8 @@ var es = new EventSource('http://localhost:' + port); | ||
es.close(); | ||
close(test.done); | ||
close(done); | ||
}); | ||
}); | ||
}, | ||
}); | ||
'does not emit error when connection is closed by client': function(test) { | ||
it('does not emit error when connection is closed by client', function(done) { | ||
createServer([], function(close) { | ||
@@ -741,3 +797,3 @@ var es = new EventSource('http://localhost:' + port); | ||
setTimeout(function() { | ||
close(test.done); | ||
close(done); | ||
}, 50); | ||
@@ -749,3 +805,3 @@ }); | ||
}); | ||
}, | ||
}; | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
65258
2
1461
42