socketioMEANseed/server/node_modules/serve-static/index.js
server/node_modules/serve-static/index.jsRaw
1/*!
2 * serve-static
3 * Copyright(c) 2010 Sencha Inc.
4 * Copyright(c) 2011 TJ Holowaychuk
5 * Copyright(c) 2014 Douglas Christopher Wilson
6 * MIT Licensed
7 */
8
9/**
10 * Module dependencies.
11 */
12
13var escapeHtml = require('escape-html');
14var merge = require('utils-merge');
15var parseurl = require('parseurl');
16var resolve = require('path').resolve;
17var send = require('send');
18var url = require('url');
19
20/**
21 * @param {String} root
22 * @param {Object} options
23 * @return {Function}
24 * @api public
25 */
26
27exports = module.exports = function serveStatic(root, options) {
28 if (!root) {
29 throw new TypeError('root path required')
30 }
31
32 if (typeof root !== 'string') {
33 throw new TypeError('root path must be a string')
34 }
35
36 // copy options object
37 options = merge({}, options)
38
39 // resolve root to absolute
40 root = resolve(root)
41
42 // default redirect
43 var redirect = options.redirect !== false
44
45 // headers listener
46 var setHeaders = options.setHeaders
47 delete options.setHeaders
48
49 if (setHeaders && typeof setHeaders !== 'function') {
50 throw new TypeError('option setHeaders must be function')
51 }
52
53 // setup options for send
54 options.maxage = options.maxage || options.maxAge || 0
55 options.root = root
56
57 return function serveStatic(req, res, next) {
58 if (req.method !== 'GET' && req.method !== 'HEAD') {
59 return next()
60 }
61
62 var opts = merge({}, options)
63 var originalUrl = parseurl.original(req)
64 var path = parseurl(req).pathname
65 var hasTrailingSlash = originalUrl.pathname[originalUrl.pathname.length - 1] === '/'
66
67 if (path === '/' && !hasTrailingSlash) {
68 // make sure redirect occurs at mount
69 path = ''
70 }
71
72 // create send stream
73 var stream = send(req, path, opts)
74
75 if (redirect) {
76 // redirect relative to originalUrl
77 stream.on('directory', function redirect() {
78 if (hasTrailingSlash) {
79 return next()
80 }
81
82 // append trailing slash
83 originalUrl.pathname = collapseLeadingSlashes(originalUrl.pathname + '/')
84
85 // reformat the URL
86 var target = url.format(originalUrl)
87
88 // send redirect response
89 res.statusCode = 303
90 res.setHeader('Content-Type', 'text/html; charset=utf-8')
91 res.setHeader('Location', target)
92 res.end('Redirecting to <a href="' + escapeHtml(target) + '">' + escapeHtml(target) + '</a>\n')
93 })
94 } else {
95 // forward to next middleware on directory
96 stream.on('directory', next)
97 }
98
99 // add headers listener
100 if (setHeaders) {
101 stream.on('headers', setHeaders)
102 }
103
104 // forward non-404 errors
105 stream.on('error', function error(err) {
106 next(err.status === 404 ? null : err)
107 })
108
109 // pipe
110 stream.pipe(res)
111 }
112}
113
114/**
115 * Expose mime module.
116 *
117 * If you wish to extend the mime table use this
118 * reference to the "mime" module in the npm registry.
119 */
120
121exports.mime = send.mime
122
123/**
124 * Collapse all leading slashes into a single slash
125 * @private
126 */
127function collapseLeadingSlashes(str) {
128 for (var i = 0; i < str.length; i++) {
129 if (str[i] !== '/') {
130 break
131 }
132 }
133
134 return i > 1
135 ? '/' + str.substr(i)
136 : str
137}