Compare commits

...

38 Commits

Author SHA1 Message Date
John Hiesey 43d1322dd6 1.7.0 2015-09-15 00:22:13 -07:00
John Hiesey f72d22b2a9 Disable IE8 tests due to intermittent failures 2015-09-14 23:37:43 -07:00
John Hiesey bde26be949 Add WebWorker test using webworkify 2015-09-14 23:25:24 -07:00
John Hiesey 8cab16f26e Change window to global for WebWorker support 2015-09-14 18:18:53 -07:00
John Hiesey 166795fc05 1.6.0 2015-09-11 21:19:23 -07:00
John Hiesey ff339bd64c Merge pull request #21 from jhiesey/browser-resolve
Add support for relative paths in urls
2015-09-11 20:40:14 -07:00
John Hiesey 5986071393 Allow newer versions of some deps 2015-09-11 20:40:00 -07:00
John Hiesey bbf1fd81f0 Test handling of relative paths in urls
This adds the test from #17.
2015-09-11 20:09:20 -07:00
John Hiesey 6b9d3d107c Drastically simplify and improve url handling
Make options handling logic match node's `http` module more
closely and let the browser handle all of the relative url
cases itself.

This has a few important advantages:
* Behavior is closer to native `http` modula
* Relative paths in urls are handled properly (fixes #16)
* Code is simpler and more obviously correct
2015-09-11 20:06:13 -07:00
John Hiesey 3fda0048d7 Minor whitespace fixes in node test 2015-09-09 20:25:14 -07:00
John Hiesey bef2b95708 Fix IPv6 addresses in requests
Fixes #18
2015-09-09 20:25:14 -07:00
John Hiesey efed69e6e2 Merge pull request #13 from regular/patch-1
Update README.md
2015-08-28 10:46:20 -07:00
Jan Bölsche caa40a0950 Update README.md
from the code it looks like if withCredentials defaults to false now.
2015-08-28 19:40:15 +02:00
John Hiesey 168dbac90c 1.5.0 2015-08-20 01:21:15 -07:00
John Hiesey a91ed0db64 Modify feature testing to avoid warnings in Chrome
Previously, testing for 'ms-stream' and 'moz-chunked-arraybuffer'
support on the xhr object caused warnings to appear in Chrome.
Since fetch will always be used instead of these when available,
short-circuit and return false when fetch is available.
2015-08-20 01:06:34 -07:00
John Hiesey da4085e33d Make content-type header correct by default
The default behavior now preserves the 'content-type' header, at
the expense of not providing pseudo-streming in Safari, generic
WebKit, and older Chrome. Applications that require streaming
and already use 'prefer-stream' mode will not be affected.

The 'prefer-fast' mode is now deprecated, as that behavior now
matches the default. The 'allow-wrong-content-type' mode is new;
it gives the same behavior as the old default in case binary
streaming is essential.

Fixes #8
2015-08-20 01:01:40 -07:00
John Hiesey 6d17b406a9 1.4.1 2015-08-07 18:18:02 -07:00
John Hiesey 1a4a89a5e4 Add test for data in request.end() 2015-08-07 18:02:33 -07:00
John Hiesey 838aaffac7 Fix passing data to request.end()
Previously this would result in an exception.
Thanks @magnuslundstedt for finding the bug!
2015-08-07 17:55:43 -07:00
John Hiesey f70ac39bf4 1.4.0 2015-08-06 22:44:10 -07:00
John Hiesey ed525a4a2d Merge pull request #11 from tjmehta/add-http-methods-from-node
Add http methods from node v0.12
2015-08-06 22:33:45 -07:00
Tejesh Mehta b162e21d92 Add http methods from node v0.12 2015-08-06 17:39:17 -07:00
John Hiesey c8c0966c63 1.3.0 2015-07-20 16:10:29 -07:00
John Hiesey efaad2a3c7 Add keywords 2015-07-20 16:07:30 -07:00
John Hiesey 9059849673 Make withCredentials default to false
This may break compatibility with code that was written for
`http-browserify`. Fixes #7
2015-07-20 16:01:24 -07:00
John Hiesey aeabb2cc70 Merge pull request #6 from cesarandreu/consistent-fetch
Fix inconsistency between XMLHttpRequest and fetch
2015-07-20 00:32:46 -07:00
Cesar Andreu 588e5874f3 Add test for cookie behavior 2015-07-19 17:50:30 -07:00
Cesar Andreu 5fc4858d6d Use same-origin instead of omit with fetch credentials
In order to have parity with XMLHttpRequest fetch credentials should use same-origin instead of omit
Setting XMLHttpRequest.withCredentials to false has no effect on same-site request
2015-07-19 17:06:28 -07:00
John Hiesey 22b3cc7acb v1.2.1 2015-07-17 00:50:31 -07:00
John Hiesey 5ffc869490 Fix readme to point to new saucelabs account 2015-07-17 00:35:03 -07:00
John Hiesey cc74bc83c8 v1.2.0 2015-07-13 18:18:13 -07:00
John Hiesey 5e81240a05 add process.nextTick for 'close' 2015-07-13 18:14:30 -07:00
John Hiesey 29a2ad2032 Add abort() test 2015-07-13 16:57:31 -07:00
John Hiesey 6b544c54a3 Fix spelling of 'destroyed' 2015-07-13 16:45:46 -07:00
John Hiesey 734974d279 Improve behavior of request.prototype.abort() and add destroy synonym 2015-07-13 16:37:04 -07:00
John Hiesey 57ce59c207 Re-add close event on response 2015-07-13 16:07:46 -07:00
John Hiesey 15181f5586 v1.1.1 2015-07-12 21:26:03 -07:00
John Hiesey 916ab55402 Hide warnings for unsafe headers 2015-07-12 21:25:08 -07:00
16 changed files with 382 additions and 86 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ browsers:
- name: safari
version: 5..latest
- name: ie
version: 8..latest
version: 9..latest
- name: opera
version: 11..latest
- name: iphone
+15 -8
View File
@@ -1,6 +1,6 @@
# stream-http [![Build Status](https://travis-ci.org/jhiesey/stream-http.svg?branch=master)](https://travis-ci.org/jhiesey/stream-http)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/jhiesey.svg)](https://saucelabs.com/u/jhiesey)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/stream-http.svg)](https://saucelabs.com/u/stream-http)
This module is an implementation of node's native `http` module for the browser.
It tries to match node's api and behavior as closely as possible, but some features
@@ -42,7 +42,7 @@ node docs for how these work.
### Extra features compared to node
* The `options.withCredentials` boolean flag, used to indicate if the browser should send
cookies or authentication information with a CORS request. Default true.
cookies or authentication information with a CORS request. Default false.
This module has to make some tradeoffs to support binary data and/or streaming. Generally,
the module can make a fairly good decision about which underlying browser features to use,
@@ -51,14 +51,21 @@ but sometimes it helps to get a little input from the user.
* The `options.mode` field passed into `http.request` or `http.get` can take on one of the
following values:
* 'default' (or any falsy value, including undefined): Try to provide partial data before
the equest completes, but not at the cost of correctness for binary data. In some cases
the implementation may be a bit slow.
the request completes, but not at the cost of correctness for binary data or correctness of
the 'content-type' response header. This mode will also avoid slower code paths whenever
possible, which is particularly useful when making large requests in a browser like Safari
that has a weaker javascript engine.
* 'allow-wrong-content-type': Provides partial data in more cases than 'default', but
at the expense of causing the 'content-type' response header to be incorrectly reported
(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
that isn't a single-byte ASCII or utf8 character) will be corrupted. Of course, this option
is only safe for text data.
* 'prefer-fast': Use an implementation that does less processing even if it means that
partial data isn't available. This is particularly useful when making large requests in
a browser like Safari that has a weaker javascript engine.
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').
* 'prefer-fast': Deprecated; now a synonym for 'default', which has the same performance
characteristics as this mode did in versions before 1.5.
### Features missing compared to node
+35 -16
View File
@@ -11,22 +11,19 @@ http.request = function (opts, cb) {
else
opts = extend(opts)
// Split opts.host into its components
var hostHostname = opts.host ? opts.host.split(':')[0] : null
var hostPort = opts.host ? parseInt(opts.host.split(':')[1], 10) : null
var protocol = opts.protocol || ''
var host = opts.hostname || opts.host
var port = opts.port
var path = opts.path || '/'
opts.method = opts.method || 'GET'
// Necessary for IPv6 addresses
if (host && host.indexOf(':') !== -1)
host = '[' + host + ']'
// This may be a relative url. The browser should always be able to interpret it correctly.
opts.url = (host ? (protocol + '//' + host) : '') + (port ? ':' + port : '') + path
opts.method = (opts.method || 'GET').toUpperCase()
opts.headers = opts.headers || {}
opts.path = opts.path || '/'
opts.protocol = opts.protocol || window.location.protocol
// If the hostname is provided, use the default port for the protocol. If
// the url is instead relative, use window.location.port
var defaultPort = (opts.hostname || hostHostname) ? (opts.protocol === 'https:' ? 443 : 80) : window.location.port
opts.hostname = opts.hostname || hostHostname || window.location.hostname
opts.port = opts.port || hostPort || defaultPort
if (opts.withCredentials === undefined)
opts.withCredentials = true
// Also valid opts.auth, opts.mode
@@ -48,8 +45,30 @@ http.Agent.defaultMaxSockets = 4
http.STATUS_CODES = statusCodes
http.METHODS = [
'CHECKOUT',
'CONNECT',
'COPY',
'DELETE',
'GET',
'HEAD',
'LOCK',
'M-SEARCH',
'MERGE',
'MKACTIVITY',
'MKCOL',
'MOVE',
'NOTIFY',
'OPTIONS',
'PATCH',
'POST',
'PROPFIND',
'PROPPATCH',
'PURGE',
'PUT',
'DELETE' // TODO: include the methods from RFC 2616 and 2518?
]
'REPORT',
'SEARCH',
'SUBSCRIBE',
'TRACE',
'UNLOCK',
'UNSUBSCRIBE'
]
+15 -8
View File
@@ -1,4 +1,4 @@
exports.fetch = isFunction(window.fetch) && isFunction(window.ReadableByteStream)
exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableByteStream)
exports.blobConstructor = false
try {
@@ -6,8 +6,10 @@ try {
exports.blobConstructor = true
} catch (e) {}
var xhr = new window.XMLHttpRequest()
xhr.open('GET', '/')
var xhr = new global.XMLHttpRequest()
// If location.host is empty, e.g. if this page/worker was loaded
// from a Blob, then use example.com to avoid an error
xhr.open('GET', global.location.host ? '/' : 'https://example.com')
function checkTypeSupport (type) {
try {
@@ -17,14 +19,19 @@ function checkTypeSupport (type) {
return false
}
var haveArrayBuffer = isFunction(window.ArrayBuffer)
var haveSlice = haveArrayBuffer && isFunction(window.ArrayBuffer.prototype.slice)
// For some strange reason, Safari 7.0 reports typeof global.ArrayBuffer === 'object'.
// Safari 7.1 appears to have fixed this bug.
var haveArrayBuffer = typeof global.ArrayBuffer !== 'undefined'
var haveSlice = haveArrayBuffer && isFunction(global.ArrayBuffer.prototype.slice)
exports.arraybuffer = haveArrayBuffer && checkTypeSupport('arraybuffer')
exports.msstream = haveSlice && checkTypeSupport('ms-stream')
exports.mozchunkedarraybuffer = haveArrayBuffer && checkTypeSupport('moz-chunked-arraybuffer')
// These next two tests unavoidably show warnings in Chrome. Since fetch will always
// be used if it's available, just return false for these to avoid the warnings.
exports.msstream = !exports.fetch && haveSlice && checkTypeSupport('ms-stream')
exports.mozchunkedarraybuffer = !exports.fetch && haveArrayBuffer &&
checkTypeSupport('moz-chunked-arraybuffer')
exports.overrideMimeType = isFunction(xhr.overrideMimeType)
exports.vbArray = isFunction(window.VBArray)
exports.vbArray = isFunction(global.VBArray)
function isFunction (value) {
return typeof value === 'function'
+62 -20
View File
@@ -1,10 +1,11 @@
// var Base64 = require('Base64')
var capability = require('./capability')
var foreach = require('foreach')
var indexOf = require('indexof')
var inherits = require('inherits')
var keys = require('object-keys')
var response = require('./response')
var stream = require('stream')
var inherits = require('inherits')
var IncomingMessage = response.IncomingMessage
var rStates = response.readyStates
@@ -30,7 +31,6 @@ var ClientRequest = module.exports = function (opts) {
stream.Writable.call(self)
self._opts = opts
self._url = opts.protocol + '//' + opts.hostname + ':' + opts.port + opts.path
self._body = []
self._headers = {}
if (opts.auth)
@@ -41,14 +41,15 @@ var ClientRequest = module.exports = function (opts) {
var preferBinary
if (opts.mode === 'prefer-streaming') {
// If streaming is a high priority but binary compatibility isn't
// If streaming is a high priority but binary compatibility and
// the accuracy of the 'content-type' header aren't
preferBinary = false
} else if (opts.mode === 'prefer-fast') {
// If binary is preferred for speed
preferBinary = true
} else if (!opts.mode || opts.mode === 'default') {
// By default, use binary if text streaming may corrupt data
} else if (opts.mode === 'allow-wrong-content-type') {
// If streaming is more important than preserving the 'content-type' header
preferBinary = !capability.overrideMimeType
} else if (!opts.mode || opts.mode === 'default' || opts.mode === 'prefer-fast') {
// Use binary if text streaming may corrupt data or the content-type header, or for speed
preferBinary = true
} else {
throw new Error('Invalid value for opts.mode')
}
@@ -63,7 +64,14 @@ inherits(ClientRequest, stream.Writable)
ClientRequest.prototype.setHeader = function (name, value) {
var self = this
self._headers[name.toLowerCase()] = {
var lowerName = name.toLowerCase()
// This check is not necessary, but it prevents warnings from browsers about setting unsafe
// headers. To be honest I'm not entirely sure hiding these warnings is a good thing, but
// http-browserify did it, so I will too.
if (indexOf(unsafeHeaders, lowerName) !== -1)
return
self._headers[lowerName] = {
name: name,
value: value
}
@@ -82,13 +90,15 @@ ClientRequest.prototype.removeHeader = function (name) {
ClientRequest.prototype._onFinish = function () {
var self = this
if (self._destroyed)
return
var opts = self._opts
var headersObj = self._headers
var body
if (opts.method === 'POST' || opts.method === 'PUT') {
if (capability.blobConstructor) {
body = new window.Blob(self._body.map(function (buffer) {
body = new global.Blob(self._body.map(function (buffer) {
return buffer.toArrayBuffer()
}), {
type: (headersObj['content-type'] || {}).value || ''
@@ -104,12 +114,12 @@ ClientRequest.prototype._onFinish = function () {
return [headersObj[name].name, headersObj[name].value]
})
window.fetch(self._url, {
global.fetch(self._opts.url, {
method: self._opts.method,
headers: headers,
body: body,
mode: 'cors',
credentials: opts.withCredentials ? 'include' : 'omit'
credentials: opts.withCredentials ? 'include' : 'same-origin'
}).then(function (response) {
self._fetchResponse = response
self._connect()
@@ -117,9 +127,9 @@ ClientRequest.prototype._onFinish = function () {
self.emit('error', reason)
})
} else {
var xhr = self._xhr = new window.XMLHttpRequest()
var xhr = self._xhr = new global.XMLHttpRequest()
try {
xhr.open(self._opts.method, self._url, true)
xhr.open(self._opts.method, self._opts.url, true)
} catch (err) {
process.nextTick(function () {
self.emit('error', err)
@@ -159,6 +169,8 @@ ClientRequest.prototype._onFinish = function () {
}
xhr.onerror = function () {
if (self._destroyed)
return
self.emit('error', new Error('XHR error'))
}
@@ -188,7 +200,7 @@ function statusValid (xhr) {
ClientRequest.prototype._onXHRProgress = function () {
var self = this
if (!statusValid(self._xhr) || self._failed)
if (!statusValid(self._xhr) || self._destroyed)
return
if (!self._response)
@@ -200,6 +212,9 @@ ClientRequest.prototype._onXHRProgress = function () {
ClientRequest.prototype._connect = function () {
var self = this
if (self._destroyed)
return
self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode)
self.emit('response', self._response)
}
@@ -211,10 +226,15 @@ ClientRequest.prototype._write = function (chunk, encoding, cb) {
cb()
}
ClientRequest.prototype.abort = function () {
ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function () {
var self = this
self._destroyed = true
if (self._response)
self._response._destroyed = true
if (self._xhr)
self._xhr.abort()
// Currently, there isn't a way to truly abort a fetch.
// If you like bikeshedding, see https://github.com/whatwg/fetch/issues/27
}
ClientRequest.prototype.end = function (data, encoding, cb) {
@@ -224,13 +244,35 @@ ClientRequest.prototype.end = function (data, encoding, cb) {
data = undefined
}
if (data)
stream.Writable.push.call(self, data, encoding)
stream.Writable.prototype.end.call(self, cb)
stream.Writable.prototype.end.call(self, data, encoding, cb)
}
ClientRequest.prototype.flushHeaders = function () {}
ClientRequest.prototype.setTimeout = function () {}
ClientRequest.prototype.setNoDelay = function () {}
ClientRequest.prototype.setSocketKeepAlive = function () {}
// Taken from http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method
var unsafeHeaders = [
'accept-charset',
'accept-encoding',
'access-control-request-headers',
'access-control-request-method',
'connection',
'content-length',
'cookie',
'cookie2',
'date',
'dnt',
'expect',
'host',
'keep-alive',
'origin',
'referer',
'te',
'trailer',
'transfer-encoding',
'upgrade',
'user-agent',
'via'
]
+13 -3
View File
@@ -1,7 +1,7 @@
var capability = require('./capability')
var foreach = require('foreach')
var stream = require('stream')
var inherits = require('inherits')
var stream = require('stream')
var rStates = exports.readyStates = {
UNSENT: 0,
@@ -21,6 +21,14 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode) {
self.trailers = {}
self.rawTrailers = []
// Fake the 'close' event, but only once 'end' fires
self.on('end', function () {
// The nextTick is necessary to prevent the 'request' module from causing an infinite loop
process.nextTick(function () {
self.emit('close')
})
})
if (mode === 'fetch') {
self._fetchResponse = response
@@ -37,6 +45,8 @@ var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode) {
var reader = response.body.getReader()
function read () {
reader.read().then(function (result) {
if (self._destroyed)
return
if (result.done) {
self.push(null)
return
@@ -97,7 +107,7 @@ IncomingMessage.prototype._onXHRProgress = function () {
break
try {
// This fails in IE8
response = new window.VBArray(xhr.responseBody).toArray()
response = new global.VBArray(xhr.responseBody).toArray()
} catch (e) {}
if (response !== null) {
self.push(new Buffer(response))
@@ -141,7 +151,7 @@ IncomingMessage.prototype._onXHRProgress = function () {
response = xhr.response
if (xhr.readyState !== rStates.LOADING)
break
var reader = new window.MSStreamReader()
var reader = new global.MSStreamReader()
reader.onprogress = function () {
if (reader.result.byteLength > self._pos) {
self.push(new Buffer(new Uint8Array(reader.result.slice(self._pos))))
+14 -4
View File
@@ -1,6 +1,6 @@
{
"name": "stream-http",
"version": "1.1.0",
"version": "1.7.0",
"description": "Streaming http in the browser",
"main": "index.js",
"repository": {
@@ -10,24 +10,34 @@
"scripts": {
"test": "npm run test-node && npm run test-browser",
"test-node": "tape test/node/*.js",
"test-browser": "zuul -- test/browser/*.js",
"test-browser": "zuul --no-coverage -- test/browser/*.js",
"test-browser-local": "zuul --local 8080 --no-coverage -- test/browser/*.js"
},
"author": "John Hiesey",
"license": "MIT",
"keywords": [
"http",
"stream",
"streaming",
"xhr",
"http-browserify"
],
"dependencies": {
"builtin-status-codes": "~1.0.0",
"builtin-status-codes": "^1.0.0",
"foreach": "^2.0.5",
"indexof": "0.0.1",
"inherits": "^2.0.1",
"object-keys": "1.0.4",
"object-keys": "^1.0.4",
"xtend": "^4.0.0"
},
"devDependencies": {
"basic-auth": "^1.0.3",
"brfs": "^1.4.0",
"cookie-parser": "^1.3.5",
"express": "^4.13.0",
"tape": "^4.0.0",
"ua-parser-js": "^0.7.7",
"webworkify": "^1.0.2",
"zuul": "^3.1.0"
}
}
+48
View File
@@ -0,0 +1,48 @@
var Buffer = require('buffer').Buffer
var fs = require('fs')
var test = require('tape')
var http = require('../..')
test('abort before response', function (t) {
var req = http.get('/basic.txt', function (res) {
t.fail('unexpected response')
})
req.abort()
t.end()
})
test('abort on response', function (t) {
var req = http.get('/basic.txt', function (res) {
req.abort()
t.end()
res.on('end', function () {
t.fail('unexpected end')
})
res.on('data', function (data) {
t.fail('unexpected data')
})
})
})
test('abort on data', function (t) {
var req = http.get('/browserify.png?copies=5', function (res) {
var firstData = true
res.on('end', function () {
t.fail('unexpected end')
})
res.on('data', function (data) {
if (firstData) {
firstData = false
req.abort()
t.end()
} else {
t.fail('unexpected data')
}
})
})
})
+5 -2
View File
@@ -26,7 +26,10 @@ for(var i = 0; i < COPIES; i++) {
}
test('binary streaming', function (t) {
http.get('/browserify.png?copies=' + COPIES, function (res) {
http.get({
path: '/browserify.png?copies=' + COPIES,
mode: 'allow-wrong-content-type'
}, function (res) {
var buffers = []
res.on('end', function () {
if (skipVerification)
@@ -50,7 +53,7 @@ test('binary streaming', function (t) {
test('large binary request without streaming', function (t) {
http.get({
path: '/browserify.png?copies=' + COPIES,
mode: 'prefer-fast',
mode: 'default',
}, function (res) {
var buffers = []
res.on('end', function () {
+25
View File
@@ -0,0 +1,25 @@
var Buffer = require('buffer').Buffer
var test = require('tape')
var http = require('../..')
test('cookie', function (t) {
var cookie = 'hello=world'
window.document.cookie = cookie
http.get({
path: '/cookie',
withCredentials: false
}, function (res) {
var buffers = []
res.on('end', function () {
t.ok(new Buffer(cookie).equals(Buffer.concat(buffers)), 'hello cookie echoed')
t.end()
})
res.on('data', function (data) {
buffers.push(data)
})
})
})
+29
View File
@@ -2,6 +2,7 @@ var Buffer = require('buffer').Buffer
var fs = require('fs')
var keys = require('object-keys')
var test = require('tape')
var UAParser = require('ua-parser-js')
var http = require('../..')
@@ -53,4 +54,32 @@ test('headers', function (t) {
buffers.push(data)
})
})
})
test('content-type response header', function (t) {
http.get('/testHeaders', function (res) {
t.equal(res.headers['content-type'], 'application/json', 'content-type preserved')
t.end()
})
})
var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser()
var browserName = browser.name
var browserVersion = browser.major
// The content-type header is broken when 'prefer-streaming' or 'allow-wrong-content-type'
// is passed in browsers that rely on xhr.overrideMimeType(), namely older chrome and newer safari
var wrongMimeType = ((browserName === 'Chrome' && browserVersion <= 42) ||
((browserName === 'Safari' || browserName === 'Mobile Safari') && browserVersion >= 6))
test('content-type response header with forced streaming', function (t) {
http.get({
path: '/testHeaders',
mode: 'prefer-streaming'
}, function (res) {
if (wrongMimeType)
t.equal(res.headers['content-type'], 'text/plain; charset=x-user-defined', 'content-type overridden')
else
t.equal(res.headers['content-type'], 'application/json', 'content-type preserved')
t.end()
})
})
+20
View File
@@ -0,0 +1,20 @@
var Buffer = require('buffer').Buffer
var http = require('../../..')
module.exports = function (self) {
self.addEventListener('message', function (ev) {
var url = ev.data
http.get(url, function (res) {
var buffers = []
res.on('end', function () {
self.postMessage(Buffer.concat(buffers).toArrayBuffer())
})
res.on('data', function (data) {
buffers.push(data)
})
})
})
}
+20
View File
@@ -25,4 +25,24 @@ test('post text', function (t) {
req.write(reference)
req.end()
})
test('post text with data in end()', function (t) {
var req = http.request({
path: '/echo',
method: 'POST'
}, function (res) {
var buffers = []
res.on('end', function () {
t.ok(reference.equals(Buffer.concat(buffers)), 'echoed contents match')
t.end()
})
res.on('data', function (data) {
buffers.push(data)
})
})
req.end(reference)
})
+32
View File
@@ -0,0 +1,32 @@
var fs = require('fs')
var test = require('tape')
var UAParser = require('ua-parser-js')
var url = require('url')
var work = require('webworkify')
var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser()
var browserName = browser.name
var browserVersion = browser.major
// Skip browsers with poor or nonexistant WebWorker support
var skip = ((browserName === 'Opera' && browserVersion <= 12) ||
(browserName === 'IE' && browserVersion <= 10) ||
(browserName === 'Safari' && browserVersion <= 5) ||
(browserName === 'WebKit' && browserVersion <= 534) || // Old mobile safari
(browserName === 'Android Browser' && browserVersion <= 4))
var reference = fs.readFileSync(__dirname + '/../server/static/browserify.png')
test('binary download in WebWorker', {
skip: skip
}, function (t) {
// We have to use a global url, since webworkify puts the worker in a Blob,
// which doesn't have a proper location
var testUrl = url.resolve(global.location.href, '/browserify.png')
var worker = work(require('./lib/webworker-worker.js'))
worker.addEventListener('message', function (ev) {
var data = new Buffer(new Uint8Array(ev.data))
t.ok(reference.equals(data), 'contents match')
t.end()
})
worker.postMessage(testUrl)
})
+41 -24
View File
@@ -1,16 +1,13 @@
// These tests are teken from http-browserify to ensure compatibility with
// that module
var test = require('tape')
var url = require('url')
global.window = {}
window.location = {
hostname: 'localhost',
port: 8081,
protocol: 'http:'
}
var location = 'http://localhost:8081/foo/123'
var noop = function() {}
window.XMLHttpRequest = function() {
global.location = url.parse(location)
global.XMLHttpRequest = function() {
this.open = noop
this.send = noop
this.withCredentials = false
@@ -21,16 +18,17 @@ delete require.cache[moduleName]
var http = require('../../')
test('Test simple url string', function(t) {
var url = { path: '/api/foo' }
var request = http.get(url, noop)
var testUrl = { path: '/api/foo' }
var request = http.get(testUrl, noop)
t.equal( request._url, 'http://localhost:8081/api/foo', 'Url should be correct')
var resolved = url.resolve(location, request._opts.url)
t.equal(resolved, 'http://localhost:8081/api/foo', 'Url should be correct')
t.end()
})
test('Test full url object', function(t) {
var url = {
var testUrl = {
host: "localhost:8081",
hostname: "localhost",
href: "http://localhost:8081/api/foo?bar=baz",
@@ -44,11 +42,11 @@ test('Test full url object', function(t) {
slashes: true
}
var request = http.get(url, noop)
var request = http.get(testUrl, noop)
t.equal( request._url, 'http://localhost:8081/api/foo?bar=baz', 'Url should be correct')
var resolved = url.resolve(location, request._opts.url)
t.equal(resolved, 'http://localhost:8081/api/foo?bar=baz', 'Url should be correct')
t.end()
})
test('Test alt protocol', function(t) {
@@ -61,37 +59,56 @@ test('Test alt protocol', function(t) {
var request = http.get(params, noop)
t.equal( request._url, 'foo://localhost:3000/bar', 'Url should be correct')
var resolved = url.resolve(location, request._opts.url)
t.equal(resolved, 'foo://localhost:3000/bar', 'Url should be correct')
t.end()
})
test('Test string as parameters', function(t) {
var url = '/api/foo'
var request = http.get(url, noop)
var testUrl = '/api/foo'
var request = http.get(testUrl, noop)
t.equal( request._url, 'http://localhost:8081/api/foo', 'Url should be correct')
var resolved = url.resolve(location, request._opts.url)
t.equal(resolved, 'http://localhost:8081/api/foo', 'Url should be correct')
t.end()
})
test('Test withCredentials param', function(t) {
var url = '/api/foo'
var request = http.get({ url: url, withCredentials: false }, noop)
t.equal( request._xhr.withCredentials, false, 'xhr.withCredentials should be false')
t.equal(request._xhr.withCredentials, false, 'xhr.withCredentials should be false')
var request = http.get({ url: url, withCredentials: true }, noop)
t.equal( request._xhr.withCredentials, true, 'xhr.withCredentials should be true')
t.equal(request._xhr.withCredentials, true, 'xhr.withCredentials should be true')
var request = http.get({ url: url }, noop)
t.equal( request._xhr.withCredentials, true, 'xhr.withCredentials should be true')
t.equal(request._xhr.withCredentials, false, 'xhr.withCredentials should be false')
t.end()
})
test('Test ipv6 address', function(t) {
var testUrl = 'http://[::1]:80/foo'
var request = http.get(testUrl, noop)
var resolved = url.resolve(location, request._opts.url)
t.equal(resolved, 'http://[::1]:80/foo', 'Url should be correct')
t.end()
})
test('Test relative path in url', function(t) {
var params = { path: './bar' }
var request = http.get(params, noop)
var resolved = url.resolve(location, request._opts.url)
t.equal(resolved, 'http://localhost:8081/foo/bar', 'Url should be correct')
t.end()
})
test('Cleanup', function (t) {
delete global.window
delete global.location
delete global.XMLHttpRequest
delete require.cache[moduleName]
t.end()
})
+7
View File
@@ -1,3 +1,4 @@
var cookieParser = require('cookie-parser')
var basicAuth = require('basic-auth')
var express = require('express')
var fs = require('fs')
@@ -46,6 +47,12 @@ app.get('/testHeaders', function (req, res) {
res.end()
})
app.get('/cookie', cookieParser(), function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('hello=' + req.cookies.hello)
res.end()
})
app.get('/auth', function (req, res) {
var user = basicAuth(req)