forwardemail / forwardemail/superagent
Support posting multipart/form-data following a redirect
- 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
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