@@ -72,32 +72,80 @@ export async function getBufferFrom(
7272 cancellationToken ?: CancellationToken ) : Promise < Buffer | null > {
7373
7474 const streamEnded = new Deferred < void > ( ) ;
75- while ( size > 0 ) {
76- cancellationToken ?. throwIfCancelled ( ) ;
7775
78- const readBuffer = readable . read ( size ) as Buffer ;
79- if ( readBuffer === null ) {
80- const bytesAvailable = new Deferred < void > ( ) ;
81- readable . once ( "readable" , bytesAvailable . resolve . bind ( bytesAvailable ) ) ;
82- readable . once ( "end" , streamEnded . resolve . bind ( streamEnded ) ) ;
83- const endPromise = Promise . race ( [ bytesAvailable . promise , streamEnded . promise ] ) ;
84- await ( cancellationToken ? cancellationToken . racePromise ( endPromise ) : endPromise ) ;
76+ if ( size === 0 ) {
77+ return Buffer . from ( [ ] ) ;
78+ }
8579
86- if ( bytesAvailable . isCompleted ) {
87- continue ;
80+ let readBuffer : Buffer | null = null ;
81+ let index : number = 0 ;
82+ while ( size > 0 ) {
83+ cancellationToken ?. throwIfCancelled ( ) ;
84+ let availableSize = ( readable as Readable ) . readableLength ;
85+ if ( ! availableSize ) {
86+ // Check the end of stream
87+ if ( ( readable as Readable ) . readableEnded || streamEnded . isCompleted ) {
88+ // stream is closed
89+ if ( ! allowEndOfStream ) {
90+ throw new Error ( "Stream terminated before required bytes were read." ) ;
91+ }
92+
93+ // Returns what has been read so far
94+ if ( readBuffer === null ) {
95+ return null ;
96+ }
97+
98+ // we need trim extra spaces
99+ return readBuffer . subarray ( 0 , index )
88100 }
101+
102+ // we retain this behavior when availableSize === false
103+ // to make existing unit tests happy (which assumes we will try to read stream when no data is ready.)
104+ availableSize = size ;
105+ } else if ( availableSize > size ) {
106+ availableSize = size ;
89107 }
90108
91- if ( ! allowEndOfStream ) {
92- if ( ! readBuffer || readBuffer . length < size ) {
109+ const newBuffer = readable . read ( availableSize ) as Buffer ;
110+ if ( newBuffer ) {
111+ if ( newBuffer . length < availableSize && ! allowEndOfStream ) {
93112 throw new Error ( "Stream terminated before required bytes were read." ) ;
94113 }
114+
115+ if ( readBuffer === null ) {
116+ if ( availableSize === size || newBuffer . length < availableSize ) {
117+ // in the fast pass, we read the entire data once, and donot allocate an extra array.
118+ return newBuffer ;
119+ }
120+
121+ // if we read partial data, we need allocate a buffer to join all data together.
122+ readBuffer = Buffer . alloc ( size ) ;
123+ }
124+
125+ // now append new data to the buffer
126+ newBuffer . copy ( readBuffer , index ) ;
127+
128+ size -= newBuffer . length ;
129+ index += newBuffer . length ;
95130 }
96131
97- return readBuffer ;
132+ if ( size > 0 ) {
133+ const bytesAvailable = new Deferred < void > ( ) ;
134+ const bytesAvailableCallback = bytesAvailable . resolve . bind ( bytesAvailable ) ;
135+ const streamEndedCallback = streamEnded . resolve . bind ( streamEnded ) ;
136+ readable . once ( "readable" , bytesAvailableCallback ) ;
137+ readable . once ( "end" , streamEndedCallback ) ;
138+ try {
139+ const endPromise = Promise . race ( [ bytesAvailable . promise , streamEnded . promise ] ) ;
140+ await ( cancellationToken ? cancellationToken . racePromise ( endPromise ) : endPromise ) ;
141+ } finally {
142+ readable . removeListener ( "readable" , bytesAvailableCallback ) ;
143+ readable . removeListener ( "end" , streamEndedCallback ) ;
144+ }
145+ }
98146 }
99147
100- return Buffer . from ( [ ] ) ;
148+ return readBuffer ;
101149}
102150
103151export function throwIfDisposed ( value : IDisposableObservable ) {
0 commit comments