1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23require('../common'); 24const assert = require('assert'); 25 26const Readable = require('stream').Readable; 27 28test1(); 29test2(); 30 31function test1() { 32 const r = new Readable(); 33 34 // Should not end when we get a Buffer.alloc(0) or '' as the _read 35 // result that just means that there is *temporarily* no data, but to 36 // go ahead and try again later. 37 // 38 // note that this is very unusual. it only works for crypto streams 39 // because the other side of the stream will call read(0) to cycle 40 // data through openssl. that's why setImmediate() is used to call 41 // r.read(0) again later, otherwise there is no more work being done 42 // and the process just exits. 43 44 const buf = Buffer.alloc(5, 'x'); 45 let reads = 5; 46 r._read = function(n) { 47 switch (reads--) { 48 case 5: 49 return setImmediate(() => { 50 return r.push(buf); 51 }); 52 case 4: 53 setImmediate(() => { 54 return r.push(Buffer.alloc(0)); 55 }); 56 return setImmediate(r.read.bind(r, 0)); 57 case 3: 58 setImmediate(r.read.bind(r, 0)); 59 return process.nextTick(() => { 60 return r.push(Buffer.alloc(0)); 61 }); 62 case 2: 63 setImmediate(r.read.bind(r, 0)); 64 return r.push(Buffer.alloc(0)); // Not-EOF! 65 case 1: 66 return r.push(buf); 67 case 0: 68 return r.push(null); // EOF 69 default: 70 throw new Error('unreachable'); 71 } 72 }; 73 74 const results = []; 75 function flow() { 76 let chunk; 77 while (null !== (chunk = r.read())) 78 results.push(String(chunk)); 79 } 80 r.on('readable', flow); 81 r.on('end', () => { 82 results.push('EOF'); 83 }); 84 flow(); 85 86 process.on('exit', () => { 87 assert.deepStrictEqual(results, [ 'xxxxx', 'xxxxx', 'EOF' ]); 88 console.log('ok'); 89 }); 90} 91 92function test2() { 93 const r = new Readable({ encoding: 'base64' }); 94 let reads = 5; 95 r._read = function(n) { 96 if (!reads--) 97 return r.push(null); // EOF 98 return r.push(Buffer.from('x')); 99 }; 100 101 const results = []; 102 function flow() { 103 let chunk; 104 while (null !== (chunk = r.read())) 105 results.push(String(chunk)); 106 } 107 r.on('readable', flow); 108 r.on('end', () => { 109 results.push('EOF'); 110 }); 111 flow(); 112 113 process.on('exit', () => { 114 assert.deepStrictEqual(results, [ 'eHh4', 'eHg=', 'EOF' ]); 115 console.log('ok'); 116 }); 117} 118