diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f80ad3..ddd6306 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ jobs: test: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: name: - Node.js 0.8 @@ -26,6 +27,18 @@ jobs: - Node.js 11.x - Node.js 12.x - Node.js 13.x + - Node.js 14.x + - Node.js 15.x + - Node.js 16.x + - Node.js 17.x + - Node.js 18.x + - Node.js 19.x + - Node.js 20.x + - Node.js 21.x + - Node.js 22.x + - Node.js 23.x + - Node.js 24.x + - Node.js 25.x include: - name: Node.js 0.8 @@ -63,45 +76,72 @@ jobs: - name: Node.js 6.x node-version: "6.17" - npm-i: mocha@6.2.3 nyc@14.1.1 + npm-i: mocha@6.2.3 nyc@14.1.1 supertest@6.1.6 - name: Node.js 7.x node-version: "7.10" - npm-i: mocha@6.2.3 nyc@14.1.1 + npm-i: mocha@6.2.3 nyc@14.1.1 supertest@6.1.6 - name: Node.js 8.x node-version: "8.16" - npm-i: mocha@7.2.0 + npm-i: mocha@7.2.0 nyc@14.1.1 supertest@6.1.6 - name: Node.js 9.x node-version: "9.11" - npm-i: mocha@7.2.0 + npm-i: mocha@7.2.0 nyc@14.1.1 supertest@6.1.6 - name: Node.js 10.x node-version: "10.24" - npm-i: mocha@8.4.0 + npm-i: mocha@8.4.0 supertest@6.1.6 - name: Node.js 11.x node-version: "11.15" - npm-i: mocha@8.4.0 + npm-i: mocha@8.4.0 supertest@6.1.6 - name: Node.js 12.x node-version: "12.22" + npm-i: supertest@6.1.6 - name: Node.js 13.x node-version: "13.14" + npm-i: supertest@6.1.6 - name: Node.js 14.x - node-version: "14.18" + node-version: "14.19" - name: Node.js 15.x node-version: "15.14" + npm-i: supertest@6.1.6 - name: Node.js 16.x - node-version: "16.13" + node-version: "16.14" - name: Node.js 17.x - node-version: "17.2" + node-version: "17.7" + + - name: Node.js 18.x + node-version: 18 + + - name: Node.js 19.x + node-version: 19 + + - name: Node.js 20.x + node-version: 20 + + - name: Node.js 21.x + node-version: 21 + + - name: Node.js 22.x + node-version: 22 + + - name: Node.js 23.x + node-version: 23 + + - name: Node.js 24.x + node-version: 24 + + - name: Node.js 25.x + node-version: 25 steps: - uses: actions/checkout@v2 @@ -118,9 +158,6 @@ jobs: fi dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH" - - name: Configure npm - run: npm config set shrinkwrap false - - name: Remove npm module(s) ${{ matrix.npm-rm }} run: npm rm --silent --save-dev ${{ matrix.npm-rm }} if: matrix.npm-rm != '' diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..9cf9495 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/HISTORY.md b/HISTORY.md index 8aa3ab3..13789ba 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,35 @@ +0.19.2 / 2025-12-15 +=================== + +* deps: use tilde notation for dependencies +* deps: http-errors@~2.0.1 +* deps: statuses@~2.0.2 + +0.19.1 / 2024-10-09 +=================== + +* deps: encodeurl@~2.0.0 + +0.19.0 / 2024-09-10 +=================== + +* Remove link renderization in html while redirecting + +0.18.0 / 2022-03-23 +=================== + + * Fix emitted 416 error missing headers property + * Limit the headers removed for 304 response + * deps: depd@2.0.0 + - Replace internal `eval` usage with `Function` constructor + - Use instance methods on `process` to check for listeners + * deps: destroy@1.2.0 + * deps: http-errors@2.0.0 + - deps: depd@2.0.0 + - deps: statuses@2.0.1 + * deps: on-finished@2.4.1 + * deps: statuses@2.0.1 + 0.17.2 / 2021-12-11 =================== @@ -465,37 +497,37 @@ * update range-parser and fresh -0.1.4 / 2013-08-11 +0.1.4 / 2013-08-11 ================== * update fresh -0.1.3 / 2013-07-08 +0.1.3 / 2013-07-08 ================== * Revert "Fix fd leak" -0.1.2 / 2013-07-03 +0.1.2 / 2013-07-03 ================== * Fix fd leak -0.1.0 / 2012-08-25 +0.1.0 / 2012-08-25 ================== * add options parameter to send() that is passed to fs.createReadStream() [kanongil] -0.0.4 / 2012-08-16 +0.0.4 / 2012-08-16 ================== * allow custom "Accept-Ranges" definition -0.0.3 / 2012-07-16 +0.0.3 / 2012-07-16 ================== * fix normalization of the root directory. Closes #3 -0.0.2 / 2012-07-09 +0.0.2 / 2012-07-09 ================== * add passing of req explicitly for now (YUCK) diff --git a/LICENSE b/LICENSE index 4aa69e8..b6ea1c1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ (The MIT License) Copyright (c) 2012 TJ Holowaychuk -Copyright (c) 2014-2016 Douglas Christopher Wilson +Copyright (c) 2014-2022 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index fc1d3a1..fadf838 100644 --- a/README.md +++ b/README.md @@ -318,8 +318,8 @@ server.listen(3000) [appveyor-url]: https://ci.appveyor.com/project/dougwilson/send [coveralls-image]: https://badgen.net/coveralls/c/github/pillarjs/send/master [coveralls-url]: https://coveralls.io/r/pillarjs/send?branch=master -[github-actions-ci-image]: https://badgen.net/github/checks/pillarjs/send/master?label=ci -[github-actions-ci-url]: https://github.com/pillarjs/send/actions?query=workflow%3Aci +[github-actions-ci-image]: https://badgen.net/github/checks/pillarjs/send/master?label=linux +[github-actions-ci-url]: https://github.com/pillarjs/send/actions/workflows/ci.yml [node-image]: https://badgen.net/npm/node/send [node-url]: https://nodejs.org/en/download/ [npm-downloads-image]: https://badgen.net/npm/dm/send diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..46b48f7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,24 @@ +# Security Policies and Procedures + +## Reporting a Bug + +The `send` team and community take all security bugs seriously. Thank you +for improving the security of Express. We appreciate your efforts and +responsible disclosure and will make every effort to acknowledge your +contributions. + +Report security bugs by emailing the current owner(s) of `send`. This information +can be found in the npm registry using the command `npm owner ls send`. +If unsure or unable to get the information from the above, open an issue +in the [project issue tracker](https://github.com/pillarjs/send/issues) +asking for the current contact information. + +To ensure the timely response to your report, please ensure that the entirety +of the report is contained within the email body and not solely behind a web +link or an attachment. + +At least one owner will acknowledge your email within 48 hours, and will send a +more detailed response within 48 hours indicating the next steps in handling +your report. After the initial reply to your report, the owners will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. diff --git a/appveyor.yml b/appveyor.yml index d577cca..1332a99 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,10 +15,10 @@ environment: - nodejs_version: "11.15" - nodejs_version: "12.22" - nodejs_version: "13.14" - - nodejs_version: "14.18" + - nodejs_version: "14.19" - nodejs_version: "15.14" - - nodejs_version: "16.13" - - nodejs_version: "17.2" + - nodejs_version: "16.14" + - nodejs_version: "17.7" cache: - node_modules install: @@ -61,10 +61,13 @@ install: # supertest for http calls # - use 2.0.0 for Node.js < 4 # - use 3.4.2 for Node.js < 6 + # - use 6.1.6 for Node.js < 8 if ([int]$env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev supertest@2.0.0 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev supertest@3.4.2 + } elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) { + npm install --silent --save-dev supertest@6.1.6 } # Update Node.js modules - ps: | diff --git a/index.js b/index.js index 06d7507..768f8ca 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ /*! * send * Copyright(c) 2012 TJ Holowaychuk - * Copyright(c) 2014-2016 Douglas Christopher Wilson + * Copyright(c) 2014-2022 Douglas Christopher Wilson * MIT Licensed */ @@ -267,13 +267,11 @@ SendStream.prototype.maxage = deprecate.function(function maxage (maxAge) { SendStream.prototype.error = function error (status, err) { // emit if listeners instead of responding if (hasListeners(this, 'error')) { - return this.emit('error', createError(status, err, { - expose: false - })) + return this.emit('error', createHttpError(status, err)) } var res = this.res - var msg = statuses[status] || String(status) + var msg = statuses.message[status] || String(status) var doc = createHtmlDocument('Error', escapeHtml(msg)) // clear existing headers @@ -349,21 +347,19 @@ SendStream.prototype.isPreconditionFailure = function isPreconditionFailure () { } /** - * Strip content-* header fields. + * Strip various content header fields for a change in entity. * * @private */ SendStream.prototype.removeContentHeaderFields = function removeContentHeaderFields () { var res = this.res - var headers = getHeaderNames(res) - for (var i = 0; i < headers.length; i++) { - var header = headers[i] - if (header.substr(0, 8) === 'content-' && header !== 'content-location') { - res.removeHeader(header) - } - } + res.removeHeader('Content-Encoding') + res.removeHeader('Content-Language') + res.removeHeader('Content-Length') + res.removeHeader('Content-Range') + res.removeHeader('Content-Type') } /** @@ -486,8 +482,7 @@ SendStream.prototype.redirect = function redirect (path) { } var loc = encodeUrl(collapseLeadingSlashes(this.path + '/')) - var doc = createHtmlDocument('Redirecting', 'Redirecting to ' + - escapeHtml(loc) + '') + var doc = createHtmlDocument('Redirecting', 'Redirecting to ' + escapeHtml(loc)) // redirect res.statusCode = 301 @@ -787,8 +782,6 @@ SendStream.prototype.sendIndex = function sendIndex (path) { */ SendStream.prototype.stream = function stream (path, options) { - // TODO: this is all lame, refactor meeee - var finished = false var self = this var res = this.res @@ -797,20 +790,18 @@ SendStream.prototype.stream = function stream (path, options) { this.emit('stream', stream) stream.pipe(res) - // response finished, done with the fd - onFinished(res, function onfinished () { - finished = true - destroy(stream) - }) + // cleanup + function cleanup () { + destroy(stream, true) + } - // error handling code-smell - stream.on('error', function onerror (err) { - // request already finished - if (finished) return + // response finished, cleanup + onFinished(res, cleanup) - // clean up stream - finished = true - destroy(stream) + // error handling + stream.on('error', function onerror (err) { + // clean up stream early + cleanup() // error self.onStatError(err) @@ -974,6 +965,24 @@ function createHtmlDocument (title, body) { '\n' } +/** + * Create a HttpError object from simple arguments. + * + * @param {number} status + * @param {Error|object} err + * @private + */ + +function createHttpError (status, err) { + if (!err) { + return createError(status) + } + + return err instanceof Error + ? createError(status, err, { expose: false }) + : createError(status, err) +} + /** * decodeURIComponent. * diff --git a/package.json b/package.json index f58140c..2d2b805 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "send", "description": "Better streaming static file server with Range and conditional-GET support", - "version": "0.17.2", + "version": "0.19.2", "author": "TJ Holowaychuk ", "contributors": [ "Douglas Christopher Wilson ", @@ -17,36 +17,37 @@ ], "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "~2.0.2" }, "devDependencies": { "after": "0.8.2", "eslint": "7.32.0", "eslint-config-standard": "14.1.1", - "eslint-plugin-import": "2.25.3", + "eslint-plugin-import": "2.25.4", "eslint-plugin-markdown": "2.2.1", "eslint-plugin-node": "11.1.0", "eslint-plugin-promise": "5.2.0", "eslint-plugin-standard": "4.1.0", - "mocha": "9.1.3", + "mocha": "9.2.2", "nyc": "15.1.0", - "supertest": "6.1.6" + "supertest": "6.2.2" }, "files": [ "HISTORY.md", "LICENSE", "README.md", + "SECURITY.md", "index.js" ], "engines": { diff --git a/test/send.js b/test/send.js index 4daacfa..7fa9dd7 100644 --- a/test/send.js +++ b/test/send.js @@ -358,7 +358,7 @@ describe('send(file).pipe(res)', function () { .get('/pets') .expect('Location', '/pets/') .expect('Content-Type', /html/) - .expect(301, />Redirecting to \/pets\/<\/a>Redirecting to \/pets\/Redirecting to \/snow%20%E2%98%83\/<\/a>Redirecting to \/snow%20%E2%98%83\/