Skip to content

Commit 432cd8a

Browse files
authored
remove encoding as a dependency, throw detailed Error if not installed (node-fetch#302)
* remove `encoding` as a dependency, throw descriptive Error if textConverted() is used without it in env * remove rollup ext dep resolution since we don't need it * switch to programmer error, rm unneeded test conditions, bump timeout for slow CI * more kill `encoding` dep PR changes keep blank "dependencies" prop in package.json so rollup's external config func doesn't seize add ext dep checks back to the rollup config no implicit var clarify test comment * [squash] alter travis cfg to test with and without `encoding`, various fix devDeps separate `encoding` tests to their own block * [squash] fixing nits * [squash] ci: full matrix of form-data versions and encoding existence and nits
1 parent 76e8ad8 commit 432cd8a

File tree

5 files changed

+144
-108
lines changed

5 files changed

+144
-108
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ node_js:
55
- "node"
66
env:
77
- FORMDATA_VERSION=1.0.0
8+
- FORMDATA_VERSION=1.0.0 ENCODING=yes
89
- FORMDATA_VERSION=2.1.0
10+
- FORMDATA_VERSION=2.1.0 ENCODING=yes
911
before_script:
1012
- 'if [ "$FORMDATA_VERSION" ]; then npm install form-data@^$FORMDATA_VERSION; fi'
13+
- 'if [ "$ENCODING" = "yes" ]; then npm install encoding; fi'
1114
before_install: npm install -g npm
1215
script: npm run coverage
1316
cache:

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,5 @@
5656
"url-search-params": "^0.9.0",
5757
"whatwg-url": "^4.0.0"
5858
},
59-
"dependencies": {
60-
"encoding": "^0.1.11"
61-
}
59+
"dependencies": { }
6260
}

src/body.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
* Body interface provides common methods for Request and Response
66
*/
77

8-
import {convert} from 'encoding';
98
import Stream, {PassThrough} from 'stream';
109
import Blob, {BUFFER} from './blob.js';
1110
import FetchError from './fetch-error.js';
1211

1312
const DISTURBED = Symbol('disturbed');
1413

14+
let convert;
15+
try { convert = require('encoding').convert; } catch(e) {}
16+
1517
/**
1618
* Body class
1719
*
@@ -231,6 +233,10 @@ function consumeBody(body) {
231233
* @return String
232234
*/
233235
function convertBody(buffer, headers) {
236+
if (typeof convert !== 'function') {
237+
throw new Error('The package `encoding` must be installed to use the textConverted() function');
238+
}
239+
234240
const ct = headers.get('content-type');
235241
let charset = 'utf-8';
236242
let res, str;

test/server.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import * as http from 'http';
22
import { parse } from 'url';
33
import * as zlib from 'zlib';
44
import * as stream from 'stream';
5-
import { convert } from 'encoding';
65
import { multipart as Multipart } from 'parted';
76

7+
let convert;
8+
try { convert = require('encoding').convert; } catch(e) {}
9+
810
export default class TestServer {
911
constructor() {
1012
this.server = http.createServer(this.router);

test/test.js

Lines changed: 130 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import * as http from 'http';
1616
import * as fs from 'fs';
1717
import * as path from 'path';
1818

19+
let convert;
20+
try { convert = require('encoding').convert; } catch(e) { }
21+
1922
chai.use(chaiPromised);
2023
chai.use(chaiIterator);
2124
chai.use(chaiString);
@@ -1090,109 +1093,6 @@ describe('node-fetch', () => {
10901093
});
10911094
});
10921095

1093-
it('should only use UTF-8 decoding with text()', function() {
1094-
url = `${base}encoding/euc-jp`;
1095-
return fetch(url).then(res => {
1096-
expect(res.status).to.equal(200);
1097-
return res.text().then(result => {
1098-
expect(result).to.equal('<?xml version="1.0" encoding="EUC-JP"?><title>\ufffd\ufffd\ufffd\u0738\ufffd</title>');
1099-
});
1100-
});
1101-
});
1102-
1103-
it('should support encoding decode, xml dtd detect', function() {
1104-
url = `${base}encoding/euc-jp`;
1105-
return fetch(url).then(res => {
1106-
expect(res.status).to.equal(200);
1107-
return res.textConverted().then(result => {
1108-
expect(result).to.equal('<?xml version="1.0" encoding="EUC-JP"?><title>日本語</title>');
1109-
});
1110-
});
1111-
});
1112-
1113-
it('should support encoding decode, content-type detect', function() {
1114-
url = `${base}encoding/shift-jis`;
1115-
return fetch(url).then(res => {
1116-
expect(res.status).to.equal(200);
1117-
return res.textConverted().then(result => {
1118-
expect(result).to.equal('<div>日本語</div>');
1119-
});
1120-
});
1121-
});
1122-
1123-
it('should support encoding decode, html5 detect', function() {
1124-
url = `${base}encoding/gbk`;
1125-
return fetch(url).then(res => {
1126-
expect(res.status).to.equal(200);
1127-
return res.textConverted().then(result => {
1128-
expect(result).to.equal('<meta charset="gbk"><div>中文</div>');
1129-
});
1130-
});
1131-
});
1132-
1133-
it('should support encoding decode, html4 detect', function() {
1134-
url = `${base}encoding/gb2312`;
1135-
return fetch(url).then(res => {
1136-
expect(res.status).to.equal(200);
1137-
return res.textConverted().then(result => {
1138-
expect(result).to.equal('<meta http-equiv="Content-Type" content="text/html; charset=gb2312"><div>中文</div>');
1139-
});
1140-
});
1141-
});
1142-
1143-
it('should default to utf8 encoding', function() {
1144-
url = `${base}encoding/utf8`;
1145-
return fetch(url).then(res => {
1146-
expect(res.status).to.equal(200);
1147-
expect(res.headers.get('content-type')).to.be.null;
1148-
return res.textConverted().then(result => {
1149-
expect(result).to.equal('中文');
1150-
});
1151-
});
1152-
});
1153-
1154-
it('should support uncommon content-type order, charset in front', function() {
1155-
url = `${base}encoding/order1`;
1156-
return fetch(url).then(res => {
1157-
expect(res.status).to.equal(200);
1158-
return res.textConverted().then(result => {
1159-
expect(result).to.equal('中文');
1160-
});
1161-
});
1162-
});
1163-
1164-
it('should support uncommon content-type order, end with qs', function() {
1165-
url = `${base}encoding/order2`;
1166-
return fetch(url).then(res => {
1167-
expect(res.status).to.equal(200);
1168-
return res.textConverted().then(result => {
1169-
expect(result).to.equal('中文');
1170-
});
1171-
});
1172-
});
1173-
1174-
it('should support chunked encoding, html4 detect', function() {
1175-
url = `${base}encoding/chunked`;
1176-
return fetch(url).then(res => {
1177-
expect(res.status).to.equal(200);
1178-
const padding = 'a'.repeat(10);
1179-
return res.textConverted().then(result => {
1180-
expect(result).to.equal(`${padding}<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" /><div>日本語</div>`);
1181-
});
1182-
});
1183-
});
1184-
1185-
it('should only do encoding detection up to 1024 bytes', function() {
1186-
url = `${base}encoding/invalid`;
1187-
return fetch(url).then(res => {
1188-
expect(res.status).to.equal(200);
1189-
const padding = 'a'.repeat(1200);
1190-
return res.textConverted().then(result => {
1191-
expect(result).to.not.equal(`${padding}中文`);
1192-
});
1193-
});
1194-
});
1195-
11961096
it('should allow piping response body as stream', function() {
11971097
url = `${base}hello`;
11981098
return fetch(url).then(res => {
@@ -1930,3 +1830,130 @@ function streamToPromise(stream, dataHandler) {
19301830
stream.on('error', reject);
19311831
});
19321832
}
1833+
1834+
describe('external encoding', () => {
1835+
const hasEncoding = typeof convert === 'function';
1836+
1837+
describe('with optional `encoding`', function() {
1838+
before(function() {
1839+
if(!hasEncoding) this.skip();
1840+
});
1841+
1842+
it('should only use UTF-8 decoding with text()', function() {
1843+
url = `${base}encoding/euc-jp`;
1844+
return fetch(url).then(res => {
1845+
expect(res.status).to.equal(200);
1846+
return res.text().then(result => {
1847+
expect(result).to.equal('<?xml version="1.0" encoding="EUC-JP"?><title>\ufffd\ufffd\ufffd\u0738\ufffd</title>');
1848+
});
1849+
});
1850+
});
1851+
1852+
it('should support encoding decode, xml dtd detect', function() {
1853+
url = `${base}encoding/euc-jp`;
1854+
return fetch(url).then(res => {
1855+
expect(res.status).to.equal(200);
1856+
return res.textConverted().then(result => {
1857+
expect(result).to.equal('<?xml version="1.0" encoding="EUC-JP"?><title>日本語</title>');
1858+
});
1859+
});
1860+
});
1861+
1862+
it('should support encoding decode, content-type detect', function() {
1863+
url = `${base}encoding/shift-jis`;
1864+
return fetch(url).then(res => {
1865+
expect(res.status).to.equal(200);
1866+
return res.textConverted().then(result => {
1867+
expect(result).to.equal('<div>日本語</div>');
1868+
});
1869+
});
1870+
});
1871+
1872+
it('should support encoding decode, html5 detect', function() {
1873+
url = `${base}encoding/gbk`;
1874+
return fetch(url).then(res => {
1875+
expect(res.status).to.equal(200);
1876+
return res.textConverted().then(result => {
1877+
expect(result).to.equal('<meta charset="gbk"><div>中文</div>');
1878+
});
1879+
});
1880+
});
1881+
1882+
it('should support encoding decode, html4 detect', function() {
1883+
url = `${base}encoding/gb2312`;
1884+
return fetch(url).then(res => {
1885+
expect(res.status).to.equal(200);
1886+
return res.textConverted().then(result => {
1887+
expect(result).to.equal('<meta http-equiv="Content-Type" content="text/html; charset=gb2312"><div>中文</div>');
1888+
});
1889+
});
1890+
});
1891+
1892+
it('should default to utf8 encoding', function() {
1893+
url = `${base}encoding/utf8`;
1894+
return fetch(url).then(res => {
1895+
expect(res.status).to.equal(200);
1896+
expect(res.headers.get('content-type')).to.be.null;
1897+
return res.textConverted().then(result => {
1898+
expect(result).to.equal('中文');
1899+
});
1900+
});
1901+
});
1902+
1903+
it('should support uncommon content-type order, charset in front', function() {
1904+
url = `${base}encoding/order1`;
1905+
return fetch(url).then(res => {
1906+
expect(res.status).to.equal(200);
1907+
return res.textConverted().then(result => {
1908+
expect(result).to.equal('中文');
1909+
});
1910+
});
1911+
});
1912+
1913+
it('should support uncommon content-type order, end with qs', function() {
1914+
url = `${base}encoding/order2`;
1915+
return fetch(url).then(res => {
1916+
expect(res.status).to.equal(200);
1917+
return res.textConverted().then(result => {
1918+
expect(result).to.equal('中文');
1919+
});
1920+
});
1921+
});
1922+
1923+
it('should support chunked encoding, html4 detect', function() {
1924+
url = `${base}encoding/chunked`;
1925+
return fetch(url).then(res => {
1926+
expect(res.status).to.equal(200);
1927+
const padding = 'a'.repeat(10);
1928+
return res.textConverted().then(result => {
1929+
expect(result).to.equal(`${padding}<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" /><div>日本語</div>`);
1930+
});
1931+
});
1932+
});
1933+
1934+
it('should only do encoding detection up to 1024 bytes', function() {
1935+
url = `${base}encoding/invalid`;
1936+
return fetch(url).then(res => {
1937+
expect(res.status).to.equal(200);
1938+
const padding = 'a'.repeat(1200);
1939+
return res.textConverted().then(result => {
1940+
expect(result).to.not.equal(`${padding}中文`);
1941+
});
1942+
});
1943+
});
1944+
});
1945+
1946+
describe('without optional `encoding`', function() {
1947+
before(function() {
1948+
if (hasEncoding) this.skip()
1949+
});
1950+
1951+
it('should throw a FetchError if res.textConverted() is called without `encoding` in require cache', () => {
1952+
url = `${base}hello`;
1953+
return fetch(url).then((res) => {
1954+
return expect(res.textConverted()).to.eventually.be.rejected
1955+
.and.have.property('message').which.includes('encoding')
1956+
});
1957+
});
1958+
});
1959+
});

0 commit comments

Comments
 (0)