forwardemail / forwardemail/superagent

Support posting multipart/form-data following a redirect

Open
#1,607 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
JavaScript
Stars
16.6k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

When a redirect response (307 or 308) is received for a request with multipart/form-data, `superagent` does not post the formData when following the redirect as the formData object is deleted to prevent request hanging by this PR #848. But this prevents the formData from being posted. As a workaround we have created a plugin to save the formdata in memory and replay it when following a redirect. I'm not sure if this is the best way so can this issue be fixed in the library itself?

```js
export default (formDataMap = new Map()) => request => {
const _originalField = request.field;
const _originalAttach = request.attach;

request.field = (name, value, options) => {
const formData = map.get(name) || [];

formData.push({value, options, isFile: false});

return _originalField.call(request, name, value, options);
};

request.attach = (name, value, options) => {
const formData = map.get(name) || [];

formData.push({value, options, isFile: true});

return _originalAttach.call(request, name, value, options);
};

request.on('redirect', ({statusCode}) => {
// Only for these 2 HTTP status code we need to post the form-data if any is available.
// For other status codes, superagent follows the redirect with a GET/HEAD request.
if ([307, 308].indexOf(statusCode) > -1 && formDataMap.size) {
const formData = new FormData();
const formFields = Array.from(formDataMap.keys());

formFields.forEach(fieldName => {
const formDataItems = formDataMap.get(fieldName);

formDataItems.forEach(({value, options, isFile}) => {
// only if file path is specified, recreate a readable stream as the previous
// one created by superagent would have been consumed by the initial request.
// This should work for any number of redirects
if (isFile && typeof value === 'string') {
value = fs.createReadStream(value);
}

formData.append(fieldName, value, options);
});
});

request._formData = formData;
}
});

return request;
};
```

Usage

```js
request.post(url)
.use(superagentReplayFormData())
.field('token', 'ABC1234ABC')
.attach('file', __dirname + '/README.md')
.attach('file', Buffer.from('Hello world'), 'hello.html');
```

Contributor guide

Open the contributing guide

Research direction

Start by tracing multipart handling through request.field, request.attach, and the redirect event, using PR #848 as context for why formData is deleted. Verify that fields and files are replayed for 307 and 308 redirects while other redirect methods retain their existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.