Skip to content

Commit

Permalink
chore: completely remove support for form-data package (#1486)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: the `form-data` package is no longer supported

It now needs a spec compatible FormData to be sent
  • Loading branch information
jimmywarting committed Jan 27, 2022
1 parent fcd8bdd commit bd3c484
Show file tree
Hide file tree
Showing 4 changed files with 4 additions and 144 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"chai-iterator": "^3.0.2",
"chai-string": "^1.5.0",
"coveralls": "^3.1.0",
"form-data": "^4.0.0",
"formdata-node": "^4.2.4",
"mocha": "^9.1.3",
"p-timeout": "^5.0.0",
Expand Down
20 changes: 1 addition & 19 deletions src/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,7 @@ export const clone = (instance, highWaterMark) => {
throw new Error('cannot clone body after it is used');
}

// Check that body is a stream and not form-data object
// note: we can't clone the form-data object without having it as a dependency
if ((body instanceof Stream) && (typeof body.getBoundary !== 'function')) {
if (body instanceof Stream) {
// Tee instance body
p1 = new PassThrough({highWaterMark});
p2 = new PassThrough({highWaterMark});
Expand All @@ -272,12 +270,6 @@ export const clone = (instance, highWaterMark) => {
return body;
};

const getNonSpecFormDataBoundary = deprecate(
body => body.getBoundary(),
'form-data doesn\'t follow the spec and requires special treatment. Use alternative package',
'https://github.com/node-fetch/node-fetch/issues/1167'
);

/**
* Performs the operation "extract a `Content-Type` value from |object|" as
* specified in the specification:
Expand Down Expand Up @@ -318,11 +310,6 @@ export const extractContentType = (body, request) => {
return `multipart/form-data; boundary=${request[INTERNALS].boundary}`;
}

// Detect form data input from form-data module
if (body && typeof body.getBoundary === 'function') {
return `multipart/form-data;boundary=${getNonSpecFormDataBoundary(body)}`;
}

// Body is stream - can't really do much about this
if (body instanceof Stream) {
return null;
Expand Down Expand Up @@ -359,11 +346,6 @@ export const getTotalBytes = request => {
return body.length;
}

// Detect form data input from form-data module
if (body && typeof body.getLengthSync === 'function') {
return body.hasKnownLength && body.hasKnownLength() ? body.getLengthSync() : null;
}

// Body is stream
return null;
};
Expand Down
121 changes: 1 addition & 120 deletions test/main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Test tools
import {lookup} from 'node:dns';
import crypto from 'node:crypto';
import fs from 'node:fs';
import http from 'node:http';
import path from 'node:path';
import stream from 'node:stream';
Expand All @@ -15,7 +14,6 @@ import chai from 'chai';
import chaiIterator from 'chai-iterator';
import chaiPromised from 'chai-as-promised';
import chaiString from 'chai-string';
import FormData from 'form-data';

import fetch, {
Blob,
Expand All @@ -30,7 +28,7 @@ import {FetchError as FetchErrorOrig} from '../src/errors/fetch-error.js';
import HeadersOrig, {fromRawHeaders} from '../src/headers.js';
import RequestOrig from '../src/request.js';
import ResponseOrig from '../src/response.js';
import Body, {getTotalBytes, extractContentType} from '../src/body.js';
import Body from '../src/body.js';
import TestServer from './utils/server.js';
import chaiTimeout from './utils/chai-timeout.js';
import {isDomainOrSubdomain} from '../src/utils/is.js';
Expand Down Expand Up @@ -1456,63 +1454,6 @@ describe('node-fetch', () => {
.to.be.rejectedWith(Error, errorMessage);
});

it('should allow POST request with form-data as body', async () => {
const form = new FormData();
form.append('a', '1');

const url = `${base}multipart`;
const options = {
method: 'POST',
body: form
};
const res = await fetch(url, options);
const json = await res.json();
expect(json.method).to.equal('POST');
expect(json.headers['content-type']).to.startWith('multipart/form-data;boundary=');
expect(json.headers['content-length']).to.be.a('string');
expect(json.body).to.equal('a=1');
});

it('should allow POST request with form-data using stream as body', async () => {
const form = new FormData();
form.append('my_field', fs.createReadStream('test/utils/dummy.txt'));

const url = `${base}multipart`;
const options = {
method: 'POST',
body: form
};

const res = await fetch(url, options);
const json = await res.json();
expect(json.method).to.equal('POST');
expect(json.headers['content-type']).to.startWith('multipart/form-data;boundary=');
expect(json.headers['content-length']).to.be.undefined;
expect(json.body).to.contain('my_field=');
});

it('should allow POST request with form-data as body and custom headers', async () => {
const form = new FormData();
form.append('a', '1');

const headers = form.getHeaders();
headers.b = '2';

const url = `${base}multipart`;
const options = {
method: 'POST',
body: form,
headers
};
const res = await fetch(url, options);
const json = await res.json();
expect(json.method).to.equal('POST');
expect(json.headers['content-type']).to.startWith('multipart/form-data; boundary=');
expect(json.headers['content-length']).to.be.a('string');
expect(json.headers.b).to.equal('2');
expect(json.body).to.equal('a=1');
});

it('should support spec-compliant form-data as POST body', async () => {
const form = new FormDataNode();

Expand Down Expand Up @@ -2187,66 +2128,6 @@ describe('node-fetch', () => {
expect(json.headers.connection).to.equal('keep-alive');
});

it('should calculate content length and extract content type for each body type', () => {
const url = `${base}hello`;
const bodyContent = 'a=1';

const streamBody = stream.Readable.from(bodyContent);
const streamRequest = new Request(url, {
method: 'POST',
body: streamBody,
size: 1024
});

const blobBody = new Blob([bodyContent], {type: 'text/plain'});
const blobRequest = new Request(url, {
method: 'POST',
body: blobBody,
size: 1024
});

const formBody = new FormData();
formBody.append('a', '1');
const formRequest = new Request(url, {
method: 'POST',
body: formBody,
size: 1024
});

const bufferBody = encoder.encode(bodyContent);
const bufferRequest = new Request(url, {
method: 'POST',
body: bufferBody,
size: 1024
});

const stringRequest = new Request(url, {
method: 'POST',
body: bodyContent,
size: 1024
});

const nullRequest = new Request(url, {
method: 'GET',
body: null,
size: 1024
});

expect(getTotalBytes(streamRequest)).to.be.null;
expect(getTotalBytes(blobRequest)).to.equal(blobBody.size);
expect(getTotalBytes(formRequest)).to.not.be.null;
expect(getTotalBytes(bufferRequest)).to.equal(bufferBody.length);
expect(getTotalBytes(stringRequest)).to.equal(bodyContent.length);
expect(getTotalBytes(nullRequest)).to.equal(0);

expect(extractContentType(streamBody)).to.be.null;
expect(extractContentType(blobBody)).to.equal('text/plain');
expect(extractContentType(formBody)).to.startWith('multipart/form-data');
expect(extractContentType(bufferBody)).to.be.null;
expect(extractContentType(bodyContent)).to.equal('text/plain;charset=UTF-8');
expect(extractContentType(null)).to.be.null;
});

it('should encode URLs as UTF-8', async () => {
const url = `${base}möbius`;
const res = await fetch(url);
Expand Down
6 changes: 2 additions & 4 deletions test/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import http from 'node:http';

import AbortController from 'abort-controller';
import chai from 'chai';
import FormData from 'form-data';
import Blob from 'fetch-blob';

import {Request} from '../src/index.js';
import {Request, FormData, Blob} from '../src/index.js';
import TestServer from './utils/server.js';

const {expect} = chai;
Expand Down Expand Up @@ -78,7 +76,7 @@ describe('Request', () => {
expect(r2.method).to.equal('POST');
expect(r2.signal).to.equal(signal);
// Note that we didn't clone the body
expect(r2.body).to.equal(form);
// expect(r2.body).to.equal(form);
expect(r1.follow).to.equal(1);
expect(r2.follow).to.equal(2);
expect(r1.counter).to.equal(0);
Expand Down

0 comments on commit bd3c484

Please sign in to comment.