Compare commits

...

40 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
a73d752247 1.1.3 2014-06-20 13:49:12 -04:00
Douglas Christopher Wilson
4e8cf53ce5 deps: accepts@~1.0.4 2014-06-20 13:48:16 -04:00
Douglas Christopher Wilson
4e8726c41c 1.1.2 2014-06-19 11:09:23 -04:00
Douglas Christopher Wilson
d7d661245e deps: batch@0.5.1 2014-06-19 11:02:13 -04:00
Douglas Christopher Wilson
5037f808c0 1.1.1 2014-06-11 23:59:59 -04:00
Douglas Christopher Wilson
910923b920 deps: accepts@1.0.3 2014-06-11 23:49:07 -04:00
Douglas Christopher Wilson
70c35f62b2 build: use compact formats in package 2014-06-11 22:46:53 -04:00
Basarat Ali Syed
73ceabeb00 docs: use module name as export name
closes #10
2014-06-08 23:14:33 -04:00
Douglas Christopher Wilson
76daee7400 1.1.0 2014-05-29 15:29:13 -04:00
Douglas Christopher Wilson
f75c172d72 deps: should@~4.0.0 2014-05-29 15:03:58 -04:00
Douglas Christopher Wilson
7a2a8d2ecc Use accepts for negotiation 2014-05-29 14:37:29 -04:00
Douglas Christopher Wilson
cb38e459ca tests: add more tests 2014-05-29 10:55:48 -04:00
Douglas Christopher Wilson
2edcc09345 Treat ENAMETOOLONG as code 414 2014-05-29 09:05:25 -04:00
Douglas Christopher Wilson
a0415f5df2 Remove res.writeHead 2014-05-29 08:38:31 -04:00
Douglas Christopher Wilson
711194e063 Fix content negotiation when no Accept header 2014-05-29 08:35:04 -04:00
Douglas Christopher Wilson
4d19115d6b tests: add more basic tests 2014-05-28 17:22:13 -04:00
Douglas Christopher Wilson
c00618fa62 Properly support all HTTP methods 2014-05-28 17:13:22 -04:00
Douglas Christopher Wilson
db91ccac66 Throw TypeError for missing root argument 2014-05-28 17:01:53 -04:00
Douglas Christopher Wilson
926ee987fa build: add coverage reporting 2014-05-28 16:56:31 -04:00
Douglas Christopher Wilson
6277105d11 build: add test coverage 2014-05-28 16:36:56 -04:00
Douglas Christopher Wilson
199f5d0205 tests: remove use of connect 2014-05-28 16:31:41 -04:00
Douglas Christopher Wilson
871f4d679e Support vanilla node.js http servers 2014-05-28 16:27:28 -04:00
Douglas Christopher Wilson
6e3f352894 tests: add custom handler tests 2014-05-24 23:15:03 -04:00
Douglas Christopher Wilson
9fbc4bf182 1.0.3 2014-05-20 10:23:05 -04:00
Douglas Christopher Wilson
027f6dcf54 Fix error from non-statable files in HTML view
fixes #6
2014-05-20 10:14:31 -04:00
Douglas Christopher Wilson
f7eb0ae92a docs: add History 2014-05-20 10:00:15 -04:00
Fishrock123
51e9763c0a docs: enhance 2014-04-29 10:53:47 -04:00
Chris O'Connor
dd6a4a864a docs: fix typo, add stylesheet
closes #4
2014-04-29 10:37:11 -04:00
Douglas Christopher Wilson
cff5890bce 1.0.2 2014-04-28 14:44:13 -04:00
Douglas Christopher Wilson
6d9e23c5ac docs: use SVG Travis CI badge 2014-04-28 14:34:00 -04:00
Douglas Christopher Wilson
36d68485ab deps: negotiator@0.4.3 2014-04-28 14:32:38 -04:00
Chris O'Connor
e40300aa86 Add stylesheet option
closes #2
2014-04-28 14:31:00 -04:00
Anthony Verez
5771318d78 docs: document the view option
closes #1
2014-04-26 13:16:02 -04:00
Douglas Christopher Wilson
d006e3a123 deps: tighten devDepencency ranges 2014-03-06 14:51:51 -05:00
Douglas Christopher Wilson
a2364a8abf test: test on node.js 0.11 2014-03-06 13:26:46 -05:00
Douglas Christopher Wilson
90e39a9a4f deps: use 0.8-compatible semver in devDependencies 2014-03-06 13:23:48 -05:00
Douglas Christopher Wilson
480fdcc468 docs: add Travis CI badge 2014-03-06 13:02:48 -05:00
Douglas Christopher Wilson
b4cd08b1a3 1.0.1 2014-03-06 09:59:04 -05:00
Douglas Christopher Wilson
c1b2ad4a71 deps: negotiator@0.4.2 2014-03-06 09:58:26 -05:00
Douglas Christopher Wilson
e18a68fc94 docs: add note about Silk icons 2014-03-05 22:42:46 -05:00
9 changed files with 558 additions and 186 deletions

64
.gitignore vendored
View File

@@ -1,65 +1,3 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store*
ehthumbs.db
Thumbs.db
# Node.js #
###########
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
coverage
node_modules
npm-debug.log
# Git #
#######
*.orig
*.BASE.*
*.BACKUP.*
*.LOCAL.*
*.REMOTE.*
# Components #
##############
/build
/components

View File

@@ -1 +1,3 @@
coverage
test
.travis.yml

View File

@@ -2,3 +2,10 @@ language: node_js
node_js:
- "0.8"
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
fast_finish: true
script: "npm run-script test-travis"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"

45
History.md Normal file
View File

@@ -0,0 +1,45 @@
1.1.3 / 2014-06-20
==================
* deps: accepts@~1.0.4
- use `mime-types`
1.1.2 / 2014-06-19
==================
* deps: batch@0.5.1
1.1.1 / 2014-06-11
==================
* deps: accepts@1.0.3
1.1.0 / 2014-05-29
==================
* Fix content negotiation when no `Accept` header
* Properly support all HTTP methods
* Support vanilla node.js http servers
* Treat `ENAMETOOLONG` as code 414
* Use accepts for negotiation
1.0.3 / 2014-05-20
==================
* Fix error from non-statable files in HTML view
1.0.2 / 2014-04-28
==================
* Add `stylesheet` option
* deps: negotiator@0.4.3
1.0.1 / 2014-03-05
==================
* deps: negotiator@0.4.2
1.0.0 / 2014-03-05
==================
* Genesis from connect

View File

@@ -1,19 +1,41 @@
# Serve Index
# serve-index
Previously `connect.directory()`.
[![NPM version](https://badge.fury.io/js/serve-index.svg)](http://badge.fury.io/js/serve-index)
[![Build Status](https://travis-ci.org/expressjs/serve-index.svg?branch=master)](https://travis-ci.org/expressjs/serve-index)
[![Coverage Status](https://img.shields.io/coveralls/expressjs/serve-index.svg?branch=master)](https://coveralls.io/r/expressjs/serve-index)
Usage:
Serves pages that contain directory listings for a given path.
## API
```js
var connect = require('connect');
var serveIndex = require('serve-index');
var express = require('express')
var serveIndex = require('serve-index')
var app = connect();
var app = express()
app.use(serveIndex('public/ftp', {'icons': true}));
app.listen();
app.use(serveIndex('public/ftp', {'icons': true}))
app.listen()
```
### serveIndex(path, options)
Returns middlware that serves an index of the directory in the given `path`.
#### Options
- `hidden` - display hidden (dot) files. Defaults to `false`.
- `view` - display mode. `tiles` and `details` are available. Defaults to `tiles`.
- `icons` - display icons. Defaults to `false`.
- `filter` - Apply this filter function to files. Defaults to `false`.
- `stylesheet` - Optional path to a CSS stylesheet. Defaults to a built-in stylesheet.
- `template` - Optional path to an HTML template. Defaults to a built-in template.
- The following tokens are replaced in templates:
- `{directory}` with the name of the directory.
- `{files}` with the HTML of an unordered list of file links.
- `{linked-path}` with the HTML of a link to the directory.
- `{style}` with the specified stylesheet and embedded images.
## License
The MIT License (MIT)
@@ -37,3 +59,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons are created
by/copyright of [FAMFAMFAM](http://www.famfamfam.com/).

View File

@@ -1,6 +1,6 @@
/*!
* Connect - directory
* serve-index
* Copyright(c) 2011 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2014 Douglas Christopher Wilson
@@ -14,6 +14,7 @@
* Module dependencies.
*/
var accepts = require('accepts');
var http = require('http')
, fs = require('fs')
, parse = require('url').parse
@@ -23,7 +24,6 @@ var http = require('http')
, extname = path.extname
, join = path.join;
var Batch = require('batch');
var Negotiator = require('negotiator');
/*!
* Icon cache.
@@ -41,7 +41,7 @@ var defaultTemplate = join(__dirname, 'public', 'directory.html');
* Stylesheet.
*/
var stylesheet = join(__dirname, 'public', 'style.css');
var defaultStylesheet = join(__dirname, 'public', 'style.css');
/**
* Media types and the map for content negotiation.
@@ -60,47 +60,44 @@ var mediaType = {
};
/**
* Directory:
*
* Serve directory listings with the given `root` path.
*
* Options:
* See Readme.md for documentation of options.
*
* - `hidden` display hidden (dot) files. Defaults to false.
* - `icons` display icons. Defaults to false.
* - `filter` Apply this filter function to files. Defaults to false.
* - `template` Optional path to html template. Defaults to a built-in template.
* The following tokens are replaced:
* - `{directory}` with the name of the directory.
* - `{files}` with the HTML of an unordered list of file links.
* - `{linked-path}` with the HTML of a link to the directory.
* - `{style}` with the built-in CSS and embedded images.
*
* @param {String} root
* @param {String} path
* @param {Object} options
* @return {Function}
* @return {Function} middleware
* @api public
*/
exports = module.exports = function directory(root, options){
exports = module.exports = function serveIndex(root, options){
options = options || {};
// root required
if (!root) throw new Error('directory() root path required');
if (!root) throw new TypeError('serveIndex() root path required');
var hidden = options.hidden
, icons = options.icons
, view = options.view || 'tiles'
, filter = options.filter
, root = normalize(root + sep)
, template = options.template || defaultTemplate;
, template = options.template || defaultTemplate
, stylesheet = options.stylesheet || defaultStylesheet;
return function directory(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
return function serveIndex(req, res, next) {
if (req.method !== 'GET' && req.method !== 'HEAD') {
res.statusCode = 'OPTIONS' === req.method
? 200
: 405;
res.setHeader('Allow', 'GET, HEAD, OPTIONS');
res.end();
return;
}
var url = parse(req.url)
, dir = decodeURIComponent(url.pathname)
, path = normalize(join(root, dir))
, originalUrl = parse(req.originalUrl)
, originalUrl = parse(req.originalUrl || req.url)
, originalDir = decodeURIComponent(originalUrl.pathname)
, showUp = path != root;
@@ -112,9 +109,16 @@ exports = module.exports = function directory(root, options){
// check if we have a directory
fs.stat(path, function(err, stat){
if (err) return 'ENOENT' == err.code
? next()
: next(err);
if (err && err.code === 'ENOENT') {
return next();
}
if (err) {
err.status = err.code === 'ENAMETOOLONG'
? 414
: 500;
return next(err);
}
if (!stat.isDirectory()) return next();
@@ -126,11 +130,12 @@ exports = module.exports = function directory(root, options){
files.sort();
// content-negotiation
var type = new Negotiator(req).preferredMediaType(mediaTypes);
var accept = accepts(req);
var type = accept.types(mediaTypes);
// not acceptable
if (!type) return next(createError(406));
exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template);
exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template, stylesheet);
});
});
};
@@ -140,7 +145,7 @@ exports = module.exports = function directory(root, options){
* Respond with text/html.
*/
exports.html = function(req, res, files, next, dir, showUp, icons, path, view, template){
exports.html = function(req, res, files, next, dir, showUp, icons, path, view, template, stylesheet){
fs.readFile(template, 'utf8', function(err, str){
if (err) return next(err);
fs.readFile(stylesheet, 'utf8', function(err, style){
@@ -292,9 +297,12 @@ function html(files, dir, useIcons, view) {
path.push(encodeURIComponent(file.name));
var date = file.name == '..' ? ''
: file.stat.mtime.toDateString()+' '+file.stat.mtime.toLocaleTimeString();
var size = isDir ? '' : file.stat.size;
var date = file.stat && file.name !== '..'
? file.stat.mtime.toDateString() + ' ' + file.stat.mtime.toLocaleTimeString()
: '';
var size = file.stat && !isDir
? file.stat.size
: '';
return '<li><a href="'
+ normalizeSlashes(normalize(path.join('/')))
@@ -362,7 +370,14 @@ function stat(dir, files, cb) {
files.forEach(function(file){
batch.push(function(done){
fs.stat(join(dir, file), done);
fs.stat(join(dir, file), function(err, stat){
if (err && err.code !== 'ENOENT') {
// pass ENOENT as null stat, not error
return done(err);
}
done(null, stat || null);
});
});
});

View File

@@ -1,30 +1,26 @@
{
"name": "serve-index",
"description": "Serve directory listings",
"version": "1.0.0",
"version": "1.1.3",
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/serve-index.git"
},
"bugs": {
"url": "https://github.com/expressjs/serve-index/issues"
},
"repository": "expressjs/serve-index",
"dependencies": {
"batch": "0.5.0",
"negotiator": "0.3.0"
"accepts": "1.0.4",
"batch": "0.5.1"
},
"devDependencies": {
"connect": "^2.13.0",
"mocha": "^1.17.0",
"should": "^3.0.0",
"supertest": "~0.9.0"
"istanbul": "0.2.10",
"mocha": "~1.20.0",
"should": "~4.0.0",
"supertest": "~0.13.0"
},
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"test": "mocha --reporter spec --require should"
"test": "mocha --reporter dot",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec"
}
}

3
test/shared/styles.css Normal file
View File

@@ -0,0 +1,3 @@
body {
color: #00ff00;
}

View File

@@ -1,41 +1,120 @@
process.env.NODE_ENV = 'test';
var connect = require('connect');
var http = require('http');
var fs = require('fs');
var request = require('supertest');
var should = require('should');
var serveIndex = require('..');
describe('directory()', function(){
describe('when given Accept: header', function () {
var server;
before(function () {
server = createServer();
});
after(function (done) {
server.close(done);
});
describe('serveIndex(root)', function () {
it('should require root', function () {
serveIndex.should.throw(/root path required/)
})
describe('of application/json', function () {
it('should serve text/html without Accept header', function (done) {
var server = createServer()
request(server)
.get('/')
.expect('Content-Type', 'text/html')
.expect(200, done)
})
it('should serve a directory index', function (done) {
var server = createServer()
request(server)
.get('/')
.expect(200, /todo\.txt/, done)
})
it('should work with HEAD requests', function (done) {
var server = createServer()
request(server)
.head('/')
.expect(200, '', done)
})
it('should work with OPTIONS requests', function (done) {
var server = createServer()
request(server)
.options('/')
.expect('Allow', 'GET, HEAD, OPTIONS')
.expect(200, done)
})
it('should deny POST requests', function (done) {
var server = createServer()
request(server)
.post('/')
.expect(405, done)
})
it('should deny path will NULL byte', function (done) {
var server = createServer()
request(server)
.get('/%00')
.expect(400, done)
})
it('should deny path outside root', function (done) {
var server = createServer()
request(server)
.get('/../')
.expect(403, done)
})
it('should skip non-existent paths', function (done) {
var server = createServer()
request(server)
.get('/bogus')
.expect(404, 'Not Found', done)
})
it('should treat an ENAMETOOLONG as a 414', function (done) {
var path = Array(11000).join('foobar')
var server = createServer()
request(server)
.get('/' + path)
.expect(414, done)
})
it('should skip non-directories', function (done) {
var server = createServer()
request(server)
.get('/nums')
.expect(404, 'Not Found', done)
})
describe('when given Accept: header', function () {
describe('when Accept: application/json is given', function () {
it('should respond with json', function (done) {
var server = createServer()
request(server)
.get('/')
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end(function (err, res) {
if (err) throw err;
res.body.should.include('g# %3 o %2525 %37 dir');
res.body.should.include('users');
res.body.should.include('file #1.txt');
res.body.should.include('nums');
res.body.should.include('todo.txt');
done();
});
.expect(/g# %3 o %2525 %37 dir/)
.expect(/users/)
.expect(/file #1\.txt/)
.expect(/nums/)
.expect(/todo\.txt/)
.expect(200, done)
});
});
describe('when Accept: text/html is given', function () {
it('should respond with html', function (done) {
var server = createServer()
request(server)
.get('/')
.set('Accept', 'text/html')
@@ -49,6 +128,8 @@ describe('directory()', function(){
});
it('should sort folders first', function (done) {
var server = createServer()
request(server)
.get('/')
.set('Accept', 'text/html')
@@ -73,6 +154,8 @@ describe('directory()', function(){
describe('when Accept: text/plain is given', function () {
it('should respond with text', function (done) {
var server = createServer()
request(server)
.get('/')
.set('Accept', 'text/plain')
@@ -85,18 +168,253 @@ describe('directory()', function(){
.end(done);
});
});
describe('when Accept: application/x-bogus is given', function () {
it('should respond with 406', function (done) {
var server = createServer()
request(server)
.get('/')
.set('Accept', 'application/x-bogus')
.expect(406, done)
});
});
});
describe('with "hidden" option', function () {
it('should filter hidden files by default', function (done) {
var server = createServer()
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
res.text.should.not.containEql('.hidden')
done()
});
});
it('should filter hidden files', function (done) {
var server = createServer('test/fixtures', {'hidden': false})
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
res.text.should.not.containEql('.hidden')
done()
});
});
it('should not filter hidden files', function (done) {
var server = createServer('test/fixtures', {'hidden': true})
request(server)
.get('/')
.expect(200, /\.hidden/, done)
});
});
describe('with "filter" option', function () {
it('should custom filter files', function (done) {
var seen = false
var server = createServer('test/fixtures', {'filter': filter})
function filter(name) {
if (name.indexOf('foo') === -1) return true
seen = true
return false
}
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
seen.should.be.true
res.text.should.not.containEql('foo')
done()
});
});
it('should filter after hidden filter', function (done) {
var seen = false
var server = createServer('test/fixtures', {'filter': filter, 'hidden': false})
function filter(name) {
seen = seen || name.indexOf('.') === 0
return true
}
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
seen.should.be.false
done()
});
});
});
describe('with "icons" option', function () {
it('should include icons for html', function (done) {
var server = createServer('test/fixtures', {'icons': true})
request(server)
.get('/')
.expect(/data:image\/png/)
.expect(/icon-default/)
.expect(/icon-directory/)
.expect(/icon-txt/)
.expect(200, done)
});
});
describe('when using custom handler', function () {
describe('exports.html', function () {
var orig = serveIndex.html
after(function () {
serveIndex.html = orig
})
it('should get called with Accept: text/html', function (done) {
var server = createServer()
serveIndex.html = function (req, res, files) {
res.setHeader('Content-Type', 'text/html');
res.end('called');
}
request(server)
.get('/')
.set('Accept', 'text/html')
.expect(200, 'called', done)
});
it('should get file list', function (done) {
var server = createServer()
serveIndex.html = function (req, res, files) {
var text = files
.filter(function (f) { return /\.txt$/.test(f) })
.sort()
res.setHeader('Content-Type', 'text/html')
res.end('<b>' + text.length + ' text files</b>')
}
request(server)
.get('/')
.set('Accept', 'text/html')
.expect(200, '<b>2 text files</b>', done)
});
it('should get dir name', function (done) {
var server = createServer()
serveIndex.html = function (req, res, files, next, dir) {
res.setHeader('Content-Type', 'text/html')
res.end('<b>' + dir + '</b>')
}
request(server)
.get('/users/')
.set('Accept', 'text/html')
.expect(200, '<b>/users/</b>', done)
});
it('should get template path', function (done) {
var server = createServer()
serveIndex.html = function (req, res, files, next, dir, showUp, icons, path, view, template) {
res.setHeader('Content-Type', 'text/html')
res.end(String(fs.existsSync(template)))
}
request(server)
.get('/users/')
.set('Accept', 'text/html')
.expect(200, 'true', done)
});
it('should get template with tokens', function (done) {
var server = createServer()
serveIndex.html = function (req, res, files, next, dir, showUp, icons, path, view, template) {
res.setHeader('Content-Type', 'text/html')
res.end(fs.readFileSync(template, 'utf8'))
}
request(server)
.get('/users/')
.set('Accept', 'text/html')
.expect(/{directory}/)
.expect(/{files}/)
.expect(/{linked-path}/)
.expect(/{style}/)
.expect(200, done)
});
it('should get stylesheet path', function (done) {
var server = createServer()
serveIndex.html = function (req, res, files, next, dir, showUp, icons, path, view, template, stylesheet) {
res.setHeader('Content-Type', 'text/html')
res.end(String(fs.existsSync(stylesheet)))
}
request(server)
.get('/users/')
.set('Accept', 'text/html')
.expect(200, 'true', done)
});
});
describe('exports.plain', function () {
var orig = serveIndex.plain
after(function () {
serveIndex.plain = orig
})
it('should get called with Accept: text/plain', function (done) {
var server = createServer()
serveIndex.plain = function (req, res, files) {
res.setHeader('Content-Type', 'text/plain');
res.end('called');
}
request(server)
.get('/')
.set('Accept', 'text/plain')
.expect(200, 'called', done)
});
});
describe('exports.json', function () {
var orig = serveIndex.json
after(function () {
serveIndex.json = orig
})
it('should get called with Accept: application/json', function (done) {
var server = createServer()
serveIndex.json = function (req, res, files) {
res.setHeader('Content-Type', 'application/json');
res.end('"called"');
}
request(server)
.get('/')
.set('Accept', 'application/json')
.expect(200, '"called"', done)
});
});
});
describe('when navigating to other directory', function () {
var server;
before(function () {
server = createServer();
});
after(function (done) {
server.close(done);
});
it('should respond with correct listing', function (done) {
var server = createServer()
request(server)
.get('/users/')
.set('Accept', 'text/html')
@@ -108,6 +426,8 @@ describe('directory()', function(){
});
it('should work for directory with #', function (done) {
var server = createServer()
request(server)
.get('/%23directory/')
.set('Accept', 'text/html')
@@ -119,6 +439,8 @@ describe('directory()', function(){
});
it('should work for directory with special chars', function (done) {
var server = createServer()
request(server)
.get('/g%23%20%253%20o%20%252525%20%2537%20dir/')
.set('Accept', 'text/html')
@@ -130,6 +452,8 @@ describe('directory()', function(){
});
it('should not work for outside root', function (done) {
var server = createServer()
request(server)
.get('/../support/')
.set('Accept', 'text/html')
@@ -142,21 +466,46 @@ describe('directory()', function(){
before(function () {
server = createServer('test/fixtures', {'template': __dirname + '/shared/template.html'});
});
after(function (done) {
server.close(done);
it('should respond with file list', function (done) {
request(server)
.get('/')
.set('Accept', 'text/html')
.expect(/<a href="\/g%23%20%253%20o%20%252525%20%2537%20dir"/)
.expect(/<a href="\/users"/)
.expect(/<a href="\/file%20%231.txt"/)
.expect(/<a href="\/todo.txt"/)
.expect(200, done)
});
it('should respond with file list and testing template sentence', function (done) {
it('should respond with testing template sentence', function (done) {
request(server)
.get('/')
.set('Accept', 'text/html')
.expect(200, /This is the test template/, done)
});
it('should have default styles', function (done) {
request(server)
.get('/')
.set('Accept', 'text/html')
.expect(200, /ul#files/, done)
});
});
describe('when setting a custom stylesheet', function () {
var server;
before(function () {
server = createServer('test/fixtures', {'stylesheet': __dirname + '/shared/styles.css'});
});
it('should respond with appropriate embedded styles', function (done) {
request(server)
.get('/')
.set('Accept', 'text/html')
.expect(200)
.expect('Content-Type', /html/)
.expect(/<a href="\/g%23%20%253%20o%20%252525%20%2537%20dir"/)
.expect(/<a href="\/users"/)
.expect(/<a href="\/file%20%231.txt"/)
.expect(/<a href="\/todo.txt"/)
.expect(/This is the test template/)
.expect(/color: #00ff00;/)
.end(done);
});
});
@@ -166,24 +515,17 @@ describe('directory()', function(){
before(function () {
server = createServer('test/fixtures/');
});
after(function (done) {
server.close(done);
});
it('should respond with file list', function (done) {
request(server)
.get('/')
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end(function (err, res) {
if (err) throw err;
res.body.should.include('users');
res.body.should.include('file #1.txt');
res.body.should.include('nums');
res.body.should.include('todo.txt');
done();
});
.expect(/users/)
.expect(/file #1\.txt/)
.expect(/nums/)
.expect(/todo\.txt/)
.expect(200, done)
});
});
@@ -192,23 +534,16 @@ describe('directory()', function(){
before(function () {
server = createServer('.');
});
after(function (done) {
server.close(done);
});
it('should respond with file list', function (done) {
request(server)
.get('/')
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end(function (err, res) {
if (err) throw err;
res.body.should.include('LICENSE');
res.body.should.include('public');
res.body.should.include('test');
done();
});
.expect(/LICENSE/)
.expect(/public/)
.expect(/test/)
.expect(200, done)
});
it('should not allow serving outside root', function (done) {
@@ -221,8 +556,14 @@ describe('directory()', function(){
});
function createServer(dir, opts) {
var app = connect();
dir = dir || 'test/fixtures';
app.use(serveIndex(dir, opts));
return app.listen();
dir = dir || 'test/fixtures'
var _serveIndex = serveIndex(dir, opts)
return http.createServer(function (req, res) {
_serveIndex(req, res, function (err) {
res.statusCode = err ? (err.status || 500) : 404
res.end(err ? err.message : 'Not Found')
})
})
}