diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4bd45fc..d0ffb65 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,3 +11,4 @@ Major changes since the last busboy release (0.31):
* Tests were converted to Mocha (#11, #12, #22, #23)
* Add isPartAFile-option, to make the file-detection configurable (#53)
* Empty Parts will not hang the process (#55)
+* FileStreams also provide the property `bytesRead`
diff --git a/README.md b/README.md
index e9ebc41..c5e2340 100644
--- a/README.md
+++ b/README.md
@@ -194,6 +194,7 @@ Busboy (special) events
* **file**(< _string_ >fieldname, < _ReadableStream_ >stream, < _string_ >filename, < _string_ >transferEncoding, < _string_ >mimeType) - Emitted for each new file form field found. `transferEncoding` contains the 'Content-Transfer-Encoding' value for the file stream. `mimeType` contains the 'Content-Type' value for the file stream.
* Note: if you listen for this event, you should always handle the `stream` no matter if you care about the file contents or not (e.g. you can simply just do `stream.resume();` if you want to discard the contents), otherwise the 'finish' event will never fire on the Busboy instance. However, if you don't care about **any** incoming files, you can simply not listen for the 'file' event at all and any/all files will be automatically and safely discarded (these discarded files do still count towards `files` and `parts` limits).
* If a configured file size limit was reached, `stream` will both have a boolean property `truncated` (best checked at the end of the stream) and emit a 'limit' event to notify you when this happens.
+ * The property `bytesRead` informs about the number of bytes that have been read so far.
* **field**(< _string_ >fieldname, < _string_ >value, < _boolean_ >fieldnameTruncated, < _boolean_ >valueTruncated, < _string_ >transferEncoding, < _string_ >mimeType) - Emitted for each new non-file field found.
diff --git a/benchmarks/package.json b/benchmarks/package.json
index 55ed418..9dd5153 100644
--- a/benchmarks/package.json
+++ b/benchmarks/package.json
@@ -11,8 +11,8 @@
},
"scripts": {
"install-node": "nvm install 17.2.0 && nvm install 16.13.1 && nvm install 14.18.2 && nvm install 12.22.7",
- "benchmark-busboy": "node busboy/executioner.js -c 0",
- "benchmark-fastify": "node busboy/executioner.js -c 1",
+ "benchmark-busboy": "node busboy/executioner.js -c 0 -p medium",
+ "benchmark-fastify": "node busboy/executioner.js -c 1 -p medium",
"benchmark-all": "npm run benchmark-busboy -- -p high && npm run benchmark-fastify -- -p high",
"benchmark-all-medium": "npm run benchmark-busboy -- -p medium && npm run benchmark-fastify -- -p medium",
"benchmark-all-low": "npm run benchmark-busboy -- -p low && npm run benchmark-fastify -- -p low",
diff --git a/lib/main.d.ts b/lib/main.d.ts
index bf50a57..bb87da6 100644
--- a/lib/main.d.ts
+++ b/lib/main.d.ts
@@ -5,7 +5,7 @@
///
import * as http from 'http';
-import {Readable, Writable} from 'stream';
+import { Readable, Writable } from 'stream';
declare const busboy: BusboyConstructor;
export default busboy
@@ -49,7 +49,7 @@ export interface BusboyConfig {
* Various limits on incoming data.
*/
limits?:
- | {
+ | {
/**
* Max field name size (in bytes)
* @default 100 bytes
@@ -86,11 +86,22 @@ export interface BusboyConfig {
*/
headerPairs?: number | undefined;
}
- | undefined;
+ | undefined;
}
export type BusboyHeaders = { 'content-type': string } & http.IncomingHttpHeaders;
+export interface BusboyFileStream extends
+ Readable {
+
+ truncated: boolean;
+
+ /**
+ * The number of bytes that have been read so far.
+ */
+ bytesRead: number;
+}
+
export interface Busboy extends Writable {
addListener(event: Event, listener: BusboyEvents[Event]): this;
@@ -138,7 +149,7 @@ export interface BusboyEvents {
*/
file: (
fieldname: string,
- stream: Readable,
+ stream: BusboyFileStream,
filename: string,
transferEncoding: string,
mimeType: string,
diff --git a/lib/types/multipart.js b/lib/types/multipart.js
index ac8b022..bbbc53a 100644
--- a/lib/types/multipart.js
+++ b/lib/types/multipart.js
@@ -195,12 +195,16 @@ function Multipart (boy, cfg) {
onData = function (data) {
if ((nsize += data.length) > fileSizeLimit) {
- const extralen = (fileSizeLimit - (nsize - data.length))
+ const extralen = fileSizeLimit - nsize + data.length
if (extralen > 0) { file.push(data.slice(0, extralen)) }
- file.emit('limit')
file.truncated = true
+ file.bytesRead = fileSizeLimit
part.removeAllListeners('data')
+ file.emit('limit')
+ return
} else if (!file.push(data)) { self._pause = true }
+
+ file.bytesRead = nsize
}
onEnd = function () {
@@ -287,6 +291,8 @@ function FileStream (opts) {
if (!(this instanceof FileStream)) { return new FileStream(opts) }
ReadableStream.call(this, opts)
+ this.bytesRead = 0
+
this.truncated = false
}
inherits(FileStream, ReadableStream)
diff --git a/test/types-multipart.spec.js b/test/types-multipart.spec.js
index b3dc23d..6e9cf4f 100644
--- a/test/types-multipart.spec.js
+++ b/test/types-multipart.spec.js
@@ -452,6 +452,8 @@ describe('types-multipart', () => {
++info[3]
}).on('end', function () {
info[2] = nb
+ assert(typeof (stream.bytesRead) === 'number', 'file.bytesRead is missing')
+ assert(stream.bytesRead === nb, 'file.bytesRead is not equal to filesize')
if (stream.truncated) { ++info[3] }
})
})
diff --git a/test/types/main.test-d.ts b/test/types/main.test-d.ts
index f2a780b..0fe9125 100644
--- a/test/types/main.test-d.ts
+++ b/test/types/main.test-d.ts
@@ -1,6 +1,5 @@
-import BusboyDefault, { BusboyConstructor, BusboyConfig, BusboyHeaders, Busboy, BusboyEvents } from '../..';
+import BusboyDefault, { BusboyConstructor, BusboyConfig, BusboyHeaders, Busboy, BusboyEvents, BusboyFileStream } from '../..';
import {expectError, expectType} from "tsd";
-import {Readable} from "stream";
// test type exports
type Constructor = BusboyConstructor;
@@ -28,7 +27,7 @@ new BusboyDefault({ headers: { 'content-type': 'foo' }, isPartAFile: (fieldName,
busboy.addListener('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname)
- expectType(file);
+ expectType(file);
expectType(filename);
expectType(encoding);
expectType(mimetype);
@@ -58,7 +57,7 @@ busboy.on(Symbol('foo'), foo => {
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname);
- expectType (file);
+ expectType (file);
expectType (filename);
expectType (encoding);
expectType (mimetype);
@@ -88,7 +87,7 @@ busboy.on(Symbol('foo'), foo => {
busboy.once('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname);
- expectType (file);
+ expectType (file);
expectType (filename);
expectType (encoding);
expectType (mimetype);
@@ -118,7 +117,7 @@ busboy.once(Symbol('foo'), foo => {
busboy.removeListener('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname);
- expectType (file);
+ expectType (file);
expectType (filename);
expectType (encoding);
expectType (mimetype);
@@ -148,7 +147,7 @@ busboy.removeListener(Symbol('foo'), foo => {
busboy.off('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname);
- expectType (file);
+ expectType (file);
expectType (filename);
expectType (encoding);
expectType (mimetype);
@@ -178,7 +177,7 @@ busboy.off(Symbol('foo'), foo => {
busboy.prependListener('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname);
- expectType (file);
+ expectType (file);
expectType (filename);
expectType (encoding);
expectType (mimetype);
@@ -208,7 +207,7 @@ busboy.prependListener(Symbol('foo'), foo => {
busboy.prependOnceListener('file', (fieldname, file, filename, encoding, mimetype) => {
expectType (fieldname);
- expectType (file);
+ expectType (file);
expectType (filename);
expectType (encoding);
expectType (mimetype);