diff --git a/README.md b/README.md index 825c811..1ef61b7 100644 --- a/README.md +++ b/README.md @@ -118,24 +118,30 @@ If you only want to *listen* for errors, you can use *event listeners*: With this method, you don't have to explicitly send the response back, in case of an error. -### Options when creating an instance of `Server` # +### Setting rfc2616 Cache Options Options # +Controling caching is an important part of optimizing your static file server. In node-static a subset of the rfc2616 `Cache-Control` headers are exposed. -#### `cache` # +To enable caching set the cache options when creating a node-static server: -Sets the `Cache-Control` header. + var cacheServer = new static.Server('./public', { cache: 7200 }); -example: `{ cache: 7200 }` +* Passing a number will set the cache duration to that number of seconds. +* Passing `false` will disable the `Cache-Control` header. +* Default value is `3600` -Passing a number will set the cache duration to that number of seconds. -Passing `false` will disable the `Cache-Control` header. +There are additional options you can pass which set additional optional components of the [rfc2616 Cache-Control header][0]: -> Defaults to `3600` +* `revalidate`: Sets 'must-revalidate' which tells caches that they must obey any freshness information you give them about a representation. HTTP allows caches to serve stale representations under special conditions; by specifying this header, you’re telling the cache that you want it to strictly follow your rules. [Source][1] +* `public`: Sets 'public' which marks authenticated responses as cacheable; normally, if HTTP authentication is required, responses are automatically private. [Source][1] +* `private`: Sets 'private' which allows caches that are specific to one user (e.g., in a browser) to store the response; shared caches (e.g., in a proxy) may not. [Source][1] -#### `headers` # +### Setting Custom Response Headers -Sets response headers. +It is possible to set custom response headers by setting the `headers` option when creating an instance of a node-static Server. -example: `{ 'X-Hello': 'World!' }` + var server = new static.Server('./public', { 'X-Hello': 'World!' }); -> defaults to `{}` +* defaults to `{}` +[0]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 +[1]: http://www.mnot.net/cache_docs/ \ No newline at end of file diff --git a/examples/file-server.js b/examples/file-server.js index a12c43b..38dc965 100644 --- a/examples/file-server.js +++ b/examples/file-server.js @@ -4,7 +4,7 @@ var static = require('../lib/node-static'); // // Create a node-static server to serve the current directory // -var file = new(static.Server)('.', { cache: 7200, headers: {'X-Hello':'World!'} }); +var file = new(static.Server)('.', { cache: 7200, revalidate: true, public: true, headers: {'X-Hello':'World!'} }); require('http').createServer(function (request, response) { request.addListener('end', function () { diff --git a/lib/node-static.js b/lib/node-static.js index 4335768..9995678 100644 --- a/lib/node-static.js +++ b/lib/node-static.js @@ -20,6 +20,7 @@ this.indexStore = {}; this.Server = function (root, options) { if (root && (typeof(root) === 'object')) { options = root, root = null } + var that = this; this.root = path.normalize(root || '.'); this.options = options || {}; this.cache = 3600; @@ -27,16 +28,29 @@ this.Server = function (root, options) { this.defaultHeaders = {}; this.options.headers = this.options.headers || {}; - if ('cache' in this.options) { - if (typeof(this.options.cache) === 'number') { - this.cache = this.options.cache; - } else if (! this.options.cache) { - this.cache = false; + if (this.cache in this.options) { + function setCacheOption (option, type, def) { + that[option] = typeof(that.options[option]) === type ? that.options[option] : def; } + + setCacheOption('cache', 'number', false); + setCacheOption('revalidate', 'boolean', false); + setCacheOption('public', 'boolean', false); + setCacheOption('private', 'boolean', false); } if (this.cache !== false) { - this.defaultHeaders['Cache-Control'] = 'max-age=' + this.cache; + function setCacheControl(expr, value) { + if (expr) cacheControl.push(value); + } + + var cacheControl = []; + setCacheControl(this.public === true && !this.private, 'public'); + setCacheControl(this.private === true && !this.public, 'private'); + setCacheControl(true, 'max-age=' + this.cache); + setCacheControl(this.revalidate === true, 'must-revalidate'); + + this.defaultHeaders['Cache-Control'] = cacheControl.join(', '); } this.defaultHeaders['Server'] = serverInfo; @@ -230,7 +244,8 @@ this.Server.prototype.stream = function (pathname, files, buffer, res, callback) if (file) { // Stream the file to the client - fs.createReadStream(path.join(pathname || '.', file), { + var target = file[0] === '/' ? file : path.join(pathname || '.', file); + fs.createReadStream(target, { flags: 'r', mode: 0666 }).on('data', function (chunk) {