[Spec] Should check body _source_ on redirect (#866)
* correct stream tests * bump Node.JS min to 10.17 * lint
This commit is contained in:
parent
df1a4fafa9
commit
1cb9070cce
|
@ -17,7 +17,7 @@
|
|||
],
|
||||
"types": "./@types/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=10.16"
|
||||
"node": ">=10.17"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
|
@ -60,7 +60,6 @@
|
|||
"mocha": "^7.2.0",
|
||||
"p-timeout": "^3.2.0",
|
||||
"parted": "^0.1.1",
|
||||
"resumer": "0.0.0",
|
||||
"rollup": "^2.15.0",
|
||||
"string-to-arraybuffer": "^1.0.2",
|
||||
"tsd": "^0.11.0",
|
||||
|
|
|
@ -208,6 +208,10 @@ async function consumeBody(data) {
|
|||
|
||||
if (body.readableEnded === true || body._readableState.ended === true) {
|
||||
try {
|
||||
if (accum.every(c => typeof c === 'string')) {
|
||||
return Buffer.from(accum.join(''));
|
||||
}
|
||||
|
||||
return Buffer.concat(accum, accumBytes);
|
||||
} catch (error) {
|
||||
throw new FetchError(`Could not create Buffer from response body for ${data.url}: ${error.message}`, 'system', error);
|
||||
|
|
|
@ -12,7 +12,7 @@ import zlib from 'zlib';
|
|||
import Stream, {PassThrough, pipeline as pump} from 'stream';
|
||||
import dataUriToBuffer from 'data-uri-to-buffer';
|
||||
|
||||
import {writeToStream, getTotalBytes} from './body.js';
|
||||
import {writeToStream} from './body.js';
|
||||
import Response from './response.js';
|
||||
import Headers, {fromRawHeaders} from './headers.js';
|
||||
import Request, {getNodeRequestOptions} from './request.js';
|
||||
|
@ -153,7 +153,7 @@ export default async function fetch(url, options_) {
|
|||
};
|
||||
|
||||
// HTTP-redirect fetch step 9
|
||||
if (response_.statusCode !== 303 && request.body && getTotalBytes(request) === null) {
|
||||
if (response_.statusCode !== 303 && request.body && options_.body instanceof Stream.Readable) {
|
||||
reject(new FetchError('Cannot follow redirect with body being a readable stream', 'unsupported-redirect'));
|
||||
finalize();
|
||||
return;
|
||||
|
|
37
test/main.js
37
test/main.js
|
@ -1,4 +1,5 @@
|
|||
// Test tools
|
||||
/* eslint-disable node/no-unsupported-features/node-builtins */
|
||||
import zlib from 'zlib';
|
||||
import crypto from 'crypto';
|
||||
import http from 'http';
|
||||
|
@ -10,7 +11,6 @@ import chai from 'chai';
|
|||
import chaiPromised from 'chai-as-promised';
|
||||
import chaiIterator from 'chai-iterator';
|
||||
import chaiString from 'chai-string';
|
||||
import resumer from 'resumer';
|
||||
import FormData from 'form-data';
|
||||
import stringToArrayBuffer from 'string-to-arraybuffer';
|
||||
import delay from 'delay';
|
||||
|
@ -404,7 +404,7 @@ describe('node-fetch', () => {
|
|||
const url = `${base}redirect/307`;
|
||||
const options = {
|
||||
method: 'PATCH',
|
||||
body: resumer().queue('a=1').end()
|
||||
body: stream.Readable.from('tada')
|
||||
};
|
||||
return expect(fetch(url, options)).to.eventually.be.rejected
|
||||
.and.be.an.instanceOf(FetchError)
|
||||
|
@ -1250,13 +1250,10 @@ describe('node-fetch', () => {
|
|||
});
|
||||
|
||||
it('should allow POST request with readable stream as body', () => {
|
||||
let body = resumer().queue('a=1').end();
|
||||
body = body.pipe(new stream.PassThrough());
|
||||
|
||||
const url = `${base}inspect`;
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body
|
||||
body: stream.Readable.from('a=1')
|
||||
};
|
||||
return fetch(url, options).then(res => {
|
||||
return res.json();
|
||||
|
@ -1971,27 +1968,16 @@ describe('node-fetch', () => {
|
|||
|
||||
// Issue #414
|
||||
it('should reject if attempt to accumulate body stream throws', () => {
|
||||
let body = resumer().queue('a=1').end();
|
||||
body = body.pipe(new stream.PassThrough());
|
||||
const res = new Response(body);
|
||||
const bufferConcat = Buffer.concat;
|
||||
const restoreBufferConcat = () => {
|
||||
Buffer.concat = bufferConcat;
|
||||
};
|
||||
const res = new Response(stream.Readable.from((async function * () {
|
||||
yield Buffer.from('tada');
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
yield {tada: 'yes'};
|
||||
})()));
|
||||
|
||||
Buffer.concat = () => {
|
||||
throw new Error('embedded error');
|
||||
};
|
||||
|
||||
const textPromise = res.text();
|
||||
// Ensure that `Buffer.concat` is always restored:
|
||||
textPromise.then(restoreBufferConcat, restoreBufferConcat);
|
||||
|
||||
return expect(textPromise).to.eventually.be.rejected
|
||||
return expect(res.text()).to.eventually.be.rejected
|
||||
.and.be.an.instanceOf(FetchError)
|
||||
.and.include({type: 'system'})
|
||||
.and.have.property('message').that.includes('Could not create Buffer')
|
||||
.and.that.includes('embedded error');
|
||||
.and.have.property('message').that.include('Could not create Buffer');
|
||||
});
|
||||
|
||||
it('supports supplying a lookup function to the agent', () => {
|
||||
|
@ -2053,8 +2039,7 @@ describe('node-fetch', () => {
|
|||
const url = `${base}hello`;
|
||||
const bodyContent = 'a=1';
|
||||
|
||||
let streamBody = resumer().queue(bodyContent).end();
|
||||
streamBody = streamBody.pipe(new stream.PassThrough());
|
||||
const streamBody = stream.Readable.from(bodyContent);
|
||||
const streamRequest = new Request(url, {
|
||||
method: 'POST',
|
||||
body: streamBody,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/* eslint-disable node/no-unsupported-features/node-builtins */
|
||||
|
||||
import stream from 'stream';
|
||||
import http from 'http';
|
||||
import AbortController from 'abort-controller';
|
||||
import chai from 'chai';
|
||||
import FormData from 'form-data';
|
||||
import Blob from 'fetch-blob';
|
||||
import resumer from 'resumer';
|
||||
import stringToArrayBuffer from 'string-to-arraybuffer';
|
||||
|
||||
import TestServer from './utils/server.js';
|
||||
|
@ -200,8 +201,7 @@ describe('Request', () => {
|
|||
|
||||
it('should support clone() method', () => {
|
||||
const url = base;
|
||||
let body = resumer().queue('a=1').end();
|
||||
body = body.pipe(new stream.PassThrough());
|
||||
const body = stream.Readable.from('a=1');
|
||||
const agent = new http.Agent();
|
||||
const {signal} = new AbortController();
|
||||
const request = new Request(url, {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable node/no-unsupported-features/node-builtins */
|
||||
|
||||
import * as stream from 'stream';
|
||||
import chai from 'chai';
|
||||
import resumer from 'resumer';
|
||||
import stringToArrayBuffer from 'string-to-arraybuffer';
|
||||
import Blob from 'fetch-blob';
|
||||
import {Response} from '../src/index.js';
|
||||
|
@ -54,9 +55,7 @@ describe('Response', () => {
|
|||
});
|
||||
|
||||
it('should support empty options', () => {
|
||||
let body = resumer().queue('a=1').end();
|
||||
body = body.pipe(new stream.PassThrough());
|
||||
const res = new Response(body);
|
||||
const res = new Response(stream.Readable.from('a=1'));
|
||||
return res.text().then(result => {
|
||||
expect(result).to.equal('a=1');
|
||||
});
|
||||
|
@ -107,8 +106,7 @@ describe('Response', () => {
|
|||
});
|
||||
|
||||
it('should support clone() method', () => {
|
||||
let body = resumer().queue('a=1').end();
|
||||
body = body.pipe(new stream.PassThrough());
|
||||
const body = stream.Readable.from('a=1');
|
||||
const res = new Response(body, {
|
||||
headers: {
|
||||
a: '1'
|
||||
|
@ -131,8 +129,7 @@ describe('Response', () => {
|
|||
});
|
||||
|
||||
it('should support stream as body', () => {
|
||||
let body = resumer().queue('a=1').end();
|
||||
body = body.pipe(new stream.PassThrough());
|
||||
const body = stream.Readable.from('a=1');
|
||||
const res = new Response(body);
|
||||
return res.text().then(result => {
|
||||
expect(result).to.equal('a=1');
|
||||
|
|
Loading…
Reference in New Issue