From 8a8343ec8e32dca6335f8948705a81beef029564 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 29 Nov 2021 16:44:47 +0100 Subject: [PATCH 1/6] fix malformed header bug, red phase --- test/dicer-malformed-header.spec.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/dicer-malformed-header.spec.js diff --git a/test/dicer-malformed-header.spec.js b/test/dicer-malformed-header.spec.js new file mode 100644 index 0000000..ce729f8 --- /dev/null +++ b/test/dicer-malformed-header.spec.js @@ -0,0 +1,27 @@ +const Dicer = require('../deps/dicer/lib/Dicer'); + +describe('dicer-malformed-header', () => { + + it("should gracefully handle headers with leading whitespace", done => { + var inspect = require('util').inspect; + var d = new Dicer({ boundary: "----WebKitFormBoundaryoo6vortfDzBsDiro" }); + + d.on('part', function (p) { + p.on('header', function (header) { + for (var h in header) { + console.log('Part header: k: ' + inspect(h) + + ', v: ' + inspect(header[h])); + } + }); + p.on('data', function (data) { + }); + p.on('end', function () { + }); + }); + d.on('finish', function () { + done(); + }); + + d.write(Buffer.from('------WebKitFormBoundaryoo6vortfDzBsDiro\r\n Content-Disposition: form-data; name="bildbeschreibung"\r\n\r\n\r\n------WebKitFormBoundaryoo6vortfDzBsDiro--')); + }).timeout(10000); +}); From 3cef32101b0e180021641bfe79004c25117cf04d Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 29 Nov 2021 16:45:27 +0100 Subject: [PATCH 2/6] fix malformed header bug, green phase --- deps/dicer/lib/Dicer.js | 21 +++++---------- deps/dicer/lib/HeaderParser.js | 48 ++++++++++++++++------------------ 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/deps/dicer/lib/Dicer.js b/deps/dicer/lib/Dicer.js index ad6c1b7..01598d3 100644 --- a/deps/dicer/lib/Dicer.js +++ b/deps/dicer/lib/Dicer.js @@ -31,7 +31,6 @@ function Dicer(cfg) { this._dashes = 0; this._parts = 0; this._finished = false; - this._realFinish = false; this._isPreamble = true; this._justMatched = false; this._firstWrite = true; @@ -54,7 +53,7 @@ function Dicer(cfg) { inherits(Dicer, WritableStream); Dicer.prototype.emit = function(ev) { - if (ev === 'finish' && !this._realFinish) { + if (ev === 'finish') { if (!this._finished) { var self = this; process.nextTick(function() { @@ -64,15 +63,11 @@ Dicer.prototype.emit = function(ev) { self._part.emit('error', new Error(type + ' terminated early due to unexpected end of multipart data')); self._part.push(null); process.nextTick(function() { - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; + WritableStream.prototype.emit.call(self, 'finish'); }); return; } - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; + WritableStream.prototype.emit.call(self, 'finish'); }); } } else @@ -160,9 +155,7 @@ Dicer.prototype._oninfo = function(isMatch, data, start, end) { this._finished = true; // no more parts will be added if (self._parts === 0) { - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; + WritableStream.prototype.emit.call(self, 'finish'); } } if (this._dashes) @@ -190,7 +183,7 @@ Dicer.prototype._oninfo = function(isMatch, data, start, end) { shouldWriteMore = this._part.push(data.slice(start, end)); if (!shouldWriteMore) this._pause = true; - } else if (!this._isPreamble && this._inHeader) { + } else { if (buf) this._hparser.push(buf); r = this._hparser.push(data.slice(start, end)); @@ -207,9 +200,7 @@ Dicer.prototype._oninfo = function(isMatch, data, start, end) { this._part.on('end', function() { if (--self._parts === 0) { if (self._finished) { - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; + WritableStream.prototype.emit.call(self, 'finish'); } else { self._unpause(); } diff --git a/deps/dicer/lib/HeaderParser.js b/deps/dicer/lib/HeaderParser.js index 203b72b..0e06b84 100644 --- a/deps/dicer/lib/HeaderParser.js +++ b/deps/dicer/lib/HeaderParser.js @@ -26,7 +26,7 @@ function HeaderParser(cfg) { this.ss.on('info', function(isMatch, data, start, end) { if (data && !self.maxed) { if (self.nread + (end - start) > MAX_HEADER_SIZE) { - end = (MAX_HEADER_SIZE - self.nread); + end = MAX_HEADER_SIZE - self.nread + start; self.nread = MAX_HEADER_SIZE; } else self.nread += (end - start); @@ -72,39 +72,37 @@ HeaderParser.prototype._parseHeader = function() { if (this.npairs === this.maxHeaderPairs) return; - var lines = this.buffer.split(RE_CRLF), len = lines.length, m, h, - modded = false; + const lines = this.buffer.split(RE_CRLF), + len = lines.length; + let m, h; - for (var i = 0; i < len; ++i) { + for (let i = 0; i < len; ++i) { if (lines[i].length === 0) continue; if (lines[i][0] === '\t' || lines[i][0] === ' ') { // folded header content // RFC2822 says to just remove the CRLF and not the whitespace following // it, so we follow the RFC and include the leading whitespace ... - this.header[h][this.header[h].length - 1] += lines[i]; - } else { - m = RE_HDR.exec(lines[i]); - if (m) { - h = m[1].toLowerCase(); - if (m[2]) { - if (this.header[h] === undefined) - this.header[h] = [m[2]]; - else - this.header[h].push(m[2]); - } else - this.header[h] = ['']; - if (++this.npairs === this.maxHeaderPairs) - break; - } else { - this.buffer = lines[i]; - modded = true; - break; + if (h) { + this.header[h][this.header[h].length - 1] += lines[i]; + continue; } } + m = RE_HDR.exec(lines[i]); + if (m) { + h = m[1].toLowerCase(); + if (m[2]) { + if (this.header[h] === undefined) + this.header[h] = [m[2]]; + else + this.header[h].push(m[2]); + } else + this.header[h] = ['']; + if (++this.npairs === this.maxHeaderPairs) + break; + } else + return; } - if (!modded) - this.buffer = ''; }; -module.exports = HeaderParser; +module.exports = HeaderParser; \ No newline at end of file From 8c8d6d4a1e15f3dd2345736c70d948277605449a Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 29 Nov 2021 16:50:51 +0100 Subject: [PATCH 3/6] modify test --- test/dicer-malformed-header.spec.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/dicer-malformed-header.spec.js b/test/dicer-malformed-header.spec.js index ce729f8..16b588f 100644 --- a/test/dicer-malformed-header.spec.js +++ b/test/dicer-malformed-header.spec.js @@ -1,17 +1,15 @@ const Dicer = require('../deps/dicer/lib/Dicer'); +const { expect } = require('chai'); describe('dicer-malformed-header', () => { it("should gracefully handle headers with leading whitespace", done => { - var inspect = require('util').inspect; var d = new Dicer({ boundary: "----WebKitFormBoundaryoo6vortfDzBsDiro" }); d.on('part', function (p) { p.on('header', function (header) { - for (var h in header) { - console.log('Part header: k: ' + inspect(h) - + ', v: ' + inspect(header[h])); - } + expect(header).has.property(" content-disposition"); + expect(header[" content-disposition"]).to.be.eql(['form-data; name="bildbeschreibung"']) }); p.on('data', function (data) { }); From fa0fc224e93be93d807d93474f3a66f813ec9349 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 29 Nov 2021 17:11:07 +0100 Subject: [PATCH 4/6] use var instead of let --- deps/dicer/lib/HeaderParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/dicer/lib/HeaderParser.js b/deps/dicer/lib/HeaderParser.js index 0e06b84..a320470 100644 --- a/deps/dicer/lib/HeaderParser.js +++ b/deps/dicer/lib/HeaderParser.js @@ -76,7 +76,7 @@ HeaderParser.prototype._parseHeader = function() { len = lines.length; let m, h; - for (let i = 0; i < len; ++i) { + for (var i = 0; i < len; ++i) { if (lines[i].length === 0) continue; if (lines[i][0] === '\t' || lines[i][0] === ' ') { From c7c2cf6f2965d02ce2d88a57474c7b6bffd81d60 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 29 Nov 2021 17:20:27 +0100 Subject: [PATCH 5/6] revert finsh changes in dicer --- deps/dicer/lib/Dicer.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/deps/dicer/lib/Dicer.js b/deps/dicer/lib/Dicer.js index 01598d3..ad6c1b7 100644 --- a/deps/dicer/lib/Dicer.js +++ b/deps/dicer/lib/Dicer.js @@ -31,6 +31,7 @@ function Dicer(cfg) { this._dashes = 0; this._parts = 0; this._finished = false; + this._realFinish = false; this._isPreamble = true; this._justMatched = false; this._firstWrite = true; @@ -53,7 +54,7 @@ function Dicer(cfg) { inherits(Dicer, WritableStream); Dicer.prototype.emit = function(ev) { - if (ev === 'finish') { + if (ev === 'finish' && !this._realFinish) { if (!this._finished) { var self = this; process.nextTick(function() { @@ -63,11 +64,15 @@ Dicer.prototype.emit = function(ev) { self._part.emit('error', new Error(type + ' terminated early due to unexpected end of multipart data')); self._part.push(null); process.nextTick(function() { - WritableStream.prototype.emit.call(self, 'finish'); + self._realFinish = true; + self.emit('finish'); + self._realFinish = false; }); return; } - WritableStream.prototype.emit.call(self, 'finish'); + self._realFinish = true; + self.emit('finish'); + self._realFinish = false; }); } } else @@ -155,7 +160,9 @@ Dicer.prototype._oninfo = function(isMatch, data, start, end) { this._finished = true; // no more parts will be added if (self._parts === 0) { - WritableStream.prototype.emit.call(self, 'finish'); + self._realFinish = true; + self.emit('finish'); + self._realFinish = false; } } if (this._dashes) @@ -183,7 +190,7 @@ Dicer.prototype._oninfo = function(isMatch, data, start, end) { shouldWriteMore = this._part.push(data.slice(start, end)); if (!shouldWriteMore) this._pause = true; - } else { + } else if (!this._isPreamble && this._inHeader) { if (buf) this._hparser.push(buf); r = this._hparser.push(data.slice(start, end)); @@ -200,7 +207,9 @@ Dicer.prototype._oninfo = function(isMatch, data, start, end) { this._part.on('end', function() { if (--self._parts === 0) { if (self._finished) { - WritableStream.prototype.emit.call(self, 'finish'); + self._realFinish = true; + self.emit('finish'); + self._realFinish = false; } else { self._unpause(); } From 9b3bde89a25728614d1f3de087b32475e61d45f0 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 29 Nov 2021 17:38:13 +0100 Subject: [PATCH 6/6] remove timeout --- test/dicer-malformed-header.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dicer-malformed-header.spec.js b/test/dicer-malformed-header.spec.js index 16b588f..83cc235 100644 --- a/test/dicer-malformed-header.spec.js +++ b/test/dicer-malformed-header.spec.js @@ -21,5 +21,5 @@ describe('dicer-malformed-header', () => { }); d.write(Buffer.from('------WebKitFormBoundaryoo6vortfDzBsDiro\r\n Content-Disposition: form-data; name="bildbeschreibung"\r\n\r\n\r\n------WebKitFormBoundaryoo6vortfDzBsDiro--')); - }).timeout(10000); + }); });