Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Added connect.timeout() middleware #499

Closed
wants to merge 14 commits into from

2 participants

@hunterloftis

Uses new socket.setTimeout.

Tests included.

Keeps the options and defaults from the ancient connect-timeout middleware.

@hunterloftis

Just tried this branch with an actual project - routes that use res.render are working fine, but weirdly routes that use static files (via the static express middleware) generate timeouts. Ideas?

@hunterloftis

Chrome times out with .txt files, Firefox and Safari only time out with binary files like .jpg and .ico.

Perhaps I misunderstand how the socket detects idleness?

Hunter Loftis Added test for static middleware. I don't think .request() works the …
…same as a real browser, since safari/chrome/ff all timeout on certain static files.
e7b746f
@hunterloftis hunterloftis reopened this
@tj
Owner
tj commented

hmm maybe we shouldn't use setTimeout after-all

@hunterloftis

It's socket-level rather than request-level... so different requests must be grouped into the same timeout unfortunately (that's the issue I was seeing with the eventemitter leaks).

Possibly the per-request setTimeout is a better way to go, ala Connect.timeout.

@tj
Owner
tj commented

right right, makes sense

@hunterloftis

Just did a quick test; one request failing can screw all the rests of the requests on the socket. Closing :/

@hunterloftis

Would you mind if I dropped something basically identical to connect-timeout into stock connect? I feel like it's a pretty fundamental capability of a request to timeout (I don't know anyone who doesn't use timeouts at least most of the time).

@tj
Owner
tj commented

yeah I'm down for that, I wanted it in a long time ago just never got around to it for some reason, but it's small so im +1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 3, 2012
  1. stubbed in .timeout() middleware and test.

    Hunter Loftis authored
  2. Implemented timeout() and req.clearTimeout()

    Hunter Loftis authored
  3. semi

    Hunter Loftis authored
  4. Merge branch 'refs/heads/middleware-timeout'

    Hunter Loftis authored
  5. Added default options

    Hunter Loftis authored
  6. Updated thrown error

    Hunter Loftis authored
Commits on Mar 4, 2012
  1. Added test for static middleware. I don't think .request() works the …

    Hunter Loftis authored
    …same as a real browser, since safari/chrome/ff all timeout on certain static files.
  2. searching for events that should cancel the timeout

    Hunter Loftis authored
  3. Added clearTimeout on socket 'drain' to support streaming (eg static …

    Hunter Loftis authored
    …middleware)
Commits on Mar 8, 2012
  1. Merge branch 'refs/heads/upstream'

    Hunter Loftis authored
Commits on Mar 22, 2012
  1. Added check to ensure clearTimeout is only created once, and the sing…

    Hunter Loftis authored
    …le event listener is also only created once.
  2. moved drain callback to the socket so it doesn't get recreated on eac…

    Hunter Loftis authored
    …h request.
This page is out of date. Refresh to see the latest.
View
51 lib/middleware/timeout.js
@@ -0,0 +1,51 @@
+/*!
+ * Connect - timeout
+ * Copyright(c) 2012 Hunter Loftis
+ * MIT Licensed
+ */
+
+/**
+ * Timeout:
+ *
+ * Invokes `socket.setTimeout` to timeout idle requests
+ * Adds req.clearTimeout() for long-running requests
+ *
+ * - `throwError`: throw an error instead of writing a status code
+ * - `time`: timeout length in ms (default: 10000)
+ *
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+
+module.exports = function timeout(options) {
+ options = options || {};
+ options.time = options.time || 8000;
+ options.code = options.code || 500;
+ options.throwError = options.throwError || false;
+
+ return function(req, res, next) {
+
+ req.socket.removeAllListeners('timeout'); // http socket auto-destroys on timeout
+ req.socket.setTimeout(options.time, timed_out);
+
+ function timed_out() {
+ if (options.throwError) {
+ return next(new Error('Timeout ' + req.method + ' ' + req.url));
+ }
+ else {
+ res.writeHead(options.code);
+ res.end();
+ }
+ }
+
+ if (!req.socket.clearTimeout) {
+ req.socket.clearTimeout = function() {
+ req.socket.setTimeout(0);
+ };
+ req.socket.once('drain', req.socket.clearTimeout); // Clear whenever we send anything
+ }
+
+ return next();
+ };
+};
View
BIN  test/fixtures/favicon.ico
Binary file not shown
View
79 test/timeout.js
@@ -0,0 +1,79 @@
+
+var connect = require('../');
+
+var fixtures = __dirname + '/fixtures';
+
+var app = connect();
+
+app.use(connect.timeout({
+ code: 503,
+ time: 500
+}));
+
+app.use(connect['static'](fixtures));
+
+var timeouts;
+app.use(function(err, req, res, next) {
+ timeouts++;
+});
+
+app.use(function(req, res, next) {
+ if (req.url === '/should/timeout') {
+ // chill and wait for timeout
+ }
+ else if (req.url === '/should/not/timeout') {
+ res.writeHead(200);
+ res.end();
+ }
+ else if (req.url === '/should/interrupt/timeout') {
+ req.clearTimeout();
+ setTimeout(function() {
+ res.writeHead(200);
+ res.end();
+ }, 1000); // Wait until after timeout `time`
+ }
+});
+
+// Tests
+
+describe('connect.timeout()', function() {
+ it('should timeout', function(done) {
+ app.request()
+ .get('/should/timeout')
+ .end(function(res) {
+ res.statusCode.should.equal(503);
+ done();
+ });
+ });
+
+ it('should not timeout', function(done) {
+ app.request()
+ .get('/should/not/timeout')
+ .end(function(res) {
+ res.statusCode.should.equal(200);
+ done();
+ });
+ });
+
+ it('should interrupt timeout', function(done) {
+ app.request()
+ .get('/should/interrupt/timeout')
+ .end(function(res) {
+ res.statusCode.should.equal(200);
+ done();
+ });
+ });
+
+ it('should serve static files without timeout', function(done){
+ timeouts = 0;
+ app.request()
+ .get('/favicon.ico')
+ .end(function(res) {
+ setTimeout(function() {
+ timeouts.should.equal(0);
+ done();
+ }, 1000);
+ });
+ });
+
+});
Something went wrong with that request. Please try again.