stream: Never call decoder.end() multiple times
authorGil Pedersen <git@gpost.dk>
Thu, 14 Mar 2013 13:01:14 +0000 (14:01 +0100)
committerisaacs <i@izs.me>
Thu, 14 Mar 2013 23:13:10 +0000 (16:13 -0700)
Updated version that does what it says without assigning state.decoder.

lib/_stream_readable.js
test/simple/test-stream2-set-encoding.js

index b09694c..ad0a783 100644 (file)
@@ -342,14 +342,14 @@ function chunkInvalid(state, chunk) {
 
 
 function onEofChunk(stream, state) {
-  state.ended = true;
-  if (state.decoder) {
+  if (state.decoder && !state.ended) {
     var chunk = state.decoder.end();
     if (chunk && chunk.length) {
       state.buffer.push(chunk);
       state.length += state.objectMode ? 1 : chunk.length;
     }
   }
+  state.ended = true;
 
   // if we've ended and we have some data left, then emit
   // 'readable' now to make sure it gets picked up.
@@ -733,12 +733,12 @@ Readable.prototype.wrap = function(stream) {
 
   var self = this;
   stream.on('end', function() {
-    state.ended = true;
-    if (state.decoder) {
+    if (state.decoder && !state.ended) {
       var chunk = state.decoder.end();
       if (chunk && chunk.length)
         self.push(chunk);
     }
+    state.ended = true;
 
     self.push(null);
   });
index 8c5973f..931cf48 100644 (file)
@@ -74,11 +74,15 @@ TestReader.prototype._read = function(n) {
   setTimeout(function() {
 
     if (this.pos >= this.len) {
+      // double push(null) to test eos handling
+      this.push(null);
       return this.push(null);
     }
 
     n = Math.min(n, this.len - this.pos);
     if (n <= 0) {
+      // double push(null) to test eos handling
+      this.push(null);
       return this.push(null);
     }
 
@@ -204,6 +208,41 @@ test('setEncoding hex with read(13)', function(t) {
   tr.emit('readable');
 });
 
+test('setEncoding base64', function(t) {
+  var tr = new TestReader(100);
+  tr.setEncoding('base64');
+  var out = [];
+  var expect =
+    [ 'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYQ==' ];
+
+  tr.on('readable', function flow() {
+    var chunk;
+    while (null !== (chunk = tr.read(10)))
+      out.push(chunk);
+  });
+
+  tr.on('end', function() {
+    t.same(out, expect);
+    t.end();
+  });
+
+  // just kick it off.
+  tr.emit('readable');
+});
+
 test('encoding: utf8', function(t) {
   var tr = new TestReader(100, { encoding: 'utf8' });
   var out = [];
@@ -310,3 +349,37 @@ test('encoding: hex with read(13)', function(t) {
   // just kick it off.
   tr.emit('readable');
 });
+
+test('encoding: base64', function(t) {
+  var tr = new TestReader(100, { encoding: 'base64' });
+  var out = [];
+  var expect =
+    [ 'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYWFhYWFh',
+      'YWFhYWFhYW',
+      'FhYQ==' ];
+
+  tr.on('readable', function flow() {
+    var chunk;
+    while (null !== (chunk = tr.read(10)))
+      out.push(chunk);
+  });
+
+  tr.on('end', function() {
+    t.same(out, expect);
+    t.end();
+  });
+
+  // just kick it off.
+  tr.emit('readable');
+});