diff --git a/.taprc b/.taprc index 7c34f05..eb6eb3e 100644 --- a/.taprc +++ b/.taprc @@ -1,4 +1,2 @@ files: - test/**/*.test.js - -branches: 95 diff --git a/index.js b/index.js index bf0b53c..25971aa 100644 --- a/index.js +++ b/index.js @@ -184,7 +184,7 @@ SendStream.prototype.error = function error (status, err) { } const res = this.res - const msg = statuses.message[status] || String(status) + const msg = statuses.message[status] const doc = createHtmlDocument('Error', escapeHtml(msg)) // clear existing headers @@ -323,10 +323,12 @@ SendStream.prototype.isCachable = function isCachable () { */ SendStream.prototype.onStatError = function onStatError (error) { + // POSIX throws ENAMETOOLONG and ENOTDIR, Windows only ENOENT + /* istanbul ignore next */ switch (error.code) { case 'ENAMETOOLONG': - case 'ENOENT': case 'ENOTDIR': + case 'ENOENT': this.error(404, error) break default: @@ -474,10 +476,9 @@ SendStream.prototype.pipe = function pipe (res) { if (containsDotFile(parts)) { let access = this._dotfiles - // legacy support if (access === undefined) { access = parts[parts.length - 1][0] === '.' - ? (this._hidden ? 'allow' : 'ignore') + ? 'ignore' : 'allow' } diff --git a/package.json b/package.json index 67063a5..7bb2d8b 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "lint": "standard | snazzy", "lint:fix": "standard --fix | snazzy", "test": "npm run test:unit && npm run test:typescript", + "test:coverage": "tap --coverage-report=html", "test:typescript": "tsd", "test:unit": "tap" } diff --git a/test/send-pipe.test.js b/test/send-pipe.test.js index b6ecebd..41f9f20 100644 --- a/test/send-pipe.test.js +++ b/test/send-pipe.test.js @@ -6,13 +6,14 @@ const http = require('http') const path = require('path') const request = require('supertest') const send = require('..') +const os = require('os') const { shouldNotHaveBody, createServer, shouldNotHaveHeader } = require('./utils') const dateRegExp = /^\w{3}, \d+ \w+ \d+ \d+:\d+:\d+ \w+$/ const fixtures = path.join(__dirname, 'fixtures') test('send(file).pipe(res)', function (t) { - t.plan(27) + t.plan(29) t.test('should stream the file contents', function (t) { t.plan(1) @@ -296,6 +297,36 @@ test('send(file).pipe(res)', function (t) { .expect(200, '404 ENOENT', err => t.error(err)) }) + t.test('should emit ENAMETOOLONG if the filename is too long', function (t) { + t.plan(1) + + const app = http.createServer(function (req, res) { + send(req, req.url, { root: fixtures }) + .on('error', function (err) { res.end(err.statusCode + ' ' + err.code) }) + .pipe(res) + }) + + const longFilename = new Array(512).fill('a').join('') + + request(app) + .get('/' + longFilename) + .expect(200, os.platform() === 'win32' ? '404 ENOENT' : '404 ENAMETOOLONG', err => t.error(err)) + }) + + t.test('should emit ENOTDIR if the requested resource is not a directory', function (t) { + t.plan(1) + + const app = http.createServer(function (req, res) { + send(req, req.url, { root: fixtures }) + .on('error', function (err) { res.end(err.statusCode + ' ' + err.code) }) + .pipe(res) + }) + + request(app) + .get('/nums.txt/invalid') + .expect(200, os.platform() === 'win32' ? '404 ENOENT' : '404 ENOTDIR', err => t.error(err)) + }) + t.test('should not override content-type', function (t) { t.plan(1) @@ -630,7 +661,7 @@ test('send(file).pipe(res)', function (t) { }) t.test('with conditional-GET', function (t) { - t.plan(6) + t.plan(7) t.test('should remove Content headers with 304', function (t) { t.plan(5) @@ -657,6 +688,32 @@ test('send(file).pipe(res)', function (t) { }) }) + t.test('should remove Content headers with 304 /2', function (t) { + t.plan(5) + + const server = createServer({ root: fixtures }, function (req, res) { + res.setHeader('Content-Language', 'en-US') + res.setHeader('Content-Location', 'http://localhost/name.txt') + res.setHeader('Contents', 'foo') + res.statusCode = 304 + }) + + request(server) + .get('/name.txt') + .expect(304, function (err, res) { + t.error(err) + request(server) + .get('/name.txt') + .set('If-None-Match', res.headers.etag) + .expect(shouldNotHaveHeader('Content-Language', t)) + .expect(shouldNotHaveHeader('Content-Length', t)) + .expect(shouldNotHaveHeader('Content-Type', t)) + .expect('Content-Location', 'http://localhost/name.txt') + .expect('Contents', 'foo') + .expect(304, err => t.error(err)) + }) + }) + t.test('should not remove all Content-* headers', function (t) { t.plan(4) diff --git a/test/statuses.test.js b/test/statuses.test.js new file mode 100644 index 0000000..40cf8d9 --- /dev/null +++ b/test/statuses.test.js @@ -0,0 +1,18 @@ +'use strict' + +const { test } = require('tap') +const statuses = require('statuses') + +test('statuses', function (t) { + t.plan(1) + + t.test('should have uses statusCodes', function (t) { + t.plan(6) + t.ok(statuses(400)) + t.ok(statuses(403)) + t.ok(statuses(404)) + t.ok(statuses(412)) + t.ok(statuses(416)) + t.ok(statuses(500)) + }) +})