Socket
Socket
Sign inDemoInstall

dweb

Package Overview
Dependencies
45
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.3 to 0.1.4

195

dweb.js

@@ -6,98 +6,123 @@ #!/usr/bin/env node

//
var fs = require('fs'),
argv = require('optimist').argv,
path = require('path'),
util = require('util'),
connect = require('connect'),
inotify = require('inotify').Inotify,
socketio = require('socket.io');
// WARNING: THIS IS NOT A PRODUCTION WEBSERVER.
// USE FOR DEVELOPMENT ONLY.
//
// In particular, URLs are not mapped to files in a secure way.
//
var fs = require('fs')
, argv = require('optimist').argv
, path = require('path')
, util = require('util')
, walk = require('walk')
, connect = require('connect')
, inotify = require('inotify').Inotify
, socketio = require('socket.io')
;
(function main() {
// Start webserver serving out current working directory
// Parameters
var watch_extensions = {
'.html': true,
'.js': true,
'.css': true,
'.less': true,
'.json': true
};
argv.port = argv.port || 8000;
argv.dir = argv.dir || process.cwd();
argv.poll = argv.poll || 10000; // poll frequency for new files, in milliseconds
// Recursively add inotify watches for files in directory
var monitor = new inotify();
var watched_files = {};
(function _walk_directory() {
var walker = walk.walk(path.normalize(argv.dir));
walker.on('file', function(dirName, fileStats, next) {
var filename = fileStats.name;
var extension = path.extname(filename);
if (watch_extensions[extension]) {
var filepath = path.join(dirName, filename);
if (!watched_files[filepath]) {
var inotify_options = {
path: filepath,
watch_for: inotify.IN_MODIFY,
callback: function(e) { _server_inotify_hook(filepath) },
};
watched_files[filepath] = monitor.addWatch(inotify_options);
util.log('dweb: watching ' + path.relative(argv.dir, filepath));
}
}
next();
});
walker.on('end', function() {
setTimeout(_walk_directory, argv.poll);
});
})(); // end function _walk_directory()
// Start webserver serving out current directory and socketio server
// for broadcasting reload events to connected clients.
var app = connect()
.use(intercept)
.use(connect.static(process.cwd()))
.listen(argv.port);
// Start socket.io server
.use(_intercept)
.use(connect.static(argv.dir))
.listen(argv.port);
var io = socketio.listen(app, {log: false});
util.log('dweb: webserver listening on port ' + argv.port);
// Callback function for file modification
var last_mtimes = {};
function _server_inotify_hook(filepath) {
var stat = fs.statSync(filepath);
var mtime = stat.mtime;
if (last_mtimes[filepath] - mtime !== 0) {
util.log('dweb: change detected in ' + filepath);
io.sockets.emit('inotify', filepath);
last_mtimes[filepath] = mtime;
}
} // end function _server_inotify_hook
// Start inotify monitor
var monitor = (new inotify())
.addWatch({
path: process.cwd(),
watch_for: inotify.IN_MODIFY | inotify.IN_CREATE,
callback: __inotify_hook_server
});
util.log('Listening on port ' + argv.port);
// Middleware to inject socket.io hook into HTML files
function intercept(req, res, next) {
var url = path.resolve('.' + (req.url == '/' ? '/index.html' : req.url));
// Middleware to inject socket.io hook into served HTML files
function _intercept(req, res, next) {
util.log(req.method + ' ' + req.url);
if (url.length >= 4 && url.substr(url.length - 4) == 'html') {
try {
var html = inject_inotify_hook(fs.readFileSync(url).toString('utf8'));
} catch(e) {
if (typeof next == 'function')
return next();
html = (e && e.toString()) || 'error';
}
// TODO: replace with something that does not allow breaking out
// of the server's root directory.
var req_url = req.url == '/' ? '/index.html' : req.url;
req_url = path.join(argv.dir, req_url);
var extension = path.extname(req_url);
if (extension !== '.html') return next();
// Inject socket.io listener into HTML file
try {
var html = _inject_inotify_hook(fs.readFileSync(req_url).toString('utf8'));
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
} else
next();
}
// Inotify event callback
function __inotify_hook_server(event) {
io.sockets.emit('inotify', event.name);
}
})();
// Inject the inotify hook HTML fragment into every HTML page served.
// This does not attempt to parse the DOM in any way, and relies on the
// existence of at least a </head> or </body> tag in the HTML file.
function inject_inotify_hook(html) {
var inject_pos = html.indexOf('</head>');
inject_pos = (inject_pos == -1) ? html.indexOf('</body>') : inject_pos;
if (inject_pos != -1)
html = [ html.substr(0, inject_pos),
'<script src="http://localhost:'
+ argv.port
+ '/socket.io/socket.io.js"></script>',
'<script language="javascript">',
'window.addEventListener("load", __inotify_hook_client);',
__inotify_hook_client.toString(),
'</script>',
html.substr(inject_pos)
].join('');
return html;
// Only parsed and called in the browser
function __inotify_hook_client() {
var files_to_watch = {};
// Watch all stylesheet files
var parser = document.createElement('a');
for (var i = 0; i < document.styleSheets.length; i++) {
parser.href = document.styleSheets[i].href;
files_to_watch[parser.pathname.substr(1)] = true;
res.end(html);
} catch (e) {
util.error('dweb: cannot inject listener into ' + req_url);
return next();
}
// Watch document root
parser.href = document.location.href;
var root = parser.pathname.substr(1);
if (root == '') root = 'index.html';
files_to_watch[root] = true;
} // end function _intercept()
function _inject_inotify_hook(html) {
var inject_pos = html.indexOf('</head>');
inject_pos = (inject_pos == -1) ? html.indexOf('</body>') : inject_pos;
if (inject_pos == -1) throw 'could not find a </head> or </body> tag';
return [ html.substr(0, inject_pos)
, util.format('<script src="http://localhost:%d/socket.io/socket.io.js"></script>\n', argv.port)
, '<script language="javascript">'
, _client_inotify_hook.toString()
, 'window.addEventListener("load", _client_inotify_hook);'
, '</script>'
, html.substr(inject_pos)
].join('');
} // end function _inject_inotify_hook()
function _client_inotify_hook() {
// Connect to SocketIO server
var socket = io.connect(parser.protocol + '//' + parser.host);
var url_parser = document.createElement('a');
url_parser.href = document.location.href;
var socket = io.connect(url_parser.protocol + '//' + url_parser.host);
socket.on('inotify', function (data) {
if (data in files_to_watch);
window.location.reload();
window.location.reload();
});
}
}
} // end function _client_inotify_hook()
})(); // end function main()

@@ -5,3 +5,3 @@ {

"preferGlobal": true,
"version": "0.1.3",
"version": "0.1.4",
"author": "Mayank Lahiri <mlahiri@gmail.com>",

@@ -17,12 +17,16 @@ "description": "A debugging web server that auto-reloads pages on local modifications.",

"keywords": [
"development",
"debugging",
"http",
"server"
"webserver",
"instant refresh",
"refresh on save"
],
"dependencies" : {
"inotify": ">=1.2.1",
"socket.io": ">=0.9.16",
"connect": ">=2.9.0",
"optimist": ">=0.6.0"
"inotify": "1.2.x",
"socket.io": "0.9.x",
"connect": "2.9.x",
"optimist": "0.6.x",
"walk": "2.2.x"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc