@@ -36,6 +36,71 @@ class Sender {
36
36
this . onerror = null ;
37
37
}
38
38
39
+ /**
40
+ * Frames a piece of data according to the HyBi WebSocket protocol.
41
+ *
42
+ * @param {Buffer } data The data to frame
43
+ * @param {Object } options Options object
44
+ * @param {Number } options.opcode The opcode
45
+ * @param {Boolean } options.readOnly Specifies whether `data` can be modified
46
+ * @param {Boolean } options.fin Specifies whether or not to set the FIN bit
47
+ * @param {Boolean } options.mask Specifies whether or not to mask `data`
48
+ * @param {Boolean } options.rsv1 Specifies whether or not to set the RSV1 bit
49
+ * @return {Buffer[] } The framed data as a list of `Buffer` instances
50
+ * @public
51
+ */
52
+ static frame ( data , options ) {
53
+ const merge = data . length < 1024 || options . mask && options . readOnly ;
54
+ var offset = options . mask ? 6 : 2 ;
55
+ var payloadLength = data . length ;
56
+
57
+ if ( data . length >= 65536 ) {
58
+ offset += 8 ;
59
+ payloadLength = 127 ;
60
+ } else if ( data . length > 125 ) {
61
+ offset += 2 ;
62
+ payloadLength = 126 ;
63
+ }
64
+
65
+ const target = Buffer . allocUnsafe ( merge ? data . length + offset : offset ) ;
66
+
67
+ target [ 0 ] = options . fin ? options . opcode | 0x80 : options . opcode ;
68
+ if ( options . rsv1 ) target [ 0 ] |= 0x40 ;
69
+
70
+ if ( payloadLength === 126 ) {
71
+ target . writeUInt16BE ( data . length , 2 , true ) ;
72
+ } else if ( payloadLength === 127 ) {
73
+ target . writeUInt32BE ( 0 , 2 , true ) ;
74
+ target . writeUInt32BE ( data . length , 6 , true ) ;
75
+ }
76
+
77
+ if ( ! options . mask ) {
78
+ target [ 1 ] = payloadLength ;
79
+ if ( merge ) {
80
+ data . copy ( target , offset ) ;
81
+ return [ target ] ;
82
+ }
83
+
84
+ return [ target , data ] ;
85
+ }
86
+
87
+ const mask = crypto . randomBytes ( 4 ) ;
88
+
89
+ target [ 1 ] = payloadLength | 0x80 ;
90
+ target [ offset - 4 ] = mask [ 0 ] ;
91
+ target [ offset - 3 ] = mask [ 1 ] ;
92
+ target [ offset - 2 ] = mask [ 2 ] ;
93
+ target [ offset - 1 ] = mask [ 3 ] ;
94
+
95
+ if ( merge ) {
96
+ bufferUtil . mask ( data , mask , target , offset , data . length ) ;
97
+ return [ target ] ;
98
+ }
99
+
100
+ bufferUtil . mask ( data , mask , data , 0 , data . length ) ;
101
+ return [ target , data ] ;
102
+ }
103
+
39
104
/**
40
105
* Sends a close message to the other peer.
41
106
*
@@ -71,13 +136,13 @@ class Sender {
71
136
* @private
72
137
*/
73
138
doClose ( data , mask , cb ) {
74
- this . frameAndSend ( data , {
139
+ this . sendFrame ( Sender . frame ( data , {
75
140
readOnly : false ,
76
141
opcode : 0x08 ,
77
142
rsv1 : false ,
78
143
fin : true ,
79
144
mask
80
- } , cb ) ;
145
+ } ) , cb ) ;
81
146
}
82
147
83
148
/**
@@ -117,13 +182,13 @@ class Sender {
117
182
* @private
118
183
*/
119
184
doPing ( data , mask , readOnly ) {
120
- this . frameAndSend ( data , {
185
+ this . sendFrame ( Sender . frame ( data , {
121
186
opcode : 0x09 ,
122
187
rsv1 : false ,
123
188
fin : true ,
124
189
readOnly,
125
190
mask
126
- } ) ;
191
+ } ) ) ;
127
192
}
128
193
129
194
/**
@@ -163,13 +228,13 @@ class Sender {
163
228
* @private
164
229
*/
165
230
doPong ( data , mask , readOnly ) {
166
- this . frameAndSend ( data , {
231
+ this . sendFrame ( Sender . frame ( data , {
167
232
opcode : 0x0a ,
168
233
rsv1 : false ,
169
234
fin : true ,
170
235
readOnly,
171
236
mask
172
- } ) ;
237
+ } ) ) ;
173
238
}
174
239
175
240
/**
@@ -229,13 +294,13 @@ class Sender {
229
294
this . dispatch ( data , opts , cb ) ;
230
295
}
231
296
} else {
232
- this . frameAndSend ( data , {
297
+ this . sendFrame ( Sender . frame ( data , {
233
298
mask : options . mask ,
234
299
fin : options . fin ,
235
300
rsv1 : false ,
236
301
readOnly,
237
302
opcode
238
- } , cb ) ;
303
+ } ) , cb ) ;
239
304
}
240
305
}
241
306
@@ -255,7 +320,7 @@ class Sender {
255
320
*/
256
321
dispatch ( data , options , cb ) {
257
322
if ( ! options . compress ) {
258
- this . frameAndSend ( data , options , cb ) ;
323
+ this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
259
324
return ;
260
325
}
261
326
@@ -268,74 +333,12 @@ class Sender {
268
333
}
269
334
270
335
options . readOnly = false ;
271
- this . frameAndSend ( buf , options , cb ) ;
336
+ this . sendFrame ( Sender . frame ( buf , options ) , cb ) ;
272
337
this . deflating = false ;
273
338
this . dequeue ( ) ;
274
339
} ) ;
275
340
}
276
341
277
- /**
278
- * Frames and sends a piece of data according to the HyBi WebSocket protocol.
279
- *
280
- * @param {Buffer } data The data to send
281
- * @param {Object } options Options object
282
- * @param {Number } options.opcode The opcode
283
- * @param {Boolean } options.readOnly Specifies whether `data` can be modified
284
- * @param {Boolean } options.fin Specifies whether or not to set the FIN bit
285
- * @param {Boolean } options.mask Specifies whether or not to mask `data`
286
- * @param {Boolean } options.rsv1 Specifies whether or not to set the RSV1 bit
287
- * @param {Function } cb Callback
288
- * @private
289
- */
290
- frameAndSend ( data , options , cb ) {
291
- const mergeBuffers = data . length < 1024 || options . mask && options . readOnly ;
292
- var dataOffset = options . mask ? 6 : 2 ;
293
- var payloadLength = data . length ;
294
-
295
- if ( data . length >= 65536 ) {
296
- dataOffset += 8 ;
297
- payloadLength = 127 ;
298
- } else if ( data . length > 125 ) {
299
- dataOffset += 2 ;
300
- payloadLength = 126 ;
301
- }
302
-
303
- const outputBuffer = Buffer . allocUnsafe (
304
- mergeBuffers ? data . length + dataOffset : dataOffset
305
- ) ;
306
-
307
- outputBuffer [ 0 ] = options . fin ? options . opcode | 0x80 : options . opcode ;
308
- if ( options . rsv1 ) outputBuffer [ 0 ] |= 0x40 ;
309
-
310
- if ( payloadLength === 126 ) {
311
- outputBuffer . writeUInt16BE ( data . length , 2 , true ) ;
312
- } else if ( payloadLength === 127 ) {
313
- outputBuffer . writeUInt32BE ( 0 , 2 , true ) ;
314
- outputBuffer . writeUInt32BE ( data . length , 6 , true ) ;
315
- }
316
-
317
- if ( options . mask ) {
318
- const mask = getRandomMask ( ) ;
319
-
320
- outputBuffer [ 1 ] = payloadLength | 0x80 ;
321
- outputBuffer [ dataOffset - 4 ] = mask [ 0 ] ;
322
- outputBuffer [ dataOffset - 3 ] = mask [ 1 ] ;
323
- outputBuffer [ dataOffset - 2 ] = mask [ 2 ] ;
324
- outputBuffer [ dataOffset - 1 ] = mask [ 3 ] ;
325
-
326
- if ( mergeBuffers ) {
327
- bufferUtil . mask ( data , mask , outputBuffer , dataOffset , data . length ) ;
328
- } else {
329
- bufferUtil . mask ( data , mask , data , 0 , data . length ) ;
330
- }
331
- } else {
332
- outputBuffer [ 1 ] = payloadLength ;
333
- if ( mergeBuffers ) data . copy ( outputBuffer , dataOffset ) ;
334
- }
335
-
336
- sendFramedData ( this , outputBuffer , mergeBuffers ? null : data , cb ) ;
337
- }
338
-
339
342
/**
340
343
* Executes queued send operations.
341
344
*
@@ -360,6 +363,22 @@ class Sender {
360
363
this . bufferedBytes += params [ 1 ] . length ;
361
364
this . queue . push ( params ) ;
362
365
}
366
+
367
+ /**
368
+ * Sends a frame.
369
+ *
370
+ * @param {Buffer[] } list The frame to send
371
+ * @param {Function } cb Callback
372
+ * @private
373
+ */
374
+ sendFrame ( list , cb ) {
375
+ if ( list . length === 2 ) {
376
+ this . _socket . write ( list [ 0 ] ) ;
377
+ this . _socket . write ( list [ 1 ] , cb ) ;
378
+ } else {
379
+ this . _socket . write ( list [ 0 ] , cb ) ;
380
+ }
381
+ }
363
382
}
364
383
365
384
module . exports = Sender ;
@@ -380,31 +399,3 @@ function viewToBuffer (view) {
380
399
381
400
return buf ;
382
401
}
383
-
384
- /**
385
- * Generates a random mask.
386
- *
387
- * @return {Buffer } The mask
388
- * @private
389
- */
390
- function getRandomMask ( ) {
391
- return crypto . randomBytes ( 4 ) ;
392
- }
393
-
394
- /**
395
- * Sends a frame.
396
- *
397
- * @param {Sender } sender Sender instance
398
- * @param {Buffer } outputBuffer The data to send
399
- * @param {Buffer } data Additional data to send if frame is split into two buffers
400
- * @param {Function } cb Callback
401
- * @private
402
- */
403
- function sendFramedData ( sender , outputBuffer , data , cb ) {
404
- if ( data ) {
405
- sender . _socket . write ( outputBuffer ) ;
406
- sender . _socket . write ( data , cb ) ;
407
- } else {
408
- sender . _socket . write ( outputBuffer , cb ) ;
409
- }
410
- }
0 commit comments