Permalink
Browse files

a

  • Loading branch information...
1 parent 2bfe45e commit db87c16b7275f33b2eae89279312e2d589eff42b @omphalos committed Sep 13, 2012
@@ -0,0 +1,3 @@
+{"ts":1347314469903,"silentsave":true,"restoring":false,"patch":[[{"diffs":[[1,"[![build status](https://secure.travis-ci.org/omphalos/crud-file-server.png)](http://travis-ci.org/omphalos/crud-file-server)\ncrud-file-server\n================\n\nThis package exposes a directory and its children to create, read, update, and delete operations over http.\nAdditionally, it supports change notification over faye.\n\nCommand-line usage\n==================\n\n crud-file-server [options]\n\nThis starts a file server using the specified command-line options.\n\n -f file system path to expose over http\n\t-h log head requests\n\t-m vpath to use to mount the faye server (omit to disable publication)\n -p port to listen on (example, 80)\n -q suppress this message\n\t-r read only\n -v virtual path to host the file server on\t\n\t\nExample:\n\n crud-file-server -f c:/ -p 8080 -q -m /faye -v filez\t\n\nSupported operations\n====================\n\n**GET** returns a file's contents with the correct mime type, or else the contents of a directory as html.\n\n**GET** http://localhost?type=json formats content as json instead of the default type. This works for directories and files.\n\n**HEAD** is the same as a GET, omitting the body.\n\n**PUT** can be used to write a file.\n\n**DELETE** can be used to delete a file or folder.\n\n**POST** supports two operations, rename and create directory. \n\n**POST** http://localhost/newDir?create=directory would create a directory named newDir. \n\n**POST** http://localhost/abc.html?rename=def.html would rename abc.html to def.html.\n\nRun the Example\n===============\n\nFor further clarification, try running the example.\n\n npm install crud-file-server\n\nNavigate to the example directory (which should now be under node_modules/crud-file-server/example).\n\n\tcd node_modules/crud-file-server/example\n\nRun crud-file-server to host the current directory. \n\n crud-file-server -p 3300\n \t\nNow use your browser to navigate to http://localhost:3300/example.html. \nYou will see a simple client that lets you interact with your file system from the web browser.\n"]],"start1":0,"start2":0,"length1":0,"length2":1996}]],"length":1996}
+{"contributors":[],"silentsave":false,"ts":1347314475728,"patch":[[{"diffs":[[0,"sts\n"],[-1,"\t-m vpath to use to mount the faye server (omit to disable publication)\n"],[0," "]],"start1":530,"start2":530,"length1":80,"length2":8}]],"length":1924,"saved":false}
+{"ts":1347314487698,"patch":[[{"diffs":[[0," -q "],[-1,"-m /faye "],[0,"-v f"]],"start1":711,"start2":711,"length1":17,"length2":8}]],"length":1915,"saved":false}
@@ -0,0 +1,3 @@
+{"ts":1347314436576,"silentsave":true,"restoring":false,"patch":[[{"diffs":[[1,"#!/usr/bin/env node\r\n\r\nvar argv = require('optimist').argv;\r\nvar server = require('../crud-file-server');\r\n\r\nif(!argv.q) {\r\n\tconsole.log('usage:');\t\r\n\tconsole.log(' crud-file-server [options]');\r\n\tconsole.log('');\r\n\tconsole.log('this starts a file server using the specified command-line options');\r\n\tconsole.log('');\r\n\tconsole.log('options:');\r\n\tconsole.log('');\r\n\tconsole.log(' -f file system path to expose over http');\r\n\tconsole.log(' -h log head requests');\t\r\n\tconsole.log(' -m vpath to use the mount the faye server (omit to disable publication)');\r\n\tconsole.log(' -p port to listen on (example, 80)');\r\n\tconsole.log(' -q suppress this message');\r\n\tconsole.log(' -r read only');\r\n\tconsole.log(' -v virtual path to host the file server on');\r\n\tconsole.log('');\r\n\tconsole.log('example:');\r\n\tconsole.log('');\r\n\tconsole.log(' crud-file-server -f c:/ -p 8080 -q -m /faye -v filez');\r\n\tconsole.log('');\r\n}\r\n\r\nvar port = argv.p || 80;\r\nvar path = argv.f || process.cwd();\r\nvar vpath = (argv.v || '').trimLeft();\r\nvar readOnly = argv.v;\r\nvar logHeadRequests = argv.h;\r\nvar publish = function() {};\r\nif(argv.m) {\r\n\tvar faye = require('faye');\r\n\tvar server = new faye.NodeAdapter({mount: argv.m});\r\n\tconsole.log('faye server listening on ' + argv.p);\r\n\tserver.listen(argv.p);\r\n\tpublish = function(message) { \r\n\t\tserver.publish('/', message);\r\n\t};\r\n}\r\n\r\nrequire('http').createServer(function (req, res) {\r\n\tserver.handleRequest(vpath, path, req, res, publish, readOnly, logHeadRequests);\r\n}).listen(port);\r\n\r\nconsole.log('listening on :' + port + '/' + vpath + ', serving ' + path);\r\n"]],"start1":0,"start2":0,"length1":0,"length2":1590}]],"length":1590}
+{"contributors":[],"silentsave":false,"ts":1347314458854,"patch":[[{"diffs":[[0,";\t\r\n"],[-1,"\tconsole.log(' -m vpath to use the mount the faye server (omit to disable publication)');\r\n"],[0,"\tcon"]],"start1":464,"start2":464,"length1":100,"length2":8},{"diffs":[[0,".h;\r"],[-1,"\nvar publish = function() {};\r\nif(argv.m) {\r\n\tvar faye = require('faye');\r\n\tvar server = new faye.NodeAdapter({mount: argv.m});\r\n\tconsole.log('faye server listening on ' + argv.p);\r\n\tserver.listen(argv.p);\r\n\tpublish = function(message) { \r\n\t\tserver.publish('/', message);\r\n\t};\r\n}\r"],[0,"\n\r\nr"]],"start1":981,"start2":981,"length1":288,"length2":8}]],"length":1218,"saved":false}
+{"ts":1347314467279,"patch":[[{"diffs":[[0," -q "],[-1,"-m /faye "],[0,"-v f"]],"start1":776,"start2":776,"length1":17,"length2":8}]],"length":1209,"saved":false}
@@ -0,0 +1,2 @@
+{"ts":1347314420789,"silentsave":true,"restoring":false,"patch":[[{"diffs":[[1,"var http = require(\"http\");\r\nvar fs = require('fs');\r\nvar faye = require('faye');\r\n\r\n// don't let users crawl up the folder structure by using a/../../../c/d\r\nvar cleanUrl = function(url) { \r\n\twhile(url.indexOf('..').length > 0) { url = url.replace('..', ''); }\r\n\treturn url;\r\n};\r\n\r\n/* \r\nexample usage:\r\n\trequire('http').createServer(function (req, res) {\r\n\t\tserver.handleRequest(port, path, req, res, vpath);\r\n\t}).listen(port);\r\n*/\r\nexports.handleRequest = function(vpath, path, req, res, publish, readOnly, logHeadRequests) {\t\r\n\t// vpath: (optional) virtual path to host in the url\r\n\t// path: the file system path to serve\r\n\t// readOnly: whether to allow modifications to the file\r\n\r\n\t// our error handler\r\n\tvar writeError = function (err, code) { \r\n\t\tcode = code || 500;\r\n\t\tconsole.log('Error ' + code + ': ' + err);\r\n\t\t// write the error to the response, if possible\r\n\t\ttry {\t\t\t\r\n\t\t\tres.statusCode = code;\r\n\t\t\tres.setHeader('Content-Type', 'application/json');\r\n\t\t\tres.end(JSON.stringify(err));\t\r\n\t\t} catch(resErr) {\r\n\t\t\tconsole.log('failed to write error to response: ' + resErr);\r\n\t\t}\r\n\t};\r\n\r\n\tif(path.lastIndexOf('/') !== path.length - 1) { path += '/'; } // make sure path ends with a slash\t\r\n\tvar parsedUrl = require('url').parse(req.url);\t\r\n\tvar query = query ? {} : require('querystring').parse(parsedUrl.query);\r\n var url = cleanUrl(parsedUrl.pathname);\r\n\t\r\n\t// normalize the url such that there is no trailing or leading slash /\r\n\tif(url.lastIndexOf('/') === url.length - 1) { url = url.slice(0, url.length ); }\r\n\tif(url[0] === '/') { url = url.slice(1, url.length); }\r\n\r\n\t// check that url begins with vpath\r\n\tif(vpath && url.indexOf(vpath) != 0) {\r\n\t\tconsole.log('url does not begin with vpath');\r\n\t\tthrow 'url [' + url + '] does not begin with vpath [' + vpath + ']';\r\n\t}\r\n\r\n\tif(req.method != 'HEAD') {\r\n\t\tconsole.log(req.method + ' ' + req.url);\r\n\t}\r\n\tvar relativePath = vpath && url.indexOf(vpath) == 0 ?\r\n\t\tpath + url.slice(vpath.length + 1, url.length):\r\n\t\tpath + url;\t\r\n\t\r\n\ttry {\r\n\t\tif(readOnly && req.method != 'GET') {\r\n\t\t\twriteError(req.method + ' forbidden on this resource', 403);\r\n\t\t} else {\r\n\t\t\tswitch(req.method) {\r\n\t\t\t\tcase 'HEAD':\r\n\t\t\t\t\tif(logHeadRequests) {\r\n\t\t\t\t\t\tconsole.log('head: ' + relativePath);\t\t\t\t\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfs.stat(relativePath, function(err, stats) { // determine if the resource is a file or directory\r\n\t\t\t\t\t\tif(err) { writeError(err); } \r\n\t\t\t\t\t\telse {\t\t\t\t\t\r\n\t\t\t\t\t\t\tres.setHeader('Last-Modified', stats.mtime);\t\t\r\n\t\t\t\t\t\t\tif(stats.isDirectory()) {\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\tres.setHeader('Content-Type', query.type == 'json' || query.dir == 'json' ? 'application/json' : 'text/html');\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tif(query.type == 'json' || query.dir == 'json') {\r\n\t\t\t\t\t\t\t\t\tres.setHeader('Content-Type', 'application/json');\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\t\tvar type = require('mime').lookup(relativePath);\r\n\t\t\t\t\t\t\t\t\tres.setHeader('Content-Type', type);\r\n\t\t\t\t\t\t\t\t\tres.setHeader('Content-Length', stats.size);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tres.end();\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'GET': // returns file or directory contents\r\n\t\t\t\t\tconsole.log('relativePath: ' + relativePath);\r\n\t\t\t\t\tif(url === 'favicon.ico') { \t\r\n\t\t\t\t\t\tres.end(); // if the browser requests favicon, just return an empty response\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tfs.stat(relativePath, function(err, stats) { // determine if the resource is a file or directory\r\n\t\t\t\t\t\t\tif(err) { writeError(err); } \r\n\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\tif(stats.isDirectory()) {\r\n\t\t\t\t\t\t\t\t\tres.setHeader('Last-Modified', stats.mtime);\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t// if it's a directory, return the files as a JSONified array\r\n\t\t\t\t\t\t\t\t\tconsole.log('reading directory ' + relativePath);\r\n\t\t\t\t\t\t\t\t\tfs.readdir(relativePath, function(err, files) {\r\n\t\t\t\t\t\t\t\t\t\tif(err) { \r\n\t\t\t\t\t\t\t\t\t\t\tconsole.log('writeError');\r\n\t\t\t\t\t\t\t\t\t\t\twriteError(err); \r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\t\t\t\tvar results = [];\r\n\t\t\t\t\t\t\t\t\t\t\tvar search = {};\r\n\t\t\t\t\t\t\t\t\t\t\tsearch.stats = function(files) {\r\n\t\t\t\t\t\t\t\t\t\t\t\tif(files.length) { \r\n\t\t\t\t\t\t\t\t\t\t\t\t\tvar file = files.shift();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tfs.stat(relativePath + '/' + file, function(err, stats) { \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif(err) { writeError(err); } \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstats.name = file;\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstats.isFile = stats.isFile();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstats.isDirectory = stats.isDirectory();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstats.isBlockDevice = stats.isBlockDevice();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstats.isFIFO = stats.isFIFO();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstats.isSocket = stats.isSocket();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tresults.push(stats);\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsearch.stats(files);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tif(query.dir == 'json') {\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.setHeader('Content-Type', 'application/json');\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.write(JSON.stringify(results)); \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.end();\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t} else { \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.setHeader('Content-Type', 'text/html');\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.write('<html><body>');\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfor(var f = 0; f < results.length; f++) {\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvar name = results[f].name;\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvar normalized = url + '/' + name;\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twhile(normalized[0] == '/') { normalized = normalized.slice(1, normalized.length); }\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.write('\\r\\n<p><a href=\"/' + normalized + '\">' + name + '</a></p>');\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tres.end('\\r\\n</body></html>');\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t};\r\n\t\t\t\t\t\t\t\t\t\t\tsearch.stats(files);\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t// if it's a file, return the contents of a file with the correct content type\r\n\t\t\t\t\t\t\t\t\tconsole.log('reading file ' + relativePath);\r\n\t\t\t\t\t\t\t\t\tif(query.type == 'json' || query.dir == 'json') {\r\n\t\t\t\t\t\t\t\t\t\tvar type = 'application/json';\r\n\t\t\t\t\t\t\t\t\t\tres.setHeader('Content-Type', type);\r\n\t\t\t\t\t\t\t\t\t\tfs.readFile(relativePath, function(err, data) { \r\n\t\t\t\t\t\t\t\t\t\t\tif(err) { writeError(err); }\r\n\t\t\t\t\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\t\t\t\t\tres.end(JSON.stringify({ \r\n\t\t\t\t\t\t\t\t\t\t\t\t\tdata: data.toString(),\r\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: require('mime').lookup(relativePath),\r\n\t\t\t\t\t\t\t\t\t\t\t\t})); \r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tvar type = require('mime').lookup(relativePath);\r\n\t\t\t\t\t\t\t\t\t\tres.setHeader('Content-Type', type);\r\n\t\t\t\t\t\t\t\t\t\tfs.readFile(relativePath, function(err, data) { \r\n\t\t\t\t\t\t\t\t\t\t\tif(err) { writeError(err); }\r\n\t\t\t\t\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\t\t\t\t\tres.setHeader('Content-Length', data.length);\r\n\t\t\t\t\t\t\t\t\t\t\t\tres.end(data); \r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn;\r\n\t\t\t\tcase 'PUT': // write a file\r\n\t\t\t\t\tconsole.log('writing ' + relativePath);\r\n\t\t\t\t\tvar stream = fs.createWriteStream(relativePath);\t\t\r\n\t\t\t\t\tstream.ok = true;\r\n\t\t\t\t\treq.pipe(stream); // TODO: limit data length\r\n\t\t\t\t\treq.on('end', function() {\t\t\t\t\r\n\t\t\t\t\t\tif(stream.ok) {\r\n\t\t\t\t\t\t\tres.end();\r\n\t\t\t\t\t\t\tpublish({ set: relativePath });\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t\tstream.on('error', function(err) { \t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\tstream.ok = false;\r\n\t\t\t\t\t\twriteError(err);\r\n\t\t\t\t\t});\r\n\t\t\t\t\treturn;\r\n\t\t\t\tcase 'POST': // create a directory or rename a file or directory\r\n\t\t\t\t\tif(query.rename) { // rename a file or directory\r\n\t\t\t\t\t\tconsole.log('rename: ' + relativePath);\r\n\t\t\t\t\t\t// e.g., http://localhost/old-name.html?rename=new-name.html\r\n\t\t\t\t\t\tquery.rename = cleanUrl(query.rename);\r\n\t\t\t\t\t\t// TODO: handle missing vpath here\r\n\t\t\t\t\t\tif(vpath) { \r\n\t\t\t\t\t\t\tif(query.rename.indexOf('/' + vpath + '/') == 0) { \r\n\t\t\t\t\t\t\t\tquery.rename = query.rename.slice(vpath.length + 2, query.rename.length);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tthrow 'renamed url [' + query.rename + '] does not begin with vpath [' + vpath + ']';\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} \r\n\t\t\t\t\t\tconsole.log('renaming ' + relativePath + ' to ' + path + query.rename);\r\n\t\t\t\t\t\tfs.rename(relativePath, path + query.rename, function(err) {\r\n\t\t\t\t\t\t\tif(err) { writeError(err); } \r\n\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\tres.end();\r\n\t\t\t\t\t\t\t\tpublish({ remove: relativePath, set: query.rename });\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else if(query.create == 'directory') { // rename a directory\r\n\t\t\t\t\t\t// e.g., http://localhost/new-directory?create=directory\r\n\t\t\t\t\t\tconsole.log('creating directory ' + relativePath);\r\n\t\t\t\t\t\tfs.mkdir(relativePath, 0777, function(err) { \r\n\t\t\t\t\t\t\tif(err) { writeError(err); } \r\n\t\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\t\tres.end();\r\n\t\t\t\t\t\t\t\tpublish({ set: query.relativePath });\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tconsole.log('relativePath: ' + relativePath);\r\n\t\t\t\t\t\twriteError('valid queries are ' + url + '?rename=[new name] or ' + url + '?create=directory');\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn;\r\n\t\t\t\tcase 'DELETE': // delete a file or directory\t\t\t\t\r\n\t\t\t\t\tfs.stat(relativePath, function(err, stats) { \r\n\t\t\t\t\t\tif(err) { writeError(err); } \r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tif(stats.isDirectory()) { // delete a directory\r\n\t\t\t\t\t\t\t\tconsole.log('deleting directory ' + relativePath);\r\n\t\t\t\t\t\t\t\tfs.rmdir(relativePath, function(err) {\r\n\t\t\t\t\t\t\t\t\tif(err) { writeError(err); }\r\n\t\t\t\t\t\t\t\t\telse { \r\n\t\t\t\t\t\t\t\t\t\tres.end(); \r\n\t\t\t\t\t\t\t\t\t\tpublish({ remove: relativePath });\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t} else { // delete a file\r\n\t\t\t\t\t\t\t\tconsole.log('deleting file ' + relativePath);\r\n\t\t\t\t\t\t\t\tfs.unlink(relativePath, function(err) {\r\n\t\t\t\t\t\t\t\t\tif(err) { writeError(err); }\r\n\t\t\t\t\t\t\t\t\telse { \r\n\t\t\t\t\t\t\t\t\t\tres.end(); \r\n\t\t\t\t\t\t\t\t\t\tpublish({ remove: relativePath });\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\t\t\t\r\n\t\t\t\t\treturn;\r\n\t\t\t\tdefault: // unsupported method! tell the client ...\r\n\t\t\t\t\tconsole.log('unsupported: ' + relativePath);\t\t\t\t\r\n\t\t\t\t\twriteError('Method ' + method + ' not allowed', 405);\r\n\t\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t} catch(err) { \r\n\t\t// file system ('fs') errors are just bubbled up to this error handler\r\n\t\t// for example, if the GET is called on a non-existent file, an error will be thrown\r\n\t\t// and caught here\r\n\t\t// writeError will write the error information to the response\r\n\t\twriteError('unhandled error: ' + err);\r\n\t}\r\n};\r\n"]],"start1":0,"start2":0,"length1":0,"length2":9777}]],"length":9777}
+{"contributors":[],"silentsave":false,"ts":1347314432524,"patch":[[{"diffs":[[0,"var "],[-1,"http = require(\"http\");\r\nvar fs = require('fs');\r\nvar faye = require('faye"],[1,"fs = require('fs"],[0,"');\r"]],"start1":0,"start2":0,"length1":82,"length2":24}]],"length":9719,"saved":false}
Oops, something went wrong.

0 comments on commit db87c16

Please sign in to comment.