Skip to content

Commit e6ffbde

Browse files
committed
Fix handling of FormData errors
When a file cannot be uploaded (e.g. becase it does not exist), report the error via callback/promise. Before this change, FormData errors were reported via "error" event on the request. In promise mode, such error was caught by `.then()` handler in a way that shadowed the actual error reported by `.end()`. In callback mode, such error was not caught at all and crashed the process on an unhandled error. With this change in place, FormData errors finish the request and pass the error directly to the callback.
1 parent 0f0949f commit e6ffbde

File tree

3 files changed

+39
-18
lines changed

3 files changed

+39
-18
lines changed

lib/node/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,13 @@ Request.prototype._getFormData = function() {
264264
if (!this._formData) {
265265
this._formData = new FormData();
266266
this._formData.on('error', err => {
267-
this.emit('error', err);
267+
debug('FormData error', err);
268+
if (this.called) {
269+
// The request has already finished and the callback was called.
270+
// Silently ignore the error.
271+
return;
272+
}
273+
this.callback(err);
268274
this.abort();
269275
});
270276
}

lib/request-base.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ RequestBase.prototype.then = function then(resolve, reject) {
242242
console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises");
243243
}
244244
this._fullfilledPromise = new Promise((innerResolve, innerReject) => {
245-
self.on('error', innerReject);
246245
self.on('abort', () => {
247246
const err = new Error('Aborted');
248247
err.code = "ABORTED";

test/node/multipart.js

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,31 +73,49 @@ describe("Multipart", () => {
7373
});
7474

7575
describe("when a file does not exist", () => {
76-
it("should emit an error", done => {
76+
it("should fail the request with an error", done => {
7777
const req = request.post(`${base}/echo`);
7878

7979
req.attach("name", "foo");
8080
req.attach("name2", "bar");
8181
req.attach("name3", "baz");
8282

83-
req.on("error", err => {
83+
req.end((err, res) => {
84+
assert.ok(!!err, "Request should have failed.");
85+
err.code.should.equal("ENOENT");
8486
err.message.should.containEql("ENOENT");
8587
err.path.should.equal("foo");
8688
done();
8789
});
88-
89-
req.end((err, res) => {
90-
if (err) return done(err);
91-
assert(0, "end() was called");
92-
});
9390
});
9491

9592
it("promise should fail", () => {
96-
request.post('nevermind')
97-
.field({a:1,b:2})
98-
.attach('c', 'does-not-exist.txt')
99-
.then(() => assert.fail("It should not allow this"))
100-
.catch(() => true);
93+
return request.post(`${base}/echo`)
94+
.field({a:1,b:2})
95+
.attach('c', 'does-not-exist.txt')
96+
.then(
97+
res => assert.fail("It should not allow this"),
98+
err => {
99+
err.code.should.equal("ENOENT");
100+
err.path.should.equal("does-not-exist.txt");
101+
});
102+
});
103+
104+
it("should report ECONNREFUSED via the callback", done => {
105+
request.post('http://127.0.0.1:1') // nobody is listening there
106+
.attach("name", "file-does-not-exist")
107+
.end((err, res) => {
108+
assert.ok(!!err, "Request should have failed");
109+
err.code.should.equal("ECONNREFUSED");
110+
done();
111+
});
112+
});
113+
it("should report ECONNREFUSED via Promise", () => {
114+
return request.post('http://127.0.0.1:1') // nobody is listening there
115+
.attach("name", "file-does-not-exist")
116+
.then(
117+
res => assert.fail("Request should have failed"),
118+
err => err.code.should.equal("ECONNREFUSED"));
101119
});
102120
});
103121
});
@@ -143,13 +161,11 @@ describe("Multipart", () => {
143161
request
144162
.post(`${base}/echo`)
145163
.attach("filedata", "test/node/fixtures/non-existent-file.ext")
146-
.on("error", err => {
164+
.end((err, res) => {
165+
assert.ok(!!err, "Request should have failed.");
147166
err.code.should.equal("ENOENT");
148167
err.path.should.equal("test/node/fixtures/non-existent-file.ext");
149168
done();
150-
})
151-
.end((err, res) => {
152-
done(new Error("Request should have been aborted earlier!"));
153169
});
154170
});
155171
});

0 commit comments

Comments
 (0)