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

fix: handle errors from the request body stream #1392

Merged
merged 3 commits into from Nov 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Expand Up @@ -4,6 +4,9 @@ All notable changes will be recorded here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
* fix: handle errors from the request body stream by @mdmitry01 in https://github.com/node-fetch/node-fetch/pull/1392

## 3.1.0

## What's Changed
Expand Down
9 changes: 5 additions & 4 deletions src/body.js
Expand Up @@ -6,7 +6,7 @@
*/

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

import Blob from 'fetch-blob';
import {FormData, formDataToBlob} from 'formdata-polyfill/esm.min.js';
Expand All @@ -15,6 +15,7 @@ import {FetchError} from './errors/fetch-error.js';
import {FetchBaseError} from './errors/base.js';
import {isBlob, isURLSearchParameters} from './utils/is.js';

const pipeline = promisify(Stream.pipeline);
const INTERNALS = Symbol('Body internals');

/**
Expand Down Expand Up @@ -379,14 +380,14 @@ export const getTotalBytes = request => {
*
* @param {Stream.Writable} dest The stream to write to.
* @param obj.body Body object from the Body instance.
* @returns {void}
* @returns {Promise<void>}
*/
export const writeToStream = (dest, {body}) => {
export const writeToStream = async (dest, {body}) => {
if (body === null) {
// Body is null
dest.end();
} else {
// Body is stream
body.pipe(dest);
await pipeline(body, dest);
}
};
3 changes: 2 additions & 1 deletion src/index.js
Expand Up @@ -291,7 +291,8 @@ export default async function fetch(url, options_) {
resolve(response);
});

writeToStream(request_, request);
// eslint-disable-next-line promise/prefer-await-to-then
writeToStream(request_, request).catch(reject);
LinusU marked this conversation as resolved.
Show resolved Hide resolved
});
}

Expand Down
15 changes: 15 additions & 0 deletions test/main.js
Expand Up @@ -1456,6 +1456,21 @@ describe('node-fetch', () => {
});
});

it('should reject if the request body stream emits an error', () => {
const url = `${base}inspect`;
const requestBody = new stream.PassThrough();
const options = {
method: 'POST',
body: requestBody
};
const errorMessage = 'request body stream error';
setImmediate(() => {
requestBody.emit('error', new Error(errorMessage));
});
return expect(fetch(url, options))
.to.be.rejectedWith(Error, errorMessage);
});

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