Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save koichik/942099 to your computer and use it in GitHub Desktop.

Select an option

Save koichik/942099 to your computer and use it in GitHub Desktop.
Avoid 'data' events after pause() was called
From 30f9b877f00a3faa5636f5892588f7c93f28d669 Mon Sep 17 00:00:00 2001
From: koichik <koichik@improvement.jp>
Date: Tue, 26 Apr 2011 19:30:21 +0900
Subject: [PATCH] Avoid 'data' and/or 'end' events after pause() was called
---
lib/http.js | 42 +++++++++++++++++++--
test/simple/test-http-pause.js | 78 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+), 4 deletions(-)
create mode 100644 test/simple/test-http-pause.js
diff --git a/lib/http.js b/lib/http.js
index 1e7512d..eb34b9c 100644
--- a/lib/http.js
+++ b/lib/http.js
@@ -36,6 +36,8 @@ if (process.env.NODE_DEBUG && /http/.test(process.env.NODE_DEBUG)) {
}
+var END = {};
+
var parsers = new FreeList('parsers', 1000, function() {
var parser = new HTTPParser('request');
@@ -114,7 +116,9 @@ var parsers = new FreeList('parsers', 1000, function() {
parser.onBody = function(b, start, len) {
// TODO body encoding?
var slice = b.slice(start, start + len);
- if (parser.incoming._decoder) {
+ if (parser.incoming._paused) {
+ parser.incoming._pendings.push(slice);
+ } else if (parser.incoming._decoder) {
var string = parser.incoming._decoder.write(slice);
if (string.length) parser.incoming.emit('data', string);
} else {
@@ -129,8 +133,12 @@ var parsers = new FreeList('parsers', 1000, function() {
}
if (!parser.incoming.upgrade) {
// For upgraded connections, also emit this after parser.execute
- parser.incoming.readable = false;
- parser.incoming.emit('end');
+ if (parser.incoming._paused) {
+ parser.incoming._pendings.push(END);
+ } else {
+ parser.incoming.readable = false;
+ parser.incoming.emit('end');
+ }
}
};
@@ -220,6 +228,9 @@ function IncomingMessage(socket) {
this.readable = true;
+ this._paused = false;
+ this._pendings = [];
+
// request (server) only
this.url = '';
@@ -247,12 +258,35 @@ IncomingMessage.prototype.setEncoding = function(encoding) {
IncomingMessage.prototype.pause = function() {
+ this._paused = true;
this.socket.pause();
};
IncomingMessage.prototype.resume = function() {
- this.socket.resume();
+ this._paused = false;
+ if (this.socket) {
+ this.socket.resume();
+ }
+ var self = this;
+ if (this._pendings.length) {
+ process.nextTick(function() {
+ while (self._pendings.length) {
+ var chunk = self._pendings.shift();
+ if (chunk !== END) {
+ assert(Buffer.isBuffer(chunk));
+ if (self._decoder) {
+ chunk = self._decoder.write(chunk);
+ }
+ self.emit('data', chunk);
+ } else {
+ assert(self._pendings.length === 0);
+ self.readable = false;
+ self.emit('end');
+ }
+ }
+ });
+ }
};
diff --git a/test/simple/test-http-pause.js b/test/simple/test-http-pause.js
new file mode 100644
index 0000000..439c4ec
--- /dev/null
+++ b/test/simple/test-http-pause.js
@@ -0,0 +1,78 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var http = require('http');
+
+var expectedServer = 'Post Body For Test';
+var resultServer = '';
+var expectedClient = 'hello world';
+var resultClient = '';
+
+var server = http.Server(function(req, res) {
+ console.log('pause server request');
+ req.pause();
+ setTimeout(function() {
+ console.log('resume server request');
+ req.resume();
+ req.setEncoding('utf8');
+ req.on('data', function(chunk) {
+ resultServer += chunk;
+ });
+ req.on('end', function() {
+ console.log(resultServer);
+ res.writeHead(200);
+ res.end(expectedClient);
+ });
+ }, 100);
+});
+
+server.listen(common.PORT, function() {
+ http.request({
+ port: common.PORT,
+ path: '/',
+ method: 'POST'
+ }, function(res) {
+ console.log('pause client response');
+ res.pause();
+ setTimeout(function() {
+ console.log('resume client response');
+ res.resume();
+ res.on('data', function(chunk) {
+ resultClient += chunk;
+ });
+ res.on('end', function() {
+ console.log(resultClient);
+ server.close();
+ });
+ }, 100);
+ }).on('error', function(e) {
+ console.log(e.message);
+ process.exit(1);
+ }).end(expectedServer);
+});
+
+process.on('exit', function() {
+ assert.equal(expectedServer, resultServer);
+ assert.equal(expectedClient, resultClient);
+});
+
--
1.7.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment