Skip to content

Commit b091ab5

Browse files
authored
Fix up ArrayBufferView support (node-fetch#464)
Also add more test coverage. Fixes: node-fetch#482 Closes: node-fetch#484
1 parent 287bc3b commit b091ab5

File tree

2 files changed

+94
-7
lines changed

2 files changed

+94
-7
lines changed

src/body.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ export default function Body(body, {
3939
} else if (body instanceof Blob) {
4040
// body is blob
4141
} else if (Buffer.isBuffer(body)) {
42+
// body is Buffer
43+
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
4244
// body is ArrayBuffer
43-
} else if (body instanceof ArrayBuffer) {
44-
// body is ArrayBufferView
4545
} else if (ArrayBuffer.isView(body)) {
46-
// body is array buffer view
46+
// body is ArrayBufferView
4747
} else if (body instanceof Stream) {
4848
// body is stream
4949
} else {
@@ -207,10 +207,15 @@ function consumeBody() {
207207
}
208208

209209
// body is ArrayBuffer
210-
if (this.body instanceof ArrayBuffer) {
210+
if (Object.prototype.toString.call(this.body) === '[object ArrayBuffer]') {
211211
return Body.Promise.resolve(Buffer.from(this.body));
212212
}
213213

214+
// body is ArrayBufferView
215+
if (ArrayBuffer.isView(this.body)) {
216+
return Body.Promise.resolve(Buffer.from(this.body.buffer, this.body.byteOffset, this.body.byteLength));
217+
}
218+
214219
// istanbul ignore if: should never happen
215220
if (!(this.body instanceof Stream)) {
216221
return Body.Promise.resolve(Buffer.alloc(0));
@@ -418,7 +423,7 @@ export function extractContentType(instance) {
418423
} else if (Buffer.isBuffer(body)) {
419424
// body is buffer
420425
return null;
421-
} else if (body instanceof ArrayBuffer) {
426+
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
422427
// body is ArrayBuffer
423428
return null;
424429
} else if (ArrayBuffer.isView(body)) {
@@ -462,7 +467,7 @@ export function getTotalBytes(instance) {
462467
} else if (Buffer.isBuffer(body)) {
463468
// body is buffer
464469
return body.length;
465-
} else if (body instanceof ArrayBuffer) {
470+
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
466471
// body is ArrayBuffer
467472
return body.byteLength;
468473
} else if (ArrayBuffer.isView(body)) {
@@ -510,7 +515,7 @@ export function writeToStream(dest, instance) {
510515
// body is buffer
511516
dest.write(body);
512517
dest.end()
513-
} else if (body instanceof ArrayBuffer) {
518+
} else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
514519
// body is ArrayBuffer
515520
dest.write(Buffer.from(body));
516521
dest.end()

test/test.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ const path = require('path');
1818
const stream = require('stream');
1919
const { parse: parseURL, URLSearchParams } = require('url');
2020
const { lookup } = require('dns');
21+
const vm = require('vm');
22+
23+
const {
24+
ArrayBuffer: VMArrayBuffer,
25+
Uint8Array: VMUint8Array
26+
} = vm.runInNewContext('this');
2127

2228
let convert;
2329
try { convert = require('encoding').convert; } catch(e) { }
@@ -876,6 +882,27 @@ describe('node-fetch', () => {
876882
});
877883
});
878884

885+
it('should allow POST request with ArrayBuffer body from a VM context', function() {
886+
// TODO: Node.js v4 doesn't support ArrayBuffer from other contexts, so we skip this test, drop this check once Node.js v4 support is not needed
887+
try {
888+
Buffer.from(new VMArrayBuffer());
889+
} catch (err) {
890+
this.skip();
891+
}
892+
const url = `${base}inspect`;
893+
const opts = {
894+
method: 'POST',
895+
body: new VMUint8Array(Buffer.from('Hello, world!\n')).buffer
896+
};
897+
return fetch(url, opts).then(res => res.json()).then(res => {
898+
expect(res.method).to.equal('POST');
899+
expect(res.body).to.equal('Hello, world!\n');
900+
expect(res.headers['transfer-encoding']).to.be.undefined;
901+
expect(res.headers['content-type']).to.be.undefined;
902+
expect(res.headers['content-length']).to.equal('14');
903+
});
904+
});
905+
879906
it('should allow POST request with ArrayBufferView (Uint8Array) body', function() {
880907
const url = `${base}inspect`;
881908
const opts = {
@@ -906,6 +933,27 @@ describe('node-fetch', () => {
906933
});
907934
});
908935

936+
it('should allow POST request with ArrayBufferView (Uint8Array) body from a VM context', function() {
937+
// TODO: Node.js v4 doesn't support ArrayBufferView from other contexts, so we skip this test, drop this check once Node.js v4 support is not needed
938+
try {
939+
Buffer.from(new VMArrayBuffer());
940+
} catch (err) {
941+
this.skip();
942+
}
943+
const url = `${base}inspect`;
944+
const opts = {
945+
method: 'POST',
946+
body: new VMUint8Array(Buffer.from('Hello, world!\n'))
947+
};
948+
return fetch(url, opts).then(res => res.json()).then(res => {
949+
expect(res.method).to.equal('POST');
950+
expect(res.body).to.equal('Hello, world!\n');
951+
expect(res.headers['transfer-encoding']).to.be.undefined;
952+
expect(res.headers['content-type']).to.be.undefined;
953+
expect(res.headers['content-length']).to.equal('14');
954+
});
955+
});
956+
909957
// TODO: Node.js v4 doesn't support necessary Buffer API, so we skip this test, drop this check once Node.js v4 support is not needed
910958
(Buffer.from.length === 3 ? it : it.skip)('should allow POST request with ArrayBufferView (Uint8Array, offset, length) body', function() {
911959
const url = `${base}inspect`;
@@ -1919,6 +1967,20 @@ describe('Response', function () {
19191967
});
19201968
});
19211969

1970+
it('should support Uint8Array as body', function() {
1971+
const res = new Response(new Uint8Array(stringToArrayBuffer('a=1')));
1972+
return res.text().then(result => {
1973+
expect(result).to.equal('a=1');
1974+
});
1975+
});
1976+
1977+
it('should support DataView as body', function() {
1978+
const res = new Response(new DataView(stringToArrayBuffer('a=1')));
1979+
return res.text().then(result => {
1980+
expect(result).to.equal('a=1');
1981+
});
1982+
});
1983+
19221984
it('should default to null as body', function() {
19231985
const res = new Response();
19241986
expect(res.body).to.equal(null);
@@ -2124,6 +2186,26 @@ describe('Request', function () {
21242186
expect(result).to.equal('a=1');
21252187
});
21262188
});
2189+
2190+
it('should support Uint8Array as body', function() {
2191+
const req = new Request('', {
2192+
method: 'POST',
2193+
body: new Uint8Array(stringToArrayBuffer('a=1'))
2194+
});
2195+
return req.text().then(result => {
2196+
expect(result).to.equal('a=1');
2197+
});
2198+
});
2199+
2200+
it('should support DataView as body', function() {
2201+
const req = new Request('', {
2202+
method: 'POST',
2203+
body: new DataView(stringToArrayBuffer('a=1'))
2204+
});
2205+
return req.text().then(result => {
2206+
expect(result).to.equal('a=1');
2207+
});
2208+
});
21272209
});
21282210

21292211
function streamToPromise(stream, dataHandler) {

0 commit comments

Comments
 (0)