FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
node/lib/_stream_readable.js at master · anchnk/node · GitHub
anchnk
/
node
Public
forked from
nodejs/node
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
Wiki
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
node
/
lib
/
_stream_readable.js
Copy path
More file actions
More file actions
Latest commit
History
History
History
998 lines (870 loc) · 28.3 KB
Breadcrumbs
node
/
lib
/
_stream_readable.js
Copy path
File metadata and controls
998 lines (870 loc) · 28.3 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
// 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.
'use strict'
;
module
.
exports
=
Readable
;
Readable
.
ReadableState
=
ReadableState
;
const
EE
=
require
(
'events'
)
;
const
Stream
=
require
(
'stream'
)
;
const
Buffer
=
require
(
'buffer'
)
.
Buffer
;
const
util
=
require
(
'util'
)
;
const
debug
=
util
.
debuglog
(
'stream'
)
;
const
BufferList
=
require
(
'internal/streams/BufferList'
)
;
var
StringDecoder
;
util
.
inherits
(
Readable
,
Stream
)
;
const
kProxyEvents
=
[
'error'
,
'close'
,
'destroy'
,
'pause'
,
'resume'
]
;
function
prependListener
(
emitter
,
event
,
fn
)
{
// Sadly this is not cacheable as some libraries bundle their own
// event emitter implementation with them.
if
(
typeof
emitter
.
prependListener
===
'function'
)
{
return
emitter
.
prependListener
(
event
,
fn
)
;
}
else
{
// This is a hack to make sure that our error handler is attached before any
// userland ones. NEVER DO THIS. This is here only because this code needs
// to continue to work with older versions of Node.js that do not include
// the prependListener() method. The goal is to eventually remove this hack.
if
(
!
emitter
.
_events
||
!
emitter
.
_events
[
event
]
)
emitter
.
on
(
event
,
fn
)
;
else
if
(
Array
.
isArray
(
emitter
.
_events
[
event
]
)
)
emitter
.
_events
[
event
]
.
unshift
(
fn
)
;
else
emitter
.
_events
[
event
]
=
[
fn
,
emitter
.
_events
[
event
]
]
;
}
}
function
ReadableState
(
options
,
stream
)
{
options
=
options
||
{
}
;
// object stream flag. Used to make read(n) ignore n and to
// make all the buffer merging and length checks go away
this
.
objectMode
=
!
!
options
.
objectMode
;
if
(
stream
instanceof
Stream
.
Duplex
)
this
.
objectMode
=
this
.
objectMode
||
!
!
options
.
readableObjectMode
;
// the point at which it stops calling _read() to fill the buffer
// Note: 0 is a valid value, means "don't call _read preemptively ever"
var
hwm
=
options
.
highWaterMark
;
var
defaultHwm
=
this
.
objectMode
?
16
:
16
*
1024
;
this
.
highWaterMark
=
(
hwm
||
hwm
===
0
)
?
hwm
:
defaultHwm
;
// cast to ints.
this
.
highWaterMark
=
Math
.
floor
(
this
.
highWaterMark
)
;
// A linked list is used to store data chunks instead of an array because the
// linked list can remove elements from the beginning faster than
// array.shift()
this
.
buffer
=
new
BufferList
(
)
;
this
.
length
=
0
;
this
.
pipes
=
null
;
this
.
pipesCount
=
0
;
this
.
flowing
=
null
;
this
.
ended
=
false
;
this
.
endEmitted
=
false
;
this
.
reading
=
false
;
// a flag to be able to tell if the event 'readable'/'data' is emitted
// immediately, or on a later tick. We set this to true at first, because
// any actions that shouldn't happen until "later" should generally also
// not happen before the first read call.
this
.
sync
=
true
;
// whenever we return null, then we set a flag to say
// that we're awaiting a 'readable' event emission.
this
.
needReadable
=
false
;
this
.
emittedReadable
=
false
;
this
.
readableListening
=
false
;
this
.
resumeScheduled
=
false
;
// Crypto is kind of old and crusty. Historically, its default string
// encoding is 'binary' so we have to make this configurable.
// Everything else in the universe uses 'utf8', though.
this
.
defaultEncoding
=
options
.
defaultEncoding
||
'utf8'
;
// the number of writers that are awaiting a drain event in .pipe()s
this
.
awaitDrain
=
0
;
// if true, a maybeReadMore has been scheduled
this
.
readingMore
=
false
;
this
.
decoder
=
null
;
this
.
encoding
=
null
;
if
(
options
.
encoding
)
{
if
(
!
StringDecoder
)
StringDecoder
=
require
(
'string_decoder'
)
.
StringDecoder
;
this
.
decoder
=
new
StringDecoder
(
options
.
encoding
)
;
this
.
encoding
=
options
.
encoding
;
}
}
function
Readable
(
options
)
{
if
(
!
(
this
instanceof
Readable
)
)
return
new
Readable
(
options
)
;
this
.
_readableState
=
new
ReadableState
(
options
,
this
)
;
// legacy
this
.
readable
=
true
;
if
(
options
&&
typeof
options
.
read
===
'function'
)
this
.
_read
=
options
.
read
;
Stream
.
call
(
this
)
;
}
// Manually shove something into the read() buffer.
// This returns true if the highWaterMark has not been hit yet,
// similar to how Writable.write() returns true if you should
// write() some more.
Readable
.
prototype
.
push
=
function
(
chunk
,
encoding
)
{
var
state
=
this
.
_readableState
;
if
(
!
state
.
objectMode
&&
typeof
chunk
===
'string'
)
{
encoding
=
encoding
||
state
.
defaultEncoding
;
if
(
encoding
!==
state
.
encoding
)
{
chunk
=
Buffer
.
from
(
chunk
,
encoding
)
;
encoding
=
''
;
}
}
return
readableAddChunk
(
this
,
state
,
chunk
,
encoding
,
false
)
;
}
;
// Unshift should *always* be something directly out of read()
Readable
.
prototype
.
unshift
=
function
(
chunk
)
{
var
state
=
this
.
_readableState
;
return
readableAddChunk
(
this
,
state
,
chunk
,
''
,
true
)
;
}
;
Readable
.
prototype
.
isPaused
=
function
(
)
{
return
this
.
_readableState
.
flowing
===
false
;
}
;
function
readableAddChunk
(
stream
,
state
,
chunk
,
encoding
,
addToFront
)
{
var
er
=
chunkInvalid
(
state
,
chunk
)
;
if
(
er
)
{
stream
.
emit
(
'error'
,
er
)
;
}
else
if
(
chunk
===
null
)
{
state
.
reading
=
false
;
onEofChunk
(
stream
,
state
)
;
}
else
if
(
state
.
objectMode
||
chunk
&&
chunk
.
length
>
0
)
{
if
(
state
.
ended
&&
!
addToFront
)
{
const
e
=
new
Error
(
'stream.push() after EOF'
)
;
stream
.
emit
(
'error'
,
e
)
;
}
else
if
(
state
.
endEmitted
&&
addToFront
)
{
const
e
=
new
Error
(
'stream.unshift() after end event'
)
;
stream
.
emit
(
'error'
,
e
)
;
}
else
{
var
skipAdd
;
if
(
state
.
decoder
&&
!
addToFront
&&
!
encoding
)
{
chunk
=
state
.
decoder
.
write
(
chunk
)
;
skipAdd
=
(
!
state
.
objectMode
&&
chunk
.
length
===
0
)
;
}
if
(
!
addToFront
)
state
.
reading
=
false
;
// Don't add to the buffer if we've decoded to an empty string chunk and
// we're not in object mode
if
(
!
skipAdd
)
{
// if we want the data now, just emit it.
if
(
state
.
flowing
&&
state
.
length
===
0
&&
!
state
.
sync
)
{
stream
.
emit
(
'data'
,
chunk
)
;
stream
.
read
(
0
)
;
}
else
{
// update the buffer info.
state
.
length
+=
state
.
objectMode
?
1
:
chunk
.
length
;
if
(
addToFront
)
state
.
buffer
.
unshift
(
chunk
)
;
else
state
.
buffer
.
push
(
chunk
)
;
if
(
state
.
needReadable
)
emitReadable
(
stream
)
;
}
}
maybeReadMore
(
stream
,
state
)
;
}
}
else
if
(
!
addToFront
)
{
state
.
reading
=
false
;
}
return
needMoreData
(
state
)
;
}
// if it's past the high water mark, we can push in some more.
// Also, if we have no data yet, we can stand some
// more bytes. This is to work around cases where hwm=0,
// such as the repl. Also, if the push() triggered a
// readable event, and the user called read(largeNumber) such that
// needReadable was set, then we ought to push more, so that another
// 'readable' event will be triggered.
function
needMoreData
(
state
)
{
return
!
state
.
ended
&&
(
state
.
needReadable
||
state
.
length
<
state
.
highWaterMark
||
state
.
length
===
0
)
;
}
// backwards compatibility.
Readable
.
prototype
.
setEncoding
=
function
(
enc
)
{
if
(
!
StringDecoder
)
StringDecoder
=
require
(
'string_decoder'
)
.
StringDecoder
;
this
.
_readableState
.
decoder
=
new
StringDecoder
(
enc
)
;
this
.
_readableState
.
encoding
=
enc
;
return
this
;
}
;
// Don't raise the hwm > 8MB
const
MAX_HWM
=
0x800000
;
function
computeNewHighWaterMark
(
n
)
{
if
(
n
>=
MAX_HWM
)
{
n
=
MAX_HWM
;
}
else
{
// Get the next highest power of 2 to prevent increasing hwm excessively in
// tiny amounts
n
--
;
n
|=
n
>>>
1
;
n
|=
n
>>>
2
;
n
|=
n
>>>
4
;
n
|=
n
>>>
8
;
n
|=
n
>>>
16
;
n
++
;
}
return
n
;
}
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function
howMuchToRead
(
n
,
state
)
{
if
(
n
<=
0
||
(
state
.
length
===
0
&&
state
.
ended
)
)
return
0
;
if
(
state
.
objectMode
)
return
1
;
if
(
n
!==
n
)
{
// Only flow one buffer at a time
if
(
state
.
flowing
&&
state
.
length
)
return
state
.
buffer
.
head
.
data
.
length
;
else
return
state
.
length
;
}
// If we're asking for more than the current hwm, then raise the hwm.
if
(
n
>
state
.
highWaterMark
)
state
.
highWaterMark
=
computeNewHighWaterMark
(
n
)
;
if
(
n
<=
state
.
length
)
return
n
;
// Don't have enough
if
(
!
state
.
ended
)
{
state
.
needReadable
=
true
;
return
0
;
}
return
state
.
length
;
}
// you can override either this method, or the async _read(n) below.
Readable
.
prototype
.
read
=
function
(
n
)
{
debug
(
'read'
,
n
)
;
n
=
parseInt
(
n
,
10
)
;
var
state
=
this
.
_readableState
;
var
nOrig
=
n
;
if
(
n
!==
0
)
state
.
emittedReadable
=
false
;
// if we're doing read(0) to trigger a readable event, but we
// already have a bunch of data in the buffer, then just trigger
// the 'readable' event and move on.
if
(
n
===
0
&&
state
.
needReadable
&&
(
state
.
length
>=
state
.
highWaterMark
||
state
.
ended
)
)
{
debug
(
'read: emitReadable'
,
state
.
length
,
state
.
ended
)
;
if
(
state
.
length
===
0
&&
state
.
ended
)
endReadable
(
this
)
;
else
emitReadable
(
this
)
;
return
null
;
}
n
=
howMuchToRead
(
n
,
state
)
;
// if we've ended, and we're now clear, then finish it up.
if
(
n
===
0
&&
state
.
ended
)
{
if
(
state
.
length
===
0
)
endReadable
(
this
)
;
return
null
;
}
// All the actual chunk generation logic needs to be
// *below* the call to _read. The reason is that in certain
// synthetic stream cases, such as passthrough streams, _read
// may be a completely synchronous operation which may change
// the state of the read buffer, providing enough data when
// before there was *not* enough.
//
// So, the steps are:
// 1. Figure out what the state of things will be after we do
// a read from the buffer.
//
// 2. If that resulting state will trigger a _read, then call _read.
// Note that this may be asynchronous, or synchronous. Yes, it is
// deeply ugly to write APIs this way, but that still doesn't mean
// that the Readable class should behave improperly, as streams are
// designed to be sync/async agnostic.
// Take note if the _read call is sync or async (ie, if the read call
// has returned yet), so that we know whether or not it's safe to emit
// 'readable' etc.
//
// 3. Actually pull the requested chunks out of the buffer and return.
// if we need a readable event, then we need to do some reading.
var
doRead
=
state
.
needReadable
;
debug
(
'need readable'
,
doRead
)
;
// if we currently have less than the highWaterMark, then also read some
if
(
state
.
length
===
0
||
state
.
length
-
n
<
state
.
highWaterMark
)
{
doRead
=
true
;
debug
(
'length less than watermark'
,
doRead
)
;
}
// however, if we've ended, then there's no point, and if we're already
// reading, then it's unnecessary.
if
(
state
.
ended
||
state
.
reading
)
{
doRead
=
false
;
debug
(
'reading or ended'
,
doRead
)
;
}
else
if
(
doRead
)
{
debug
(
'do read'
)
;
state
.
reading
=
true
;
state
.
sync
=
true
;
// if the length is currently zero, then we *need* a readable event.
if
(
state
.
length
===
0
)
state
.
needReadable
=
true
;
// call internal read method
this
.
_read
(
state
.
highWaterMark
)
;
state
.
sync
=
false
;
// If _read pushed data synchronously, then `reading` will be false,
// and we need to re-evaluate how much data we can return to the user.
if
(
!
state
.
reading
)
n
=
howMuchToRead
(
nOrig
,
state
)
;
}
var
ret
;
if
(
n
>
0
)
ret
=
fromList
(
n
,
state
)
;
else
ret
=
null
;
if
(
ret
===
null
)
{
state
.
needReadable
=
true
;
n
=
0
;
}
else
{
state
.
length
-=
n
;
}
if
(
state
.
length
===
0
)
{
// If we have nothing in the buffer, then we want to know
// as soon as we *do* get something into the buffer.
if
(
!
state
.
ended
)
state
.
needReadable
=
true
;
// If we tried to read() past the EOF, then emit end on the next tick.
if
(
nOrig
!==
n
&&
state
.
ended
)
endReadable
(
this
)
;
}
if
(
ret
!==
null
)
this
.
emit
(
'data'
,
ret
)
;
return
ret
;
}
;
function
chunkInvalid
(
state
,
chunk
)
{
var
er
=
null
;
if
(
!
(
chunk
instanceof
Buffer
)
&&
typeof
chunk
!==
'string'
&&
chunk
!==
null
&&
chunk
!==
undefined
&&
!
state
.
objectMode
)
{
er
=
new
TypeError
(
'Invalid non-string/buffer chunk'
)
;
}
return
er
;
}
function
onEofChunk
(
stream
,
state
)
{
if
(
state
.
ended
)
return
;
if
(
state
.
decoder
)
{
var
chunk
=
state
.
decoder
.
end
(
)
;
if
(
chunk
&&
chunk
.
length
)
{
state
.
buffer
.
push
(
chunk
)
;
state
.
length
+=
state
.
objectMode
?
1
:
chunk
.
length
;
}
}
state
.
ended
=
true
;
// emit 'readable' now to make sure it gets picked up.
emitReadable
(
stream
)
;
}
// Don't emit readable right away in sync mode, because this can trigger
// another read() call => stack overflow. This way, it might trigger
// a nextTick recursion warning, but that's not so bad.
function
emitReadable
(
stream
)
{
var
state
=
stream
.
_readableState
;
state
.
needReadable
=
false
;
if
(
!
state
.
emittedReadable
)
{
debug
(
'emitReadable'
,
state
.
flowing
)
;
state
.
emittedReadable
=
true
;
if
(
state
.
sync
)
process
.
nextTick
(
emitReadable_
,
stream
)
;
else
emitReadable_
(
stream
)
;
}
}
function
emitReadable_
(
stream
)
{
debug
(
'emit readable'
)
;
stream
.
emit
(
'readable'
)
;
flow
(
stream
)
;
}
// at this point, the user has presumably seen the 'readable' event,
// and called read() to consume some data. that may have triggered
// in turn another _read(n) call, in which case reading = true if
// it's in progress.
// However, if we're not ended, or reading, and the length < hwm,
// then go ahead and try to read some more preemptively.
function
maybeReadMore
(
stream
,
state
)
{
if
(
!
state
.
readingMore
)
{
state
.
readingMore
=
true
;
process
.
nextTick
(
maybeReadMore_
,
stream
,
state
)
;
}
}
function
maybeReadMore_
(
stream
,
state
)
{
var
len
=
state
.
length
;
while
(
!
state
.
reading
&&
!
state
.
flowing
&&
!
state
.
ended
&&
state
.
length
<
state
.
highWaterMark
)
{
debug
(
'maybeReadMore read 0'
)
;
stream
.
read
(
0
)
;
if
(
len
===
state
.
length
)
// didn't get any data, stop spinning.
break
;
else
len
=
state
.
length
;
}
state
.
readingMore
=
false
;
}
// abstract method. to be overridden in specific implementation classes.
// call cb(er, data) where data is <= n in length.
// for virtual (non-string, non-buffer) streams, "length" is somewhat
// arbitrary, and perhaps not very meaningful.
Readable
.
prototype
.
_read
=
function
(
n
)
{
this
.
emit
(
'error'
,
new
Error
(
'_read() is not implemented'
)
)
;
}
;
Readable
.
prototype
.
pipe
=
function
(
dest
,
pipeOpts
)
{
var
src
=
this
;
var
state
=
this
.
_readableState
;
switch
(
state
.
pipesCount
)
{
case
0
:
state
.
pipes
=
dest
;
break
;
case
1
:
state
.
pipes
=
[
state
.
pipes
,
dest
]
;
break
;
default
:
state
.
pipes
.
push
(
dest
)
;
break
;
}
state
.
pipesCount
+=
1
;
debug
(
'pipe count=%d opts=%j'
,
state
.
pipesCount
,
pipeOpts
)
;
var
doEnd
=
(
!
pipeOpts
||
pipeOpts
.
end
!==
false
)
&&
dest
!==
process
.
stdout
&&
dest
!==
process
.
stderr
;
var
endFn
=
doEnd
?
onend
:
unpipe
;
if
(
state
.
endEmitted
)
process
.
nextTick
(
endFn
)
;
else
src
.
once
(
'end'
,
endFn
)
;
dest
.
on
(
'unpipe'
,
onunpipe
)
;
function
onunpipe
(
readable
,
unpipeInfo
)
{
debug
(
'onunpipe'
)
;
if
(
readable
===
src
)
{
if
(
unpipeInfo
&&
unpipeInfo
.
hasUnpiped
===
false
)
{
unpipeInfo
.
hasUnpiped
=
true
;
cleanup
(
)
;
}
}
}
function
onend
(
)
{
debug
(
'onend'
)
;
dest
.
end
(
)
;
}
// when the dest drains, it reduces the awaitDrain counter
// on the source. This would be more elegant with a .once()
// handler in flow(), but adding and removing repeatedly is
// too slow.
var
ondrain
=
pipeOnDrain
(
src
)
;
dest
.
on
(
'drain'
,
ondrain
)
;
var
cleanedUp
=
false
;
function
cleanup
(
)
{
debug
(
'cleanup'
)
;
// cleanup event handlers once the pipe is broken
dest
.
removeListener
(
'close'
,
onclose
)
;
dest
.
removeListener
(
'finish'
,
onfinish
)
;
dest
.
removeListener
(
'drain'
,
ondrain
)
;
dest
.
removeListener
(
'error'
,
onerror
)
;
dest
.
removeListener
(
'unpipe'
,
onunpipe
)
;
src
.
removeListener
(
'end'
,
onend
)
;
src
.
removeListener
(
'end'
,
unpipe
)
;
src
.
removeListener
(
'data'
,
ondata
)
;
cleanedUp
=
true
;
// if the reader is waiting for a drain event from this
// specific writer, then it would cause it to never start
// flowing again.
// So, if this is awaiting a drain, then we just call it now.
// If we don't know, then assume that we are waiting for one.
if
(
state
.
awaitDrain
&&
(
!
dest
.
_writableState
||
dest
.
_writableState
.
needDrain
)
)
ondrain
(
)
;
}
// If the user pushes more data while we're writing to dest then we'll end up
// in ondata again. However, we only want to increase awaitDrain once because
// dest will only emit one 'drain' event for the multiple writes.
// => Introduce a guard on increasing awaitDrain.
var
increasedAwaitDrain
=
false
;
src
.
on
(
'data'
,
ondata
)
;
function
ondata
(
chunk
)
{
debug
(
'ondata'
)
;
increasedAwaitDrain
=
false
;
var
ret
=
dest
.
write
(
chunk
)
;
if
(
false
===
ret
&&
!
increasedAwaitDrain
)
{
// If the user unpiped during `dest.write()`, it is possible
// to get stuck in a permanently paused state if that write
// also returned false.
// => Check whether `dest` is still a piping destination.
if
(
(
(
state
.
pipesCount
===
1
&&
state
.
pipes
===
dest
)
||
(
state
.
pipesCount
>
1
&&
state
.
pipes
.
indexOf
(
dest
)
!==
-
1
)
)
&&
!
cleanedUp
)
{
debug
(
'false write response, pause'
,
src
.
_readableState
.
awaitDrain
)
;
src
.
_readableState
.
awaitDrain
++
;
increasedAwaitDrain
=
true
;
}
src
.
pause
(
)
;
}
}
// if the dest has an error, then stop piping into it.
// however, don't suppress the throwing behavior for this.
function
onerror
(
er
)
{
debug
(
'onerror'
,
er
)
;
unpipe
(
)
;
dest
.
removeListener
(
'error'
,
onerror
)
;
if
(
EE
.
listenerCount
(
dest
,
'error'
)
===
0
)
dest
.
emit
(
'error'
,
er
)
;
}
// Make sure our error handler is attached before userland ones.
prependListener
(
dest
,
'error'
,
onerror
)
;
// Both close and finish should trigger unpipe, but only once.
function
onclose
(
)
{
dest
.
removeListener
(
'finish'
,
onfinish
)
;
unpipe
(
)
;
}
dest
.
once
(
'close'
,
onclose
)
;
function
onfinish
(
)
{
debug
(
'onfinish'
)
;
dest
.
removeListener
(
'close'
,
onclose
)
;
unpipe
(
)
;
}
dest
.
once
(
'finish'
,
onfinish
)
;
function
unpipe
(
)
{
debug
(
'unpipe'
)
;
src
.
unpipe
(
dest
)
;
}
// tell the dest that it's being piped to
dest
.
emit
(
'pipe'
,
src
)
;
// start the flow if it hasn't been started already.
if
(
!
state
.
flowing
)
{
debug
(
'pipe resume'
)
;
src
.
resume
(
)
;
}
return
dest
;
}
;
function
pipeOnDrain
(
src
)
{
return
function
(
)
{
var
state
=
src
.
_readableState
;
debug
(
'pipeOnDrain'
,
state
.
awaitDrain
)
;
if
(
state
.
awaitDrain
)
state
.
awaitDrain
--
;
if
(
state
.
awaitDrain
===
0
&&
EE
.
listenerCount
(
src
,
'data'
)
)
{
state
.
flowing
=
true
;
flow
(
src
)
;
}
}
;
}
Readable
.
prototype
.
unpipe
=
function
(
dest
)
{
var
state
=
this
.
_readableState
;
var
unpipeInfo
=
{
hasUnpiped
:
false
}
;
// if we're not piping anywhere, then do nothing.
if
(
state
.
pipesCount
===
0
)
return
this
;
// just one destination. most common case.
if
(
state
.
pipesCount
===
1
)
{
// passed in one, but it's not the right one.
if
(
dest
&&
dest
!==
state
.
pipes
)
return
this
;
if
(
!
dest
)
dest
=
state
.
pipes
;
// got a match.
state
.
pipes
=
null
;
state
.
pipesCount
=
0
;
state
.
flowing
=
false
;
if
(
dest
)
dest
.
emit
(
'unpipe'
,
this
,
unpipeInfo
)
;
return
this
;
}
// slow case. multiple pipe destinations.
if
(
!
dest
)
{
// remove all.
var
dests
=
state
.
pipes
;
var
len
=
state
.
pipesCount
;
state
.
pipes
=
null
;
state
.
pipesCount
=
0
;
state
.
flowing
=
false
;
for
(
var
i
=
0
;
i
<
len
;
i
++
)
dests
[
i
]
.
emit
(
'unpipe'
,
this
,
unpipeInfo
)
;
return
this
;
}
// try to find the right one.
var
index
=
state
.
pipes
.
indexOf
(
dest
)
;
if
(
index
===
-
1
)
return
this
;
state
.
pipes
.
splice
(
index
,
1
)
;
state
.
pipesCount
-=
1
;
if
(
state
.
pipesCount
===
1
)
state
.
pipes
=
state
.
pipes
[
0
]
;
dest
.
emit
(
'unpipe'
,
this
,
unpipeInfo
)
;
return
this
;
}
;
// set up data events if they are asked for
// Ensure readable listeners eventually get something
Readable
.
prototype
.
on
=
function
(
ev
,
fn
)
{
const
res
=
Stream
.
prototype
.
on
.
call
(
this
,
ev
,
fn
)
;
if
(
ev
===
'data'
)
{
// Start flowing on next tick if stream isn't explicitly paused
if
(
this
.
_readableState
.
flowing
!==
false
)
this
.
resume
(
)
;
}
else
if
(
ev
===
'readable'
)
{
const
state
=
this
.
_readableState
;
if
(
!
state
.
endEmitted
&&
!
state
.
readableListening
)
{
state
.
readableListening
=
state
.
needReadable
=
true
;
state
.
emittedReadable
=
false
;
if
(
!
state
.
reading
)
{
process
.
nextTick
(
nReadingNextTick
,
this
)
;
}
else
if
(
state
.
length
)
{
emitReadable
(
this
)
;
}
}
}
return
res
;
}
;
Readable
.
prototype
.
addListener
=
Readable
.
prototype
.
on
;
function
nReadingNextTick
(
self
)
{
debug
(
'readable nexttick read 0'
)
;
self
.
read
(
0
)
;
}
// pause() and resume() are remnants of the legacy readable stream API
// If the user uses them, then switch into old mode.
Readable
.
prototype
.
resume
=
function
(
)
{
var
state
=
this
.
_readableState
;
if
(
!
state
.
flowing
)
{
debug
(
'resume'
)
;
state
.
flowing
=
true
;
resume
(
this
,
state
)
;
}
return
this
;
}
;
function
resume
(
stream
,
state
)
{
if
(
!
state
.
resumeScheduled
)
{
state
.
resumeScheduled
=
true
;
process
.
nextTick
(
resume_
,
stream
,
state
)
;
}
}
function
resume_
(
stream
,
state
)
{
if
(
!
state
.
reading
)
{
debug
(
'resume read 0'
)
;
stream
.
read
(
0
)
;
}
state
.
resumeScheduled
=
false
;
state
.
awaitDrain
=
0
;
stream
.
emit
(
'resume'
)
;
flow
(
stream
)
;
if
(
state
.
flowing
&&
!
state
.
reading
)
stream
.
read
(
0
)
;
}
Readable
.
prototype
.
pause
=
function
(
)
{
debug
(
'call pause flowing=%j'
,
this
.
_readableState
.
flowing
)
;
if
(
false
!==
this
.
_readableState
.
flowing
)
{
debug
(
'pause'
)
;
this
.
_readableState
.
flowing
=
false
;
this
.
emit
(
'pause'
)
;
}
return
this
;
}
;
function
flow
(
stream
)
{
const
state
=
stream
.
_readableState
;
debug
(
'flow'
,
state
.
flowing
)
;
while
(
state
.
flowing
&&
stream
.
read
(
)
!==
null
)
;
}
// wrap an old-style stream as the async data source.
// This is *not* part of the readable stream interface.
// It is an ugly unfortunate mess of history.
Readable
.
prototype
.
wrap
=
function
(
stream
)
{
var
state
=
this
.
_readableState
;
var
paused
=
false
;
var
self
=
this
;
stream
.
on
(
'end'
,
function
(
)
{
debug
(
'wrapped end'
)
;
if
(
state
.
decoder
&&
!
state
.
ended
)
{
var
chunk
=
state
.
decoder
.
end
(
)
;
if
(
chunk
&&
chunk
.
length
)
self
.
push
(
chunk
)
;
}
self
.
push
(
null
)
;
}
)
;
stream
.
on
(
'data'
,
function
(
chunk
)
{
debug
(
'wrapped data'
)
;
if
(
state
.
decoder
)
chunk
=
state
.
decoder
.
write
(
chunk
)
;
// don't skip over falsy values in objectMode
if
(
state
.
objectMode
&&
(
chunk
===
null
||
chunk
===
undefined
)
)
return
;
else
if
(
!
state
.
objectMode
&&
(
!
chunk
||
!
chunk
.
length
)
)
return
;
var
ret
=
self
.
push
(
chunk
)
;
if
(
!
ret
)
{
paused
=
true
;
stream
.
pause
(
)
;
}
}
)
;
// proxy all the other methods.
// important when wrapping filters and duplexes.
for
(
var
i
in
stream
)
{
if
(
this
[
i
]
===
undefined
&&
typeof
stream
[
i
]
===
'function'
)
{
this
[
i
]
=
function
(
method
)
{
return
function
(
)
{
return
stream
[
method
]
.
apply
(
stream
,
arguments
)
;
}
;
}
(
i
)
;
}
}
// proxy certain important events.
for
(
var
n
=
0
;
n
<
kProxyEvents
.
length
;
n
++
)
{
stream
.
on
(
kProxyEvents
[
n
]
,
self
.
emit
.
bind
(
self
,
kProxyEvents
[
n
]
)
)
;
}
// when we try to consume some more bytes, simply unpause the
// underlying stream.
self
.
_read
=
function
(
n
)
{
debug
(
'wrapped _read'
,
n
)
;
if
(
paused
)
{
paused
=
false
;
stream
.
resume
(
)
;
}
}
;
return
self
;
}
;
// exposed for testing purposes only.
Readable
.
_fromList
=
fromList
;
// Pluck off n bytes from an array of buffers.
// Length is the combined lengths of all the buffers in the list.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function
fromList
(
n
,
state
)
{
// nothing buffered
if
(
state
.
length
===
0
)
return
null
;
var
ret
;
if
(
state
.
objectMode
)
ret
=
state
.
buffer
.
shift
(
)
;
else
if
(
!
n
||
n
>=
state
.
length
)
{
// read it all, truncate the list
if
(
state
.
decoder
)
ret
=
state
.
buffer
.
join
(
''
)
;
else
if
(
state
.
buffer
.
length
===
1
)
ret
=
state
.
buffer
.
head
.
data
;
else
ret
=
state
.
buffer
.
concat
(
state
.
length
)
;
state
.
buffer
.
clear
(
)
;
}
else
{
// read part of list
ret
=
fromListPartial
(
n
,
state
.
buffer
,
state
.
decoder
)
;
}
return
ret
;
}
// Extracts only enough buffered data to satisfy the amount requested.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function
fromListPartial
(
n
,
list
,
hasStrings
)
{
var
ret
;
if
(
n
<
list
.
head
.
data
.
length
)
{
// slice is the same for buffers and strings
ret
=
list
.
head
.
data
.
slice
(
0
,
n
)
;
list
.
head
.
data
=
list
.
head
.
data
.
slice
(
n
)
;
}
else
if
(
n
===
list
.
head
.
data
.
length
)
{
// first chunk is a perfect match
ret
=
list
.
shift
(
)
;
}
else
{
// result spans more than one buffer
ret
=
(
hasStrings
?
copyFromBufferString
(
n
,
list
)
:
copyFromBuffer
(
n
,
list
)
)
;
}
return
ret
;
}
// Copies a specified amount of characters from the list of buffered data
// chunks.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function
copyFromBufferString
(
n
,
list
)
{
var
p
=
list
.
head
;
var
c
=
1
;
var
ret
=
p
.
data
;
n
-=
ret
.
length
;
while
(
p
=
p
.
next
)
{
const
str
=
p
.
data
;
const
nb
=
(
n
>
str
.
length
?
str
.
length
:
n
)
;
if
(
nb
===
str
.
length
)
ret
+=
str
;
else
ret
+=
str
.
slice
(
0
,
n
)
;
n
-=
nb
;
if
(
n
===
0
)
{
if
(
nb
===
str
.
length
)
{
++
c
;
if
(
p
.
next
)
list
.
head
=
p
.
next
;
else
list
.
head
=
list
.
tail
=
null
;
}
else
{
list
.
head
=
p
;
p
.
data
=
str
.
slice
(
nb
)
;
}
break
;
}
++
c
;
}
list
.
length
-=
c
;
return
ret
;
}
// Copies a specified amount of bytes from the list of buffered data chunks.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function
copyFromBuffer
(
n
,
list
)
{
const
ret
=
Buffer
.
allocUnsafe
(
n
)
;
var
p
=
list
.
head
;
var
c
=
1
;
p
.
data
.
copy
(
ret
)
;
n
-=
p
.
data
.
length
;
while
(
p
=
p
.
next
)
{
const
buf
=
p
.
data
;
const
nb
=
(
n
>
buf
.
length
?
buf
.
length
:
n
)
;
buf
.
copy
(
ret
,
ret
.
length
-
n
,
0
,
nb
)
;
n
-=
nb
;
if
(
n
===
0
)
{
if
(
nb
===
buf
.
length
)
{
++
c
;
if
(
p
.
next
)
list
.
head
=
p
.
next
;
else
list
.
head
=
list
.
tail
=
null
;
}
else
{
list
.
head
=
p
;
p
.
data
=
buf
.
slice
(
nb
)
;
}
break
;
}
++
c
;
}
list
.
length
-=
c
;
return
ret
;
}
function
endReadable
(
stream
)
{
var
state
=
stream
.
_readableState
;
// If we get here before consuming all the bytes, then that is a
// bug in node. Should never happen.
if
(
state
.
length
>
0
)
throw
new
Error
(
'"endReadable()" called on non-empty stream'
)
;
if
(
!
state
.
endEmitted
)
{
state
.
ended
=
true
;
process
.
nextTick
(
endReadableNT
,
state
,
stream
)
;
}
}
function
endReadableNT
(
state
,
stream
)
{
// Check that we didn't get one last unshift.
if
(
!
state
.
endEmitted
&&
state
.
length
===
0
)
{
state
.
endEmitted
=
true
;
stream
.
readable
=
false
;
stream
.
emit
(
'end'
)
;
}
}
Back
|
FazBrowse Home
|
New Git URL