@@ -8,216 +8,213 @@ const uv = process.binding('uv');
8
8
const debug = util . debuglog ( 'stream_wrap' ) ;
9
9
const errors = require ( 'internal/errors' ) ;
10
10
11
- function StreamWrap ( stream ) {
12
- const handle = new JSStream ( ) ;
13
-
14
- this . stream = stream ;
15
-
16
- this . _list = null ;
17
-
18
- const self = this ;
19
- handle . close = function ( cb ) {
20
- debug ( 'close' ) ;
21
- self . doClose ( cb ) ;
22
- } ;
23
- handle . isAlive = function ( ) {
24
- return self . isAlive ( ) ;
25
- } ;
26
- handle . isClosing = function ( ) {
27
- return self . isClosing ( ) ;
28
- } ;
29
- handle . onreadstart = function ( ) {
30
- return self . readStart ( ) ;
31
- } ;
32
- handle . onreadstop = function ( ) {
33
- return self . readStop ( ) ;
34
- } ;
35
- handle . onshutdown = function ( req ) {
36
- return self . doShutdown ( req ) ;
37
- } ;
38
- handle . onwrite = function ( req , bufs ) {
39
- return self . doWrite ( req , bufs ) ;
40
- } ;
41
-
42
- this . stream . pause ( ) ;
43
- this . stream . on ( 'error' , function onerror ( err ) {
44
- self . emit ( 'error' , err ) ;
45
- } ) ;
46
- this . stream . on ( 'data' , function ondata ( chunk ) {
47
- if ( typeof chunk === 'string' || this . _readableState . objectMode === true ) {
48
- // Make sure that no further `data` events will happen
49
- this . pause ( ) ;
50
- this . removeListener ( 'data' , ondata ) ;
51
-
52
- self . emit ( 'error' , new errors . Error ( 'ERR_STREAM_WRAP' ) ) ;
53
- return ;
54
- }
55
-
56
- debug ( 'data' , chunk . length ) ;
57
- if ( self . _handle )
58
- self . _handle . readBuffer ( chunk ) ;
59
- } ) ;
60
- this . stream . once ( 'end' , function onend ( ) {
61
- debug ( 'end' ) ;
62
- if ( self . _handle )
63
- self . _handle . emitEOF ( ) ;
64
- } ) ;
65
-
66
- Socket . call ( this , {
67
- handle : handle
68
- } ) ;
69
- }
70
- util . inherits ( StreamWrap , Socket ) ;
71
- module . exports = StreamWrap ;
72
-
73
- // require('_stream_wrap').StreamWrap
74
- StreamWrap . StreamWrap = StreamWrap ;
75
-
76
- StreamWrap . prototype . isAlive = function isAlive ( ) {
77
- return true ;
78
- } ;
79
-
80
- StreamWrap . prototype . isClosing = function isClosing ( ) {
81
- return ! this . readable || ! this . writable ;
82
- } ;
83
-
84
- StreamWrap . prototype . readStart = function readStart ( ) {
85
- this . stream . resume ( ) ;
86
- return 0 ;
87
- } ;
88
-
89
- StreamWrap . prototype . readStop = function readStop ( ) {
90
- this . stream . pause ( ) ;
91
- return 0 ;
92
- } ;
93
-
94
- StreamWrap . prototype . doShutdown = function doShutdown ( req ) {
95
- const self = this ;
96
- const handle = this . _handle ;
97
- const item = this . _enqueue ( 'shutdown' , req ) ;
98
-
99
- this . stream . end ( function ( ) {
100
- // Ensure that write was dispatched
101
- setImmediate ( function ( ) {
102
- if ( ! self . _dequeue ( item ) )
11
+ /* This class serves as a wrapper for when the C++ side of Node wants access
12
+ * to a standard JS stream. For example, TLS or HTTP do not operate on network
13
+ * resources conceptually, although that is the common case and what we are
14
+ * optimizing for; in theory, they are completely composable and can work with
15
+ * any stream resource they see.
16
+ *
17
+ * For the common case, i.e. a TLS socket wrapping around a net.Socket, we
18
+ * can skip going through the JS layer and let TLS access the raw C++ handle
19
+ * of a net.Socket. The flipside of this is that, to maintain composability,
20
+ * we need a way to create "fake" net.Socket instances that call back into a
21
+ * "real" JavaScript stream. JSStreamWrap is exactly this.
22
+ */
23
+ class JSStreamWrap extends Socket {
24
+ constructor ( stream ) {
25
+ const handle = new JSStream ( ) ;
26
+ handle . close = ( cb ) => {
27
+ debug ( 'close' ) ;
28
+ this . doClose ( cb ) ;
29
+ } ;
30
+ handle . isAlive = ( ) => this . isAlive ( ) ;
31
+ handle . isClosing = ( ) => this . isClosing ( ) ;
32
+ handle . onreadstart = ( ) => this . readStart ( ) ;
33
+ handle . onreadstop = ( ) => this . readStop ( ) ;
34
+ handle . onshutdown = ( req ) => this . doShutdown ( req ) ;
35
+ handle . onwrite = ( req , bufs ) => this . doWrite ( req , bufs ) ;
36
+
37
+ stream . pause ( ) ;
38
+ stream . on ( 'error' , ( err ) => this . emit ( 'error' , err ) ) ;
39
+ const ondata = ( chunk ) => {
40
+ if ( typeof chunk === 'string' ||
41
+ stream . _readableState . objectMode === true ) {
42
+ // Make sure that no further `data` events will happen.
43
+ stream . pause ( ) ;
44
+ stream . removeListener ( 'data' , ondata ) ;
45
+
46
+ this . emit ( 'error' , new errors . Error ( 'ERR_STREAM_WRAP' ) ) ;
103
47
return ;
48
+ }
104
49
105
- handle . finishShutdown ( req , 0 ) ;
50
+ debug ( 'data' , chunk . length ) ;
51
+ if ( this . _handle )
52
+ this . _handle . readBuffer ( chunk ) ;
53
+ } ;
54
+ stream . on ( 'data' , ondata ) ;
55
+ stream . once ( 'end' , ( ) => {
56
+ debug ( 'end' ) ;
57
+ if ( this . _handle )
58
+ this . _handle . emitEOF ( ) ;
106
59
} ) ;
107
- } ) ;
108
- return 0 ;
109
- } ;
110
60
111
- StreamWrap . prototype . doWrite = function doWrite ( req , bufs ) {
112
- const self = this ;
113
- const handle = self . _handle ;
61
+ super ( { handle, manualStart : true } ) ;
62
+ this . stream = stream ;
63
+ this . _list = null ;
64
+ this . read ( 0 ) ;
65
+ }
114
66
115
- var pending = bufs . length ;
67
+ // Legacy
68
+ static get StreamWrap ( ) {
69
+ return JSStreamWrap ;
70
+ }
116
71
117
- // Queue the request to be able to cancel it
118
- const item = self . _enqueue ( 'write' , req ) ;
72
+ isAlive ( ) {
73
+ return true ;
74
+ }
119
75
120
- self . stream . cork ( ) ;
121
- for ( var n = 0 ; n < bufs . length ; n ++ )
122
- self . stream . write ( bufs [ n ] , done ) ;
123
- self . stream . uncork ( ) ;
76
+ isClosing ( ) {
77
+ return ! this . readable || ! this . writable ;
78
+ }
124
79
125
- function done ( err ) {
126
- if ( ! err && -- pending !== 0 )
127
- return ;
80
+ readStart ( ) {
81
+ this . stream . resume ( ) ;
82
+ return 0 ;
83
+ }
128
84
129
- // Ensure that this is called once in case of error
130
- pending = 0 ;
85
+ readStop ( ) {
86
+ this . stream . pause ( ) ;
87
+ return 0 ;
88
+ }
131
89
132
- let errCode = 0 ;
133
- if ( err ) {
134
- const code = uv [ `UV_${ err . code } ` ] ;
135
- errCode = ( err . code && code ) ? code : uv . UV_EPIPE ;
136
- }
90
+ doShutdown ( req ) {
91
+ const handle = this . _handle ;
92
+ const item = this . _enqueue ( 'shutdown' , req ) ;
137
93
138
- // Ensure that write was dispatched
139
- setImmediate ( function ( ) {
140
- // Do not invoke callback twice
141
- if ( ! self . _dequeue ( item ) )
142
- return ;
94
+ this . stream . end ( ( ) => {
95
+ // Ensure that write was dispatched
96
+ setImmediate ( ( ) => {
97
+ if ( ! this . _dequeue ( item ) )
98
+ return ;
143
99
144
- handle . doAfterWrite ( req ) ;
145
- handle . finishWrite ( req , errCode ) ;
100
+ handle . finishShutdown ( req , 0 ) ;
101
+ } ) ;
146
102
} ) ;
103
+ return 0 ;
147
104
}
148
105
149
- return 0 ;
150
- } ;
106
+ doWrite ( req , bufs ) {
107
+ const self = this ;
108
+ const handle = this . _handle ;
151
109
152
- function QueueItem ( type , req ) {
153
- this . type = type ;
154
- this . req = req ;
155
- this . prev = this ;
156
- this . next = this ;
157
- }
110
+ var pending = bufs . length ;
158
111
159
- StreamWrap . prototype . _enqueue = function _enqueue ( type , req ) {
160
- const item = new QueueItem ( type , req ) ;
161
- if ( this . _list === null ) {
162
- this . _list = item ;
163
- return item ;
164
- }
112
+ // Queue the request to be able to cancel it
113
+ const item = this . _enqueue ( 'write' , req ) ;
114
+
115
+ this . stream . cork ( ) ;
116
+ for ( var n = 0 ; n < bufs . length ; n ++ )
117
+ this . stream . write ( bufs [ n ] , done ) ;
118
+ this . stream . uncork ( ) ;
119
+
120
+ function done ( err ) {
121
+ if ( ! err && -- pending !== 0 )
122
+ return ;
123
+
124
+ // Ensure that this is called once in case of error
125
+ pending = 0 ;
165
126
166
- item . next = this . _list . next ;
167
- item . prev = this . _list ;
168
- item . next . prev = item ;
169
- item . prev . next = item ;
127
+ let errCode = 0 ;
128
+ if ( err ) {
129
+ const code = uv [ `UV_${ err . code } ` ] ;
130
+ errCode = ( err . code && code ) ? code : uv . UV_EPIPE ;
131
+ }
170
132
171
- return item ;
172
- } ;
133
+ // Ensure that write was dispatched
134
+ setImmediate ( function ( ) {
135
+ // Do not invoke callback twice
136
+ if ( ! self . _dequeue ( item ) )
137
+ return ;
173
138
174
- StreamWrap . prototype . _dequeue = function _dequeue ( item ) {
175
- assert ( item instanceof QueueItem ) ;
139
+ handle . doAfterWrite ( req ) ;
140
+ handle . finishWrite ( req , errCode ) ;
141
+ } ) ;
142
+ }
176
143
177
- var next = item . next ;
178
- var prev = item . prev ;
144
+ return 0 ;
145
+ }
179
146
180
- if ( next === null && prev === null )
181
- return false ;
147
+ _enqueue ( type , req ) {
148
+ const item = new QueueItem ( type , req ) ;
149
+ if ( this . _list === null ) {
150
+ this . _list = item ;
151
+ return item ;
152
+ }
182
153
183
- item . next = null ;
184
- item . prev = null ;
154
+ item . next = this . _list . next ;
155
+ item . prev = this . _list ;
156
+ item . next . prev = item ;
157
+ item . prev . next = item ;
185
158
186
- if ( next === item ) {
187
- prev = null ;
188
- next = null ;
189
- } else {
190
- prev . next = next ;
191
- next . prev = prev ;
159
+ return item ;
192
160
}
193
161
194
- if ( this . _list === item )
195
- this . _list = next ;
162
+ _dequeue ( item ) {
163
+ assert ( item instanceof QueueItem ) ;
196
164
197
- return true ;
198
- } ;
165
+ var next = item . next ;
166
+ var prev = item . prev ;
199
167
200
- StreamWrap . prototype . doClose = function doClose ( cb ) {
201
- const self = this ;
202
- const handle = self . _handle ;
168
+ if ( next === null && prev === null )
169
+ return false ;
203
170
204
- setImmediate ( function ( ) {
205
- while ( self . _list !== null ) {
206
- const item = self . _list ;
207
- const req = item . req ;
208
- self . _dequeue ( item ) ;
171
+ item . next = null ;
172
+ item . prev = null ;
209
173
210
- const errCode = uv . UV_ECANCELED ;
211
- if ( item . type === 'write' ) {
212
- handle . doAfterWrite ( req ) ;
213
- handle . finishWrite ( req , errCode ) ;
214
- } else if ( item . type === 'shutdown' ) {
215
- handle . finishShutdown ( req , errCode ) ;
216
- }
174
+ if ( next === item ) {
175
+ prev = null ;
176
+ next = null ;
177
+ } else {
178
+ prev . next = next ;
179
+ next . prev = prev ;
217
180
}
218
181
219
- // Should be already set by net.js
220
- assert ( self . _handle === null ) ;
221
- cb ( ) ;
222
- } ) ;
223
- } ;
182
+ if ( this . _list === item )
183
+ this . _list = next ;
184
+
185
+ return true ;
186
+ }
187
+
188
+ doClose ( cb ) {
189
+ const handle = this . _handle ;
190
+
191
+ setImmediate ( ( ) => {
192
+ while ( this . _list !== null ) {
193
+ const item = this . _list ;
194
+ const req = item . req ;
195
+ this . _dequeue ( item ) ;
196
+
197
+ const errCode = uv . UV_ECANCELED ;
198
+ if ( item . type === 'write' ) {
199
+ handle . doAfterWrite ( req ) ;
200
+ handle . finishWrite ( req , errCode ) ;
201
+ } else if ( item . type === 'shutdown' ) {
202
+ handle . finishShutdown ( req , errCode ) ;
203
+ }
204
+ }
205
+
206
+ // Should be already set by net.js
207
+ assert . strictEqual ( this . _handle , null ) ;
208
+ cb ( ) ;
209
+ } ) ;
210
+ }
211
+ }
212
+
213
+ function QueueItem ( type , req ) {
214
+ this . type = type ;
215
+ this . req = req ;
216
+ this . prev = this ;
217
+ this . next = this ;
218
+ }
219
+
220
+ module . exports = JSStreamWrap ;
0 commit comments