Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Stream and Buffer based read/write loop.

- We moved to sendfile before node.JS had binary buffers. A read write
  loop is a lot faster now than back when node was converting everything
  to UTF-8 strings. Sendfile isn't needed.

Sendfile(2) was causing all sorts of hassles
- Connections would timeout, then sendfile would try and send out a null
  file descriptor
- Sendfile(2) has crap error messages for when the shit hits the fan.
  'bad argument'
  • Loading branch information...
commit b56f626dddf2f0469eca8a05eaa0bc1ff029afc2 1 parent a6ecb61
Mark Hansen authored
Showing with 30 additions and 73 deletions.
  1. +29 −72 lib/antinode.js
  2. +1 −1  package.json
101 lib/antinode.js
View
@@ -9,6 +9,7 @@ var http = require('http'),
Script = process.binding('evals').Script;
exports.default_settings = {
+ "max_bytes_per_read": 4 * 1024,
"timeout_milliseconds": 1000 * 30,
"hosts" : {},
"port" : 8080,
@@ -128,78 +129,34 @@ function handle_request(path, req, resp) {
});
function stream_file(file, stats) {
- fs.open(file,'r', 0660, function(err, fd) {
- if (err) {
- log.debug("fs.open(",file,") error: ",err.message);
- return file_not_found();
- }
- log.debug("opened", path, "on fd", fd);
- var fd_open = true;
- req.connection.addListener('timeout', function() {
- if (fd_open) {
- // close file descriptors so we don't run out of them.
- // only close the file once. If our timeout handler runs
- // after we've finished sending the file, the fd will
- // already be closed and it could be reused by another
- // request. It would interrupt the other request if we
- // closed a fd twice.
- close(fd);
- fd_open = false;
- }
- });
-
- send_headers(200, stats.size, mime.mime_type(file), stats.mtime);
- resp._send(''); // HACK force a flush
-
- send_chunk(0, stats.size, function() {
- finish(resp);
- close(fd);
- fd_open = false;
- });
-
- // For large files, sendfile(2) may only send a small chunk of the
- // file (even when we request it send more) due to TCP's flow
- // control so we need to keep sending till the whole file's sent.
- function send_chunk(offset, bytes_to_write, callback) {
- log.debug('sending chunk of', file, offset, bytes_to_write);
- if (!req.connection.fd) return callback(); //the connection timed out
- fs.sendfile(req.connection.fd, fd, offset, bytes_to_write,
- function (err, bytes_written) {
- if (err) {
- switch (err.errno) {
- case process.EAGAIN:
- // write would have blocked, try again later
- bytes_written = 0;
- break;
-
- default:
- log.error("sendfile(",file,") failed: ",err.message);
- // fall through
-
- case process.EBADF:
- // don't write a log message, the timeout handler
- // already did
- callback();
- return;
- }
- }
- if (bytes_written > 0) {
- // this isn't an idle connection. Bump the connection
- // timeout. Usually this would be done for us in the
- // response.write() call but we use sendfile(), so we
- // need to update this manually.
- req.connection.setTimeout(settings.timeout_milliseconds);
- }
- bytes_to_write -= bytes_written;
- offset += bytes_written;
- if (bytes_to_write < 1) {
- callback();
- }
- else {
- send_chunk(offset, bytes_to_write, callback);
- }
- });
- }
+ try {
+ var readStream = fs.createReadStream(file);
+ }
+ catch (err) {
+ log.debug("fs.createReadStream(",file,") error: ",sys.inspect(err));
+ return file_not_found();
+ }
+
+ req.connection.addListener('timeout', function() {
+ log.debug('timed out. destroying file read stream');
+ readStream.destroy();
+ });
+
+ log.debug("opened",path);
+ send_headers(200, stats.size, mime.mime_type(file), stats.mtime);
+ req.connection.addListener('drain', function() {
+ // it is safe to write
+ });
+ readStream.addListener('data', function (data) {
+ // send it out
+ resp.write(data);
+ });
+ readStream.addListener('error', function (err) {
+ log.error('error reading',file,sys.inspect(err));
+ finish(resp);
+ });
+ readStream.addListener('end', function () {
+ finish(resp);
});
}
2  package.json
View
@@ -1,6 +1,6 @@
{ "name" : "antinode"
, "description" : "A simple web server for node.js"
-, "version" : "2.0.1"
+, "version" : "2.0.3"
, "author" : "Mark Hansen <mark@markhansen.co.nz>"
, "contributors" :
[ "Ben Noordhuis <info@bnoordhuis.nl>"
Please sign in to comment.
Something went wrong with that request. Please try again.