Skip to content
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

core: Don't use global buffer #1422

Merged
merged 12 commits into from Dec 21, 2021
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -58,13 +58,14 @@
"formdata-node": "^4.2.4",
"mocha": "^9.1.3",
"p-timeout": "^5.0.0",
"stream-consumers": "^1.0.1",
"tsd": "^0.14.0",
"xo": "^0.39.1"
},
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"formdata-polyfill": "^4.0.10",
"fetch-blob": "^3.1.3"
"fetch-blob": "^3.1.3",
"formdata-polyfill": "^4.0.10"
},
"tsd": {
"cwd": "@types",
Expand Down
1 change: 1 addition & 0 deletions src/body.js
Expand Up @@ -7,6 +7,7 @@

import Stream, {PassThrough} from 'node:stream';
import {types, deprecate, promisify} from 'node:util';
import {Buffer} from 'node:buffer';

import Blob from 'fetch-blob';
import {FormData, formDataToBlob} from 'formdata-polyfill/esm.min.js';
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Expand Up @@ -10,6 +10,8 @@ import http from 'node:http';
import https from 'node:https';
import zlib from 'node:zlib';
import Stream, {PassThrough, pipeline as pump} from 'node:stream';
import {Buffer} from 'node:buffer';

import dataUriToBuffer from 'data-uri-to-buffer';

import {writeToStream, clone} from './body.js';
Expand Down
17 changes: 8 additions & 9 deletions test/external-encoding.js
Expand Up @@ -5,15 +5,14 @@ const {expect} = chai;

describe('external encoding', () => {
describe('data uri', () => {
it('should accept base64-encoded gif data uri', () => {
return fetch('data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=').then(r => {
expect(r.status).to.equal(200);
expect(r.headers.get('Content-Type')).to.equal('image/gif');

return r.buffer().then(b => {
expect(b).to.be.an.instanceOf(Buffer);
});
});
it('should accept base64-encoded gif data uri', async () => {
const b64 = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
const res = await fetch(b64);
expect(res.status).to.equal(200);
expect(res.headers.get('Content-Type')).to.equal('image/gif');
const buf = await res.arrayBuffer();
expect(buf.byteLength).to.equal(35);
expect(buf).to.be.an.instanceOf(ArrayBuffer);
});

it('should accept data uri with specified charset', async () => {
Expand Down
2 changes: 0 additions & 2 deletions test/headers.js
Expand Up @@ -178,7 +178,6 @@ describe('Headers', () => {
res.j = Number.NaN;
res.k = true;
res.l = false;
res.m = Buffer.from('test');

const h1 = new Headers(res);
h1.set('n', [1, 2]);
Expand All @@ -198,7 +197,6 @@ describe('Headers', () => {
expect(h1Raw.j).to.include('NaN');
expect(h1Raw.k).to.include('true');
expect(h1Raw.l).to.include('false');
expect(h1Raw.m).to.include('test');
expect(h1Raw.n).to.include('1,2');
expect(h1Raw.n).to.include('3,4');

Expand Down
97 changes: 26 additions & 71 deletions test/main.js
Expand Up @@ -16,6 +16,7 @@ import {FormData as FormDataNode} from 'formdata-polyfill/esm.min.js';
import delay from 'delay';
import AbortControllerMysticatea from 'abort-controller';
import abortControllerPolyfill from 'abortcontroller-polyfill/dist/abortcontroller.js';
import {text} from 'stream-consumers';

// Test subjects
import Blob from 'fetch-blob';
Expand All @@ -36,6 +37,7 @@ import TestServer from './utils/server.js';
import chaiTimeout from './utils/chai-timeout.js';

const AbortControllerPolyfill = abortControllerPolyfill.AbortController;
const encoder = new TextEncoder();

function isNodeLowerThan(version) {
return !~process.version.localeCompare(version, undefined, {numeric: true});
Expand All @@ -51,18 +53,6 @@ chai.use(chaiString);
chai.use(chaiTimeout);
const {expect} = chai;

function streamToPromise(stream, dataHandler) {
return new Promise((resolve, reject) => {
stream.on('data', (...args) => {
Promise.resolve()
.then(() => dataHandler(...args))
.catch(reject);
});
stream.on('end', resolve);
stream.on('error', reject);
});
}

describe('node-fetch', () => {
const local = new TestServer();
let base;
Expand Down Expand Up @@ -1314,25 +1304,7 @@ describe('node-fetch', () => {
});
});

it('should allow POST request with buffer body', () => {
const url = `${base}inspect`;
const options = {
method: 'POST',
body: Buffer.from('a=1', 'utf-8')
};
return fetch(url, options).then(res => {
return res.json();
}).then(res => {
expect(res.method).to.equal('POST');
expect(res.body).to.equal('a=1');
expect(res.headers['transfer-encoding']).to.be.undefined;
expect(res.headers['content-type']).to.be.undefined;
expect(res.headers['content-length']).to.equal('3');
});
});

it('should allow POST request with ArrayBuffer body', () => {
const encoder = new TextEncoder();
const url = `${base}inspect`;
const options = {
method: 'POST',
Expand All @@ -1351,7 +1323,7 @@ describe('node-fetch', () => {
const url = `${base}inspect`;
const options = {
method: 'POST',
body: new VMUint8Array(Buffer.from('Hello, world!\n')).buffer
body: new VMUint8Array(encoder.encode('Hello, world!\n')).buffer
};
return fetch(url, options).then(res => res.json()).then(res => {
expect(res.method).to.equal('POST');
Expand All @@ -1363,7 +1335,6 @@ describe('node-fetch', () => {
});

it('should allow POST request with ArrayBufferView (Uint8Array) body', () => {
const encoder = new TextEncoder();
const url = `${base}inspect`;
const options = {
method: 'POST',
Expand All @@ -1379,7 +1350,6 @@ describe('node-fetch', () => {
});

it('should allow POST request with ArrayBufferView (DataView) body', () => {
const encoder = new TextEncoder();
const url = `${base}inspect`;
const options = {
method: 'POST',
Expand All @@ -1398,7 +1368,7 @@ describe('node-fetch', () => {
const url = `${base}inspect`;
const options = {
method: 'POST',
body: new VMUint8Array(Buffer.from('Hello, world!\n'))
body: new VMUint8Array(encoder.encode('Hello, world!\n'))
};
return fetch(url, options).then(res => res.json()).then(res => {
expect(res.method).to.equal('POST');
Expand All @@ -1410,7 +1380,6 @@ describe('node-fetch', () => {
});

it('should allow POST request with ArrayBufferView (Uint8Array, offset, length) body', () => {
const encoder = new TextEncoder();
const url = `${base}inspect`;
const options = {
method: 'POST',
Expand Down Expand Up @@ -1846,39 +1815,28 @@ describe('node-fetch', () => {
});
});

it('should allow piping response body as stream', () => {
it('should allow piping response body as stream', async () => {
const url = `${base}hello`;
return fetch(url).then(res => {
expect(res.body).to.be.an.instanceof(stream.Transform);
return streamToPromise(res.body, chunk => {
if (chunk === null) {
return;
}

expect(chunk.toString()).to.equal('world');
});
});
const res = await fetch(url);
expect(res.body).to.be.an.instanceof(stream.Transform);
const body = await text(res.body);
expect(body).to.equal('world');
});

it('should allow cloning a response, and use both as stream', () => {
it('should allow cloning a response, and use both as stream', async () => {
const url = `${base}hello`;
return fetch(url).then(res => {
const r1 = res.clone();
expect(res.body).to.be.an.instanceof(stream.Transform);
expect(r1.body).to.be.an.instanceof(stream.Transform);
const dataHandler = chunk => {
if (chunk === null) {
return;
}
const res = await fetch(url);
const r1 = res.clone();
expect(res.body).to.be.an.instanceof(stream.Transform);
expect(r1.body).to.be.an.instanceof(stream.Transform);

expect(chunk.toString()).to.equal('world');
};
const [t1, t2] = await Promise.all([
text(res.body),
text(r1.body)
]);

return Promise.all([
streamToPromise(res.body, dataHandler),
streamToPromise(r1.body, dataHandler)
]);
});
expect(t1).to.equal('world');
expect(t2).to.equal('world');
});

it('should allow cloning a json response and log it as text response', () => {
Expand Down Expand Up @@ -2141,13 +2099,10 @@ describe('node-fetch', () => {
});
});

it('should support reading blob as stream', () => {
return new Response('hello')
.blob()
.then(blob => streamToPromise(stream.Readable.from(blob.stream()), data => {
const string = Buffer.from(data).toString();
expect(string).to.equal('hello');
}));
it('should support reading blob as stream', async () => {
const blob = await new Response('hello').blob();
const str = await text(blob.stream());
expect(str).to.equal('hello');
});

it('should support blob round-trip', () => {
Expand Down Expand Up @@ -2233,7 +2188,7 @@ describe('node-fetch', () => {
// Issue #414
it('should reject if attempt to accumulate body stream throws', () => {
const res = new Response(stream.Readable.from((async function * () {
yield Buffer.from('tada');
yield encoder.encode('tada');
await new Promise(resolve => {
setTimeout(resolve, 200);
});
Expand Down Expand Up @@ -2329,7 +2284,7 @@ describe('node-fetch', () => {
size: 1024
});

const bufferBody = Buffer.from(bodyContent);
const bufferBody = encoder.encode(bodyContent);
const bufferRequest = new Request(url, {
method: 'POST',
body: bufferBody,
Expand Down
2 changes: 1 addition & 1 deletion test/referrer.js
Expand Up @@ -127,7 +127,7 @@ describe('Request constructor', () => {
expect(() => {
const req = new Request('http://example.com', {referrer: 'foobar'});
expect.fail(req);
}).to.throw(TypeError, 'Invalid URL: foobar');
}).to.throw(TypeError, /Invalid URL/);
});
});

Expand Down
13 changes: 6 additions & 7 deletions test/request.js
Expand Up @@ -201,18 +201,17 @@ describe('Request', () => {
});
});

it('should support blob() method', () => {
it('should support blob() method', async () => {
const url = base;
const request = new Request(url, {
method: 'POST',
body: Buffer.from('a=1')
body: new TextEncoder().encode('a=1')
});
expect(request.url).to.equal(url);
return request.blob().then(result => {
expect(result).to.be.an.instanceOf(Blob);
expect(result.size).to.equal(3);
expect(result.type).to.equal('');
});
const blob = await request.blob();
expect(blob).to.be.an.instanceOf(Blob);
expect(blob.size).to.equal(3);
expect(blob.type).to.equal('');
});

it('should support clone() method', () => {
Expand Down
7 changes: 0 additions & 7 deletions test/response.js
Expand Up @@ -154,13 +154,6 @@ describe('Response', () => {
});
});

it('should support buffer as body', () => {
const res = new Response(Buffer.from('a=1'));
return res.text().then(result => {
expect(result).to.equal('a=1');
});
});

it('should support ArrayBuffer as body', () => {
const encoder = new TextEncoder();
const res = new Response(encoder.encode('a=1'));
Expand Down
9 changes: 0 additions & 9 deletions test/utils/read-stream.js

This file was deleted.