-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Ensure that each request can only fail once. #28
Changes from 3 commits
291fb29
c9084f1
d762ba8
7828a7e
cdf2774
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,27 +67,27 @@ | |
/* 0 */ | ||
/***/ (function(module, exports) { | ||
|
||
var g; | ||
|
||
// This works in non-strict mode | ||
g = (function() { | ||
return this; | ||
})(); | ||
|
||
try { | ||
// This works if eval is allowed (see CSP) | ||
g = g || Function("return this")() || (1,eval)("this"); | ||
} catch(e) { | ||
// This works if the window reference is available | ||
if(typeof window === "object") | ||
g = window; | ||
} | ||
|
||
// g can still be undefined, but nothing to do about it... | ||
// We return undefined, instead of nothing here, so it's | ||
// easier to handle this case. if(!global) { ...} | ||
|
||
module.exports = g; | ||
var g; | ||
// This works in non-strict mode | ||
g = (function() { | ||
return this; | ||
})(); | ||
try { | ||
// This works if eval is allowed (see CSP) | ||
g = g || Function("return this")() || (1,eval)("this"); | ||
} catch(e) { | ||
// This works if the window reference is available | ||
if(typeof window === "object") | ||
g = window; | ||
} | ||
// g can still be undefined, but nothing to do about it... | ||
// We return undefined, instead of nothing here, so it's | ||
// easier to handle this case. if(!global) { ...} | ||
module.exports = g; | ||
|
||
|
||
/***/ }), | ||
|
@@ -4675,7 +4675,7 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, f | |
self.url = response.url | ||
self.statusCode = response.status | ||
self.statusMessage = response.statusText | ||
|
||
response.headers.forEach(function (header, key){ | ||
self.headers[key.toLowerCase()] = header | ||
self.rawHeaders.push(key, header) | ||
|
@@ -4805,7 +4805,7 @@ IncomingMessage.prototype._onXHRProgress = function () { | |
self.push(new Buffer(response)) | ||
break | ||
} | ||
// Falls through in IE8 | ||
// Falls through in IE8 | ||
case 'text': | ||
try { // This will fail when readyState = 3 in IE9. Switch mode and wait for readyState = 4 | ||
response = xhr.responseText | ||
|
@@ -7264,6 +7264,19 @@ function hasBom (buf) { | |
}) | ||
} | ||
|
||
/** | ||
* Wrap a callback to ensure it can only be called once. | ||
*/ | ||
function once(cb) { | ||
let called = false; | ||
return (...params) => { | ||
if(!called) { | ||
called = true; | ||
cb(...params); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Creates a new EventSource object | ||
* | ||
|
@@ -7289,6 +7302,7 @@ function EventSource (url, eventSourceInitDict) { | |
|
||
var self = this | ||
self.reconnectInterval = 1000 | ||
self.session = 0 | ||
|
||
var req | ||
var lastEventId = '' | ||
|
@@ -7428,12 +7442,17 @@ function EventSource (url, eventSourceInitDict) { | |
var isSecure = urlAndOptions.options.protocol === 'https:' || | ||
(urlAndOptions.url && urlAndOptions.url.startsWith('https:')) | ||
|
||
self.session = self.session + 1 | ||
|
||
// Each request should be able to fail at most once. | ||
const failOnce = once(failed); | ||
|
||
var callback = function (res) { | ||
// Handle HTTP redirects | ||
if (res.statusCode === 301 || res.statusCode === 307) { | ||
if (!res.headers.location) { | ||
// Server sent redirect response without Location header. | ||
failed({ status: res.statusCode, message: res.statusMessage }) | ||
failOnce({ status: res.statusCode, message: res.statusMessage }) | ||
return | ||
} | ||
if (res.statusCode === 307) reconnectUrl = url | ||
|
@@ -7444,7 +7463,7 @@ function EventSource (url, eventSourceInitDict) { | |
|
||
// Handle HTTP errors | ||
if (res.statusCode !== 200) { | ||
failed({ status: res.statusCode, message: res.statusMessage }) | ||
failOnce({ status: res.statusCode, message: res.statusMessage }) | ||
return | ||
} | ||
|
||
|
@@ -7456,13 +7475,13 @@ function EventSource (url, eventSourceInitDict) { | |
res.on('close', function () { | ||
res.removeAllListeners('close') | ||
res.removeAllListeners('end') | ||
failed() | ||
failOnce() | ||
}) | ||
|
||
res.on('end', function () { | ||
res.removeAllListeners('close') | ||
res.removeAllListeners('end') | ||
failed() | ||
failOnce() | ||
}) | ||
_emit(new Event('open')) | ||
|
||
|
@@ -7561,11 +7580,11 @@ function EventSource (url, eventSourceInitDict) { | |
} | ||
|
||
req.on('error', function (err) { | ||
failed({ message: err.message }) | ||
failOnce({ message: err.message }) | ||
}) | ||
|
||
req.on('timeout', function () { | ||
failed({ message: 'Read timeout, received no data in ' + config.readTimeoutMillis + | ||
failOnce({ message: 'Read timeout, received no data in ' + config.readTimeoutMillis + | ||
'ms, assuming connection is dead' }) | ||
}) | ||
|
||
|
@@ -8711,28 +8730,28 @@ module.exports = CalculateCapacity | |
/* 33 */ | ||
/***/ (function(module, exports) { | ||
|
||
module.exports = function(module) { | ||
if(!module.webpackPolyfill) { | ||
module.deprecate = function() {}; | ||
module.paths = []; | ||
// module.parent = undefined by default | ||
if(!module.children) module.children = []; | ||
Object.defineProperty(module, "loaded", { | ||
enumerable: true, | ||
get: function() { | ||
return module.l; | ||
} | ||
}); | ||
Object.defineProperty(module, "id", { | ||
enumerable: true, | ||
get: function() { | ||
return module.i; | ||
} | ||
}); | ||
module.webpackPolyfill = 1; | ||
} | ||
return module; | ||
}; | ||
module.exports = function(module) { | ||
if(!module.webpackPolyfill) { | ||
module.deprecate = function() {}; | ||
module.paths = []; | ||
// module.parent = undefined by default | ||
if(!module.children) module.children = []; | ||
Object.defineProperty(module, "loaded", { | ||
enumerable: true, | ||
get: function() { | ||
return module.l; | ||
} | ||
}); | ||
Object.defineProperty(module, "id", { | ||
enumerable: true, | ||
get: function() { | ||
return module.i; | ||
} | ||
}); | ||
module.webpackPolyfill = 1; | ||
} | ||
return module; | ||
}; | ||
|
||
|
||
/***/ }), | ||
|
@@ -12056,4 +12075,4 @@ module.exports = function isBuffer(arg) { | |
} | ||
|
||
/***/ }) | ||
/******/ ]); | ||
/******/ ]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. newline There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if it was manually edited before, but it generated this way. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,19 @@ function hasBom (buf) { | |
}) | ||
} | ||
|
||
/** | ||
* Wrap a callback to ensure it can only be called once. | ||
*/ | ||
function once(cb) { | ||
let called = false | ||
return (...params) => { | ||
if(!called) { | ||
called = true | ||
cb(...params) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a logger util in this library? It's helpful to see logs when something is ignored. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is not. |
||
} | ||
} | ||
|
||
/** | ||
* Creates a new EventSource object | ||
* | ||
|
@@ -52,6 +65,7 @@ function EventSource (url, eventSourceInitDict) { | |
|
||
var self = this | ||
self.reconnectInterval = 1000 | ||
self.session = 0 | ||
|
||
var req | ||
var lastEventId = '' | ||
|
@@ -186,17 +200,27 @@ function EventSource (url, eventSourceInitDict) { | |
}, delay) | ||
} | ||
|
||
function destroyRequest() { | ||
if (req.destroy) req.destroy() | ||
if (req.xhr && req.xhr.abort) req.xhr.abort() | ||
} | ||
|
||
function connect () { | ||
var urlAndOptions = makeRequestUrlAndOptions() | ||
var isSecure = urlAndOptions.options.protocol === 'https:' || | ||
(urlAndOptions.url && urlAndOptions.url.startsWith('https:')) | ||
|
||
self.session = self.session + 1 | ||
|
||
// Each request should be able to fail at most once. | ||
const failOnce = once(failed) | ||
|
||
var callback = function (res) { | ||
// Handle HTTP redirects | ||
if (res.statusCode === 301 || res.statusCode === 307) { | ||
if (!res.headers.location) { | ||
// Server sent redirect response without Location header. | ||
failed({ status: res.statusCode, message: res.statusMessage }) | ||
failOnce({ status: res.statusCode, message: res.statusMessage }) | ||
return | ||
} | ||
if (res.statusCode === 307) reconnectUrl = url | ||
|
@@ -207,7 +231,7 @@ function EventSource (url, eventSourceInitDict) { | |
|
||
// Handle HTTP errors | ||
if (res.statusCode !== 200) { | ||
failed({ status: res.statusCode, message: res.statusMessage }) | ||
failOnce({ status: res.statusCode, message: res.statusMessage }) | ||
return | ||
} | ||
|
||
|
@@ -219,13 +243,13 @@ function EventSource (url, eventSourceInitDict) { | |
res.on('close', function () { | ||
res.removeAllListeners('close') | ||
res.removeAllListeners('end') | ||
failed() | ||
failOnce() | ||
}) | ||
|
||
res.on('end', function () { | ||
res.removeAllListeners('close') | ||
res.removeAllListeners('end') | ||
failed() | ||
failOnce() | ||
}) | ||
_emit(new Event('open')) | ||
|
||
|
@@ -324,12 +348,14 @@ function EventSource (url, eventSourceInitDict) { | |
} | ||
|
||
req.on('error', function (err) { | ||
failed({ message: err.message }) | ||
failOnce({ message: err.message }) | ||
}) | ||
|
||
req.on('timeout', function () { | ||
failed({ message: 'Read timeout, received no data in ' + config.readTimeoutMillis + | ||
failOnce({ message: 'Read timeout, received no data in ' + config.readTimeoutMillis + | ||
'ms, assuming connection is dead' }) | ||
// Timeout doesn't mean that the request is cancelled, just that it has elapsed the timeout. | ||
destroyRequest() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Being more careful about destroying requests will help to ensure applications are not held open by the event source. |
||
}) | ||
|
||
if (req.setNoDelay) req.setNoDelay(true) | ||
|
@@ -347,8 +373,9 @@ function EventSource (url, eventSourceInitDict) { | |
this._close = function () { | ||
if (readyState === EventSource.CLOSED) return | ||
readyState = EventSource.CLOSED | ||
if (req.abort) req.abort() | ||
if (req.xhr && req.xhr.abort) req.xhr.abort() | ||
|
||
destroyRequest() | ||
|
||
_emit(new Event('closed')) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this just formatting or was there a change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is auto-generated based on the other files. I am not sure the cause of the diff here. It looks like most of the formatting is even the same.