diff --git a/index.js b/index.js index dd9010b..55b5637 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,8 @@ var QCore = function() { this.index_parts = []; this.last_part = { start: 0, end: 0 }; + this.etags = {}; // etags cache, obj: uri { etag: '...', timestamp: } + this.res_cache = {}; // resource cache ('/view.png' => '03xc345'); this.rules = {}; @@ -428,17 +430,29 @@ qwiki.act('', function(req, res) { var path = 'wiki/'+req.url; fs.stat(path, function(err, stat) { if (err == null) { - res.writeHead(200, "OK", { - "Content-Type": mimetype, - "Content-Length": stat.size - }); - var rs = fs.createReadStream(path); - rs.on('data', function(chunk) { - res.write(chunk); - }); - rs.on('end', function() { + // TODO: etags should actually be based on binary data(CRC32, etc.), not last modified + // TODO: files should not be stat()`d each call, but should be cached and updated when the file updates (how? browser-based upload interface?) + var mtime = stat.mtime.getTime(); + if (!(path in qwiki.etags) || qwiki.etags[path] != mtime) { + qwiki.etags[path] = mtime; + } + if ('if-none-match' in req.headers && req.headers['if-none-match'] == qwiki.etags[path]) { + res.writeHead(304, "Not Modified"); res.end(); - }); + } else { + res.writeHead(200, "OK", { + "Content-Type": mimetype, + "Content-Length": stat.size, + "ETag": mtime + }); + var rs = fs.createReadStream(path); + rs.on('data', function(chunk) { + res.write(chunk); + }); + rs.on('end', function() { + res.end(); + }); + } } else if (err.code == 'ENOENT') { res.writeHead(404); res.end();