mirror of
https://github.com/seejohnrun/haste-server
synced 2025-07-14 17:13:45 -07:00
Added node modules
This commit is contained in:
parent
ca9d4c18f7
commit
d1e0644a4e
575 changed files with 77900 additions and 6 deletions
225
node_modules/connect/lib/middleware/static.js
generated
vendored
Normal file
225
node_modules/connect/lib/middleware/static.js
generated
vendored
Normal file
|
@ -0,0 +1,225 @@
|
|||
|
||||
/*!
|
||||
* Connect - staticProvider
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, join = path.join
|
||||
, basename = path.basename
|
||||
, normalize = path.normalize
|
||||
, utils = require('../utils')
|
||||
, Buffer = require('buffer').Buffer
|
||||
, parse = require('url').parse
|
||||
, mime = require('mime');
|
||||
|
||||
/**
|
||||
* Static file server with the given `root` path.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var oneDay = 86400000;
|
||||
*
|
||||
* connect(
|
||||
* connect.static(__dirname + '/public')
|
||||
* ).listen(3000);
|
||||
*
|
||||
* connect(
|
||||
* connect.static(__dirname + '/public', { maxAge: oneDay })
|
||||
* ).listen(3000);
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
|
||||
* - `hidden` Allow transfer of hidden files. defaults to false
|
||||
* - `redirect` Redirect to trailing "/" when the pathname is a dir
|
||||
*
|
||||
* @param {String} root
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function static(root, options){
|
||||
options = options || {};
|
||||
|
||||
// root required
|
||||
if (!root) throw new Error('static() root path required');
|
||||
options.root = root;
|
||||
|
||||
return function static(req, res, next) {
|
||||
options.path = req.url;
|
||||
options.getOnly = true;
|
||||
send(req, res, next, options);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose mime module.
|
||||
*/
|
||||
|
||||
exports.mime = mime;
|
||||
|
||||
/**
|
||||
* Respond with 416 "Requested Range Not Satisfiable"
|
||||
*
|
||||
* @param {ServerResponse} res
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function invalidRange(res) {
|
||||
var body = 'Requested Range Not Satisfiable';
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.setHeader('Content-Length', body.length);
|
||||
res.statusCode = 416;
|
||||
res.end(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to tranfer the requseted file to `res`.
|
||||
*
|
||||
* @param {ServerRequest}
|
||||
* @param {ServerResponse}
|
||||
* @param {Function} next
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
var send = exports.send = function(req, res, next, options){
|
||||
options = options || {};
|
||||
if (!options.path) throw new Error('path required');
|
||||
|
||||
// setup
|
||||
var maxAge = options.maxAge || 0
|
||||
, ranges = req.headers.range
|
||||
, head = 'HEAD' == req.method
|
||||
, get = 'GET' == req.method
|
||||
, root = options.root ? normalize(options.root) : null
|
||||
, redirect = false === options.redirect ? false : true
|
||||
, getOnly = options.getOnly
|
||||
, fn = options.callback
|
||||
, hidden = options.hidden
|
||||
, done;
|
||||
|
||||
// replace next() with callback when available
|
||||
if (fn) next = fn;
|
||||
|
||||
// ignore non-GET requests
|
||||
if (getOnly && !get && !head) return next();
|
||||
|
||||
// parse url
|
||||
var url = parse(options.path)
|
||||
, path = decodeURIComponent(url.pathname)
|
||||
, type;
|
||||
|
||||
// null byte(s)
|
||||
if (~path.indexOf('\0')) return utils.badRequest(res);
|
||||
|
||||
// when root is not given, consider .. malicious
|
||||
if (!root && ~path.indexOf('..')) return utils.forbidden(res);
|
||||
|
||||
// join / normalize from optional root dir
|
||||
path = normalize(join(root, path));
|
||||
|
||||
// malicious path
|
||||
if (root && 0 != path.indexOf(root)) return fn
|
||||
? fn(new Error('Forbidden'))
|
||||
: utils.forbidden(res);
|
||||
|
||||
// index.html support
|
||||
if (normalize('/') == path[path.length - 1]) path += 'index.html';
|
||||
|
||||
// "hidden" file
|
||||
if (!hidden && '.' == basename(path)[0]) return next();
|
||||
|
||||
fs.stat(path, function(err, stat){
|
||||
// mime type
|
||||
type = mime.lookup(path);
|
||||
|
||||
// ignore ENOENT
|
||||
if (err) {
|
||||
if (fn) return fn(err);
|
||||
return 'ENOENT' == err.code
|
||||
? next()
|
||||
: next(err);
|
||||
// redirect directory in case index.html is present
|
||||
} else if (stat.isDirectory()) {
|
||||
if (!redirect) return next();
|
||||
res.statusCode = 301;
|
||||
res.setHeader('Location', url.pathname + '/');
|
||||
res.end('Redirecting to ' + url.pathname + '/');
|
||||
return;
|
||||
}
|
||||
|
||||
// header fields
|
||||
if (!res.getHeader('Date')) res.setHeader('Date', new Date().toUTCString());
|
||||
if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (maxAge / 1000));
|
||||
if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString());
|
||||
if (!res.getHeader('ETag')) res.setHeader('ETag', utils.etag(stat));
|
||||
if (!res.getHeader('content-type')) {
|
||||
var charset = mime.charsets.lookup(type);
|
||||
res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
|
||||
}
|
||||
res.setHeader('Accept-Ranges', 'bytes');
|
||||
|
||||
// conditional GET support
|
||||
if (utils.conditionalGET(req)) {
|
||||
if (!utils.modified(req, res)) {
|
||||
req.emit('static');
|
||||
return utils.notModified(res);
|
||||
}
|
||||
}
|
||||
|
||||
var opts = {};
|
||||
var chunkSize = stat.size;
|
||||
|
||||
// we have a Range request
|
||||
if (ranges) {
|
||||
ranges = utils.parseRange(stat.size, ranges);
|
||||
// valid
|
||||
if (ranges) {
|
||||
// TODO: stream options
|
||||
// TODO: multiple support
|
||||
opts.start = ranges[0].start;
|
||||
opts.end = ranges[0].end;
|
||||
chunkSize = opts.end - opts.start + 1;
|
||||
res.statusCode = 206;
|
||||
res.setHeader('Content-Range', 'bytes '
|
||||
+ opts.start
|
||||
+ '-'
|
||||
+ opts.end
|
||||
+ '/'
|
||||
+ stat.size);
|
||||
// invalid
|
||||
} else {
|
||||
return fn
|
||||
? fn(new Error('Requested Range Not Satisfiable'))
|
||||
: invalidRange(res);
|
||||
}
|
||||
}
|
||||
|
||||
res.setHeader('Content-Length', chunkSize);
|
||||
|
||||
// transfer
|
||||
if (head) return res.end();
|
||||
|
||||
// stream
|
||||
var stream = fs.createReadStream(path, opts);
|
||||
req.emit('static', stream);
|
||||
stream.pipe(res);
|
||||
|
||||
// callback
|
||||
if (fn) {
|
||||
function callback(err) { done || fn(err); done = true }
|
||||
req.on('close', callback);
|
||||
stream.on('end', callback);
|
||||
}
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue