Compare commits

..

25 Commits

Author SHA1 Message Date
John Hiesey 80ef3ca4ed Improve test reliability and bump deps 2021-04-13 22:29:31 -07:00
John Hiesey a2ba46d0ab Also support opts.timeout 2021-04-13 21:05:59 -07:00
John Hiesey 2c44eeb142 Update readme 2021-04-13 17:12:33 -07:00
John Hiesey 2572062eae Add timeout test 2021-04-13 16:27:08 -07:00
John Hiesey 681541d968 Emit error on destroy(err) 2021-04-13 16:23:47 -07:00
John Hiesey 54f5c2caae Add ClientRequest.setTimeout 2021-04-13 14:55:08 -07:00
Feross Aboukhadijeh e84db22d08 3.1.1 2020-05-05 10:37:01 -07:00
Feross Aboukhadijeh c05cfbbae8 bump all deps 2020-05-05 09:57:13 -07:00
Feross Aboukhadijeh 0657afd6ce tape@5 2020-05-05 09:57:13 -07:00
Feross Aboukhadijeh 36f13468b4 airtap@3 2020-05-05 09:57:13 -07:00
Feross Aboukhadijeh 0e1f2f30fc Merge pull request #112 from jhiesey/unused-var 2020-05-05 09:54:37 -07:00
Feross Aboukhadijeh f20f3cc30a Merge pull request #114 from cusspvz/patch-1 2020-05-05 09:54:24 -07:00
José Moreira 8320c894b9 fix: typo for the mode prefer-streaming at the readme.md file 2019-10-30 23:20:40 +00:00
Feross Aboukhadijeh 79f7465418 Remove unused variable 2019-08-12 18:16:38 -07:00
Feross Aboukhadijeh a38d9ab491 3.1.0 2019-08-06 19:18:49 -07:00
Feross Aboukhadijeh b81de11325 airtap: test last two chrome, firefox, edge
Speeds up tests considerably

Note to @jhiesey: feel free to change this to test more browsers if you want to, but for the evergreen browsers (chrome, firefox, and soon edge) it seems fine to just test the last two versions since users shouldn't be on any other version. Up to you though :)
2019-08-06 19:18:36 -07:00
Feross Aboukhadijeh 7092c3c95f Delete package-lock.json 2019-08-06 19:02:49 -07:00
Feross Aboukhadijeh 2e66ab4b92 airtap: test android up to latest version 2019-08-06 18:31:11 -07:00
Feross Aboukhadijeh 4c264353b6 airtap: only test iphone 10.3+ (older was removed) 2019-08-06 18:30:52 -07:00
Feross Aboukhadijeh 5a834dcf16 airtap: Only test last 5 versions of chrome, firefox, edge 2019-08-06 18:30:38 -07:00
Feross Aboukhadijeh 7df5e4e076 airtap@2 2019-08-06 18:27:35 -07:00
Feross Aboukhadijeh 8346bacf94 ignore package-lock.json 2019-08-06 18:17:47 -07:00
Feross Aboukhadijeh 72bd014322 Merge pull request #103 from reggi/master
Add test folder to .npmignore
2019-08-06 18:16:12 -07:00
Thomas Reggi cb2aad2640 add yml files 2019-01-04 00:34:01 -05:00
Thomas Reggi 9d51d294ac ignore test 2019-01-04 00:32:09 -05:00
10 changed files with 112 additions and 7023 deletions
+13 -7
View File
@@ -1,22 +1,28 @@
sauce_connect: true
providers:
- airtap-sauce
browsers:
- name: chrome
version: 39..latest
version: -2..latest
- name: firefox
version: 34..latest
version: -2..latest
- name: safari
version: 8..latest
- name: MicrosoftEdge
version: 13..latest
version: -2..latest
- name: ie
version: 11
- name: iphone
version: '9.3..latest'
version: '10.3..latest'
- name: android
version: '6.0..6.0' # TODO: change this back to latest once https://github.com/airtap/browsers/issues/3 is fixed
version: '6.0..latest'
server: ./test/server/index.js
scripts:
- "/test-polyfill.js"
browserify:
- options:
dedupe: false
dedupe: false
presets:
local:
providers: airtap-manual
browsers:
- name: manual
+2 -1
View File
@@ -1,5 +1,6 @@
.airtaprc
.DS_Store
bundle.js
node_modules
npm-debug.log
.airtaprc
package-lock.json
+3
View File
@@ -0,0 +1,3 @@
.airtap.yml
.travis.yml
test/
+2 -4
View File
@@ -65,7 +65,7 @@ at the expense of causing the 'content-type' response header to be incorrectly r
(as 'text/plain; charset=x-user-defined') in some browsers, notably Safari and Chrome 42
and older. Preserves binary data whenever possible. In some cases the implementation may
also be a bit slow. This was the default in versions of this module before 1.5.
* 'prefer-stream': Provide data before the request completes even if binary data (anything
* 'prefer-streaming': Provide data before the request completes even if binary data (anything
that isn't a single-byte ASCII or UTF8 character) will be corrupted. Of course, this option
is only safe for text data. May also cause the 'content-type' response header to be
incorrectly reported (as 'text/plain; charset=x-user-defined').
@@ -84,7 +84,7 @@ option, which applies to opening the connection.
* `http.Agent` is only a stub
* The 'socket', 'connect', 'upgrade', and 'continue' events on `http.ClientRequest`.
* Any operations, including `request.setTimeout`, that operate directly on the underlying
* Any operations, other than `request.setTimeout`, that operate directly on the underlying
socket.
* Any options that are disallowed for security reasons. This includes setting or getting
certain headers.
@@ -94,8 +94,6 @@ the server.
* `message.trailers` and `message.rawTrailers` will remain empty.
* Redirects are followed silently by the browser, so it isn't possible to access the 301/302
redirect pages.
* The `timeout` event/option and `setTimeout` functions, which operate on the underlying
socket, are not available. However, see `options.requestTimeout` above.
## Example
+44 -7
View File
@@ -54,6 +54,8 @@ var ClientRequest = module.exports = function (opts) {
}
self._mode = decideMode(preferBinary, useFetch)
self._fetchTimer = null
self._socketTimeout = null
self._socketTimer = null
self.on('finish', function () {
self._onFinish()
@@ -96,6 +98,10 @@ ClientRequest.prototype._onFinish = function () {
return
var opts = self._opts
if ('timeout' in opts && opts.timeout !== 0) {
self.setTimeout(opts.timeout)
}
var headersObj = self._headers
var body = null
if (opts.method !== 'GET' && opts.method !== 'HEAD') {
@@ -120,7 +126,6 @@ ClientRequest.prototype._onFinish = function () {
if (self._mode === 'fetch') {
var signal = null
var fetchTimer = null
if (capability.abortController) {
var controller = new AbortController()
signal = controller.signal
@@ -144,9 +149,10 @@ ClientRequest.prototype._onFinish = function () {
signal: signal
}).then(function (response) {
self._fetchResponse = response
self._resetTimers(false)
self._connect()
}, function (reason) {
global.clearTimeout(self._fetchTimer)
self._resetTimers(true)
if (!self._destroyed)
self.emit('error', reason)
})
@@ -202,6 +208,7 @@ ClientRequest.prototype._onFinish = function () {
xhr.onerror = function () {
if (self._destroyed)
return
self._resetTimers(true)
self.emit('error', new Error('XHR error'))
}
@@ -233,13 +240,15 @@ function statusValid (xhr) {
ClientRequest.prototype._onXHRProgress = function () {
var self = this
self._resetTimers(false)
if (!statusValid(self._xhr) || self._destroyed)
return
if (!self._response)
self._connect()
self._response._onXHRProgress()
self._response._onXHRProgress(self._resetTimers.bind(self))
}
ClientRequest.prototype._connect = function () {
@@ -248,7 +257,7 @@ ClientRequest.prototype._connect = function () {
if (self._destroyed)
return
self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode, self._fetchTimer)
self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode, self._resetTimers.bind(self))
self._response.on('error', function(err) {
self.emit('error', err)
})
@@ -263,16 +272,35 @@ ClientRequest.prototype._write = function (chunk, encoding, cb) {
cb()
}
ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function () {
ClientRequest.prototype._resetTimers = function (done) {
var self = this
global.clearTimeout(self._socketTimer)
self._socketTimer = null
if (done) {
global.clearTimeout(self._fetchTimer)
self._fetchTimer = null
} else if (self._socketTimeout) {
self._socketTimer = global.setTimeout(function () {
self.emit('timeout')
}, self._socketTimeout)
}
}
ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function (err) {
var self = this
self._destroyed = true
global.clearTimeout(self._fetchTimer)
self._resetTimers(true)
if (self._response)
self._response._destroyed = true
if (self._xhr)
self._xhr.abort()
else if (self._fetchAbortController)
self._fetchAbortController.abort()
if (err)
self.emit('error', err)
}
ClientRequest.prototype.end = function (data, encoding, cb) {
@@ -285,8 +313,17 @@ ClientRequest.prototype.end = function (data, encoding, cb) {
stream.Writable.prototype.end.call(self, data, encoding, cb)
}
ClientRequest.prototype.setTimeout = function (timeout, cb) {
var self = this
if (cb)
self.once('timeout', cb)
self._socketTimeout = timeout
self._resetTimers(false)
}
ClientRequest.prototype.flushHeaders = function () {}
ClientRequest.prototype.setTimeout = function () {}
ClientRequest.prototype.setNoDelay = function () {}
ClientRequest.prototype.setSocketKeepAlive = function () {}
+9 -6
View File
@@ -10,7 +10,7 @@ var rStates = exports.readyStates = {
DONE: 4
}
var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, fetchTimer) {
var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, resetTimers) {
var self = this
stream.Readable.call(self)
@@ -43,6 +43,7 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, f
if (capability.writableStream) {
var writable = new WritableStream({
write: function (chunk) {
resetTimers(false)
return new Promise(function (resolve, reject) {
if (self._destroyed) {
reject()
@@ -54,7 +55,7 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, f
})
},
close: function () {
global.clearTimeout(fetchTimer)
resetTimers(true)
if (!self._destroyed)
self.push(null)
},
@@ -66,7 +67,7 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, f
try {
response.body.pipeTo(writable).catch(function (err) {
global.clearTimeout(fetchTimer)
resetTimers(true)
if (!self._destroyed)
self.emit('error', err)
})
@@ -79,15 +80,15 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode, f
reader.read().then(function (result) {
if (self._destroyed)
return
resetTimers(result.done)
if (result.done) {
global.clearTimeout(fetchTimer)
self.push(null)
return
}
self.push(Buffer.from(result.value))
read()
}).catch(function (err) {
global.clearTimeout(fetchTimer)
resetTimers(true)
if (!self._destroyed)
self.emit('error', err)
})
@@ -146,7 +147,7 @@ IncomingMessage.prototype._read = function () {
}
}
IncomingMessage.prototype._onXHRProgress = function () {
IncomingMessage.prototype._onXHRProgress = function (resetTimers) {
var self = this
var xhr = self._xhr
@@ -193,6 +194,7 @@ IncomingMessage.prototype._onXHRProgress = function () {
}
}
reader.onload = function () {
resetTimers(true)
self.push(null)
}
// reader.onerror = ??? // TODO: this
@@ -202,6 +204,7 @@ IncomingMessage.prototype._onXHRProgress = function () {
// The ms-stream case handles end separately in reader.onload()
if (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') {
resetTimers(true)
self.push(null)
}
}
-6981
View File
File diff suppressed because it is too large Load Diff
+14 -12
View File
@@ -1,6 +1,6 @@
{
"name": "stream-http",
"version": "3.0.0",
"version": "3.1.1",
"description": "Streaming http in the browser",
"main": "index.js",
"repository": {
@@ -10,8 +10,8 @@
"scripts": {
"test": "npm run test-node && ([ -n \"${TRAVIS_PULL_REQUEST}\" -a \"${TRAVIS_PULL_REQUEST}\" != 'false' ] || npm run test-browser)",
"test-node": "tape test/node/*.js",
"test-browser": "airtap --loopback airtap.local -- test/browser/*.js",
"test-browser-local": "airtap --no-instrument --local 8080 -- test/browser/*.js"
"test-browser": "airtap --concurrency 1 -- test/browser/*.js",
"test-browser-local": "airtap --preset local -- test/browser/*.js"
},
"author": "John Hiesey",
"license": "MIT",
@@ -28,18 +28,20 @@
],
"dependencies": {
"builtin-status-codes": "^3.0.0",
"inherits": "^2.0.1",
"readable-stream": "^3.0.6",
"xtend": "^4.0.0"
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
"xtend": "^4.0.2"
},
"devDependencies": {
"airtap": "^0.1.0",
"airtap": "^4.0.3",
"airtap-manual": "^1.0.0",
"airtap-sauce": "^1.1.0",
"basic-auth": "^2.0.1",
"brfs": "^2.0.1",
"cookie-parser": "^1.4.3",
"express": "^4.16.3",
"tape": "^4.9.0",
"ua-parser-js": "^0.7.18",
"brfs": "^2.0.2",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"tape": "^5.2.2",
"ua-parser-js": "^0.7.28",
"webworkify": "^1.5.0"
}
}
+24 -4
View File
@@ -4,7 +4,7 @@ var test = require('tape')
var http = require('../..')
test('timeout', function (t) {
test('requestTimeout', function (t) {
var req = http.get({
path: '/browserify.png?copies=5',
requestTimeout: 10 // ms
@@ -16,14 +16,14 @@ test('timeout', function (t) {
})
})
req.on('requestTimeout', function () {
t.pass('got timeout')
t.pass('got requestTimeout')
t.end()
})
})
// TODO: reenable this if there's a way to make it simultaneously
// fast and reliable
test.skip('no timeout after success', function (t) {
test.skip('no requestTimeout after success', function (t) {
var req = http.get({
path: '/basic.txt',
requestTimeout: 50000 // ms
@@ -38,6 +38,26 @@ test.skip('no timeout after success', function (t) {
})
})
req.on('requestTimeout', function () {
t.fail('unexpected timeout')
t.fail('unexpected requestTimeout')
})
})
test('setTimeout', function (t) {
t.plan(2)
var req = http.get({
path: '/browserify.png?copies=5'
}, function (res) {
res.on('data', function (data) {
})
res.on('end', function () {
t.fail('request completed (should have timed out)')
})
})
req.setTimeout(10, function () {
t.pass('got setTimeout callback')
})
req.on('timeout', function () {
t.pass('got timeout')
})
})
+1 -1
View File
@@ -132,6 +132,6 @@ app.use(function (req, res, next) {
app.use(express.static(path.join(__dirname, 'static')))
var port = parseInt(process.env.AIRTAP_PORT) || 8199
var port = parseInt(process.env.AIRTAP_SUPPORT_PORT) || 8199
console.log('Test server listening on port', port)
server.listen(port)