@@ -75,17 +75,10 @@ class Websocket
7575 */
7676 const BINARY_TYPE_ARRAYBUFFER_DEFLATE = "\xc2" ;
7777
78- /**
79- * Check the integrity of the package.
80- *
81- * @param string $buffer
82- * @param TcpConnection $connection
83- * @return int
84- */
8578 public static function input (string $ buffer , TcpConnection $ connection ): int
8679 {
87- $ connection ->websocketOrigin = $ connection -> websocketOrigin ?? null ;
88- $ connection ->websocketClientProtocol = $ connection -> websocketClientProtocol ?? null ;
80+ $ connection ->websocketOrigin ??= null ;
81+ $ connection ->websocketClientProtocol ??= null ;
8982 // Receive length.
9083 $ recvLen = strlen ($ buffer );
9184 // We need more data.
@@ -159,8 +152,7 @@ public static function input(string $buffer, TcpConnection $connection): int
159152 if ($ headLen > $ recvLen ) {
160153 return 0 ;
161154 }
162- $ pack = unpack ('nn/ntotal_len ' , $ buffer );
163- $ dataLen = $ pack ['total_len ' ];
155+ $ dataLen = unpack ('nn/ntotal_len ' , $ buffer )['total_len ' ];
164156 } else {
165157 if ($ dataLen === 127 ) {
166158 $ headLen = 14 ;
@@ -255,22 +247,13 @@ public static function input(string $buffer, TcpConnection $connection): int
255247 return 0 ;
256248 }
257249
258- /**
259- * Websocket encode.
260- *
261- * @param mixed $buffer
262- * @param TcpConnection $connection
263- * @return string
264- */
265250 public static function encode (mixed $ buffer , TcpConnection $ connection ): string
266251 {
267252 if (!is_scalar ($ buffer )) {
268253 $ buffer = json_encode ($ buffer , JSON_UNESCAPED_UNICODE );
269254 }
270255
271- if (empty ($ connection ->websocketType )) {
272- $ connection ->websocketType = static ::BINARY_TYPE_BLOB ;
273- }
256+ $ connection ->websocketType ??= static ::BINARY_TYPE_BLOB ;
274257
275258 if (ord ($ connection ->websocketType ) & 64 ) {
276259 $ buffer = static ::deflate ($ connection , $ buffer );
@@ -279,15 +262,11 @@ public static function encode(mixed $buffer, TcpConnection $connection): string
279262 $ firstByte = $ connection ->websocketType ;
280263 $ len = strlen ($ buffer );
281264
282- if ($ len <= 125 ) {
283- $ encodeBuffer = $ firstByte . chr ($ len ) . $ buffer ;
284- } else {
285- if ($ len <= 65535 ) {
286- $ encodeBuffer = $ firstByte . chr (126 ) . pack ("n " , $ len ) . $ buffer ;
287- } else {
288- $ encodeBuffer = $ firstByte . chr (127 ) . pack ("xxxxN " , $ len ) . $ buffer ;
289- }
290- }
265+ $ encodeBuffer = match (true ) {
266+ $ len <= 125 => $ firstByte . chr ($ len ) . $ buffer ,
267+ $ len <= 65535 => $ firstByte . chr (126 ) . pack ("n " , $ len ) . $ buffer ,
268+ default => $ firstByte . chr (127 ) . pack ("xxxxN " , $ len ) . $ buffer ,
269+ };
291270
292271 // Handshake not completed so temporary buffer websocket data waiting for send.
293272 if (empty ($ connection ->context ->websocketHandshake )) {
@@ -321,13 +300,6 @@ public static function encode(mixed $buffer, TcpConnection $connection): string
321300 return $ encodeBuffer ;
322301 }
323302
324- /**
325- * Websocket decode.
326- *
327- * @param string $buffer
328- * @param TcpConnection $connection
329- * @return string
330- */
331303 public static function decode (string $ buffer , TcpConnection $ connection ): string
332304 {
333305 $ firstByte = ord ($ buffer [0 ]);
@@ -336,18 +308,12 @@ public static function decode(string $buffer, TcpConnection $connection): string
336308 $ isFinFrame = (bool )($ firstByte >> 7 );
337309 $ rsv1 = 64 === ($ firstByte & 64 );
338310
339- if ($ len === 126 ) {
340- $ masks = substr ($ buffer , 4 , 4 );
341- $ data = substr ($ buffer , 8 );
342- } else {
343- if ($ len === 127 ) {
344- $ masks = substr ($ buffer , 10 , 4 );
345- $ data = substr ($ buffer , 14 );
346- } else {
347- $ masks = substr ($ buffer , 2 , 4 );
348- $ data = substr ($ buffer , 6 );
349- }
350- }
311+ [$ masks , $ data ] = match (true ) {
312+ $ len === 126 => [substr ($ buffer , 4 , 4 ), substr ($ buffer , 8 )],
313+ $ len === 127 => [substr ($ buffer , 10 , 4 ), substr ($ buffer , 14 )],
314+ default => [substr ($ buffer , 2 , 4 ), substr ($ buffer , 6 )],
315+ };
316+
351317 $ dataLength = strlen ($ data );
352318 $ masks = str_repeat ($ masks , (int )floor ($ dataLength / 4 )) . substr ($ masks , 0 , $ dataLength % 4 );
353319 $ decoded = $ data ^ $ masks ;
@@ -368,18 +334,10 @@ public static function decode(string $buffer, TcpConnection $connection): string
368334 return $ decoded ;
369335 }
370336
371- /**
372- * Inflate.
373- *
374- * @param TcpConnection $connection
375- * @param string $buffer
376- * @param bool $isFinFrame
377- * @return false|string
378- */
379- protected static function inflate (TcpConnection $ connection , string $ buffer , bool $ isFinFrame ): bool |string
337+ protected static function inflate (TcpConnection $ connection , string $ buffer , bool $ isFinFrame ): false |string
380338 {
381- if (! isset ( $ connection ->context ->inflator )) {
382- $ connection -> context -> inflator = inflate_init (
339+ $ connection ->context ->inflator ??=
340+ inflate_init (
383341 ZLIB_ENCODING_RAW ,
384342 [
385343 'level ' => -1 ,
@@ -388,7 +346,7 @@ protected static function inflate(TcpConnection $connection, string $buffer, boo
388346 'strategy ' => ZLIB_DEFAULT_STRATEGY
389347 ]
390348 );
391- }
349+
392350 if ($ isFinFrame ) {
393351 $ buffer .= "\x00\x00\xff\xff" ;
394352 }
@@ -402,17 +360,11 @@ protected static function inflate(TcpConnection $connection, string $buffer, boo
402360 return $ result ;
403361 }
404362
405- /**
406- * Deflate.
407- *
408- * @param TcpConnection $connection
409- * @param string $buffer
410- * @return false|string
411- */
412- protected static function deflate (TcpConnection $ connection , string $ buffer ): bool |string
363+ protected static function deflate (TcpConnection $ connection , string $ buffer ): false |string
413364 {
414- if (!isset ($ connection ->context ->deflator )) {
415- $ connection ->context ->deflator = deflate_init (
365+
366+ $ connection ->context ->deflator ??=
367+ deflate_init (
416368 ZLIB_ENCODING_RAW ,
417369 [
418370 'level ' => -1 ,
@@ -421,74 +373,75 @@ protected static function deflate(TcpConnection $connection, string $buffer): bo
421373 'strategy ' => ZLIB_DEFAULT_STRATEGY
422374 ]
423375 );
424- }
376+
425377 return substr (deflate_add ($ connection ->context ->deflator , $ buffer ), 0 , -4 );
426378 }
427379
428380 /**
429381 * Websocket handshake.
430382 *
431- * @param string $buffer
432- * @param TcpConnection $connection
433- * @return int
434383 */
435384 public static function dealHandshake (string $ buffer , TcpConnection $ connection ): int
436385 {
437386 // HTTP protocol.
438- if (str_starts_with ($ buffer , 'GET ' )) {
439- // Find \r\n\r\n.
440- $ headerEndPos = strpos ($ buffer , "\r\n\r\n" );
441- if (!$ headerEndPos ) {
442- return 0 ;
443- }
444- $ headerLength = $ headerEndPos + 4 ;
387+ if (!str_starts_with ($ buffer , 'GET ' )) {
388+ // Bad websocket handshake request.
389+ $ connection ->close (
390+ "HTTP/1.1 400 Bad Request \r\nServer: workerman \r\n\r\n<div style= \"text-align:center \"><h1>400 Bad Request</h1><hr>workerman</div> " , true );
391+ return 0 ;
392+ }
445393
446- // Get Sec-WebSocket-Key.
447- if (preg_match ("/Sec-WebSocket-Key: *(.*?) \r\n/i " , $ buffer , $ match )) {
448- $ SecWebSocketKey = $ match [1 ];
449- } else {
450- $ connection ->close (
451- "HTTP/1.0 400 Bad Request \r\nServer: workerman \r\n\r\n<div style= \"text-align:center \"><h1>WebSocket</h1><hr>workerman</div> " , true );
452- return 0 ;
453- }
454- // Calculation websocket key.
455- $ newKey = base64_encode (sha1 ($ SecWebSocketKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11 " , true ));
456- // Handshake response data.
457- $ handshakeMessage = "HTTP/1.1 101 Switching Protocol \r\n"
458- . "Upgrade: websocket \r\n"
459- . "Sec-WebSocket-Version: 13 \r\n"
460- . "Connection: Upgrade \r\n"
461- . "Sec-WebSocket-Accept: " . $ newKey . "\r\n" ;
462-
463- // Websocket data buffer.
464- $ connection ->context ->websocketDataBuffer = '' ;
465- // Current websocket frame length.
466- $ connection ->context ->websocketCurrentFrameLength = 0 ;
467- // Current websocket frame data.
468- $ connection ->context ->websocketCurrentFrameBuffer = '' ;
469- // Consume handshake data.
470- $ connection ->consumeRecvBuffer ($ headerLength );
471- // Request from buffer
472- $ request = new Request ($ buffer );
473-
474- // Try to emit onWebSocketConnect callback.
475- $ onWebsocketConnect = $ connection ->onWebSocketConnect ?? $ connection ->worker ->onWebSocketConnect ?? false ;
476- if ($ onWebsocketConnect ) {
477- try {
478- $ onWebsocketConnect ($ connection , $ request );
479- } catch (Throwable $ e ) {
480- Worker::stopAll (250 , $ e );
481- }
482- }
394+ // Find \r\n\r\n.
395+ $ headerEndPos = strpos ($ buffer , "\r\n\r\n" );
396+ if (!$ headerEndPos ) {
397+ return 0 ;
398+ }
399+ $ headerLength = $ headerEndPos + 4 ;
483400
484- // blob or arraybuffer
485- if (empty ($ connection ->websocketType )) {
486- $ connection ->websocketType = static ::BINARY_TYPE_BLOB ;
401+ // Get Sec-WebSocket-Key.
402+ if (preg_match ("/Sec-WebSocket-Key: *(.*?) \r\n/i " , $ buffer , $ match )) {
403+ $ SecWebSocketKey = $ match [1 ];
404+ } else {
405+ $ connection ->close (
406+ "HTTP/1.1 400 Bad Request \r\nServer: workerman \r\n\r\n<div style= \"text-align:center \"><h1>WebSocket</h1><hr>workerman</div> " , true );
407+ return 0 ;
408+ }
409+ // Calculation websocket key.
410+ $ newKey = base64_encode (sha1 ($ SecWebSocketKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11 " , true ));
411+ // Handshake response data.
412+ $ handshakeMessage = "HTTP/1.1 101 Switching Protocol \r\n"
413+ . "Upgrade: websocket \r\n"
414+ . "Sec-WebSocket-Version: 13 \r\n"
415+ . "Connection: Upgrade \r\n"
416+ . "Sec-WebSocket-Accept: $ newKey \r\n" ;
417+
418+ // Websocket data buffer.
419+ $ connection ->context ->websocketDataBuffer = '' ;
420+ // Current websocket frame length.
421+ $ connection ->context ->websocketCurrentFrameLength = 0 ;
422+ // Current websocket frame data.
423+ $ connection ->context ->websocketCurrentFrameBuffer = '' ;
424+ // Consume handshake data.
425+ $ connection ->consumeRecvBuffer ($ headerLength );
426+ // Request from buffer
427+ $ request = new Request ($ buffer );
428+
429+ // Try to emit onWebSocketConnect callback.
430+ $ onWebsocketConnect = $ connection ->onWebSocketConnect ?? $ connection ->worker ->onWebSocketConnect ?? false ;
431+ if ($ onWebsocketConnect ) {
432+ try {
433+ $ onWebsocketConnect ($ connection , $ request );
434+ } catch (Throwable $ e ) {
435+ Worker::stopAll (250 , $ e );
487436 }
437+ }
488438
489- $ hasServerHeader = false ;
439+ // blob or arraybuffer
440+ $ connection ->websocketType ??= static ::BINARY_TYPE_BLOB ;
490441
491- if ($ connection ->headers ) {
442+ $ hasServerHeader = false ;
443+
444+ if ($ connection ->headers ) {
492445 foreach ($ connection ->headers as $ header ) {
493446 if (strpbrk ($ header , "\r\n" ) !== false ) {
494447 continue ;
@@ -498,39 +451,34 @@ public static function dealHandshake(string $buffer, TcpConnection $connection):
498451 }
499452 $ handshakeMessage .= "$ header \r\n" ;
500453 }
454+ }
455+ if (!$ hasServerHeader ) {
456+ $ handshakeMessage .= "Server: workerman \r\n" ;
457+ }
458+ $ handshakeMessage .= "\r\n" ;
459+ // Send handshake response.
460+ $ connection ->send ($ handshakeMessage , true );
461+ // Mark handshake complete.
462+ $ connection ->context ->websocketHandshake = true ;
463+
464+ // Try to emit onWebSocketConnected callback.
465+ $ onWebsocketConnected = $ connection ->onWebSocketConnected ?? $ connection ->worker ->onWebSocketConnected ?? false ;
466+ if ($ onWebsocketConnected ) {
467+ try {
468+ $ onWebsocketConnected ($ connection , $ request );
469+ } catch (Throwable $ e ) {
470+ Worker::stopAll (250 , $ e );
501471 }
502- if (!$ hasServerHeader ) {
503- $ handshakeMessage .= "Server: workerman \r\n" ;
504- }
505- $ handshakeMessage .= "\r\n" ;
506- // Send handshake response.
507- $ connection ->send ($ handshakeMessage , true );
508- // Mark handshake complete.
509- $ connection ->context ->websocketHandshake = true ;
510-
511- // Try to emit onWebSocketConnected callback.
512- $ onWebsocketConnected = $ connection ->onWebSocketConnected ?? $ connection ->worker ->onWebSocketConnected ?? false ;
513- if ($ onWebsocketConnected ) {
514- try {
515- $ onWebsocketConnected ($ connection , $ request );
516- } catch (Throwable $ e ) {
517- Worker::stopAll (250 , $ e );
518- }
519- }
472+ }
520473
521- // There are data waiting to be sent.
522- if (!empty ($ connection ->context ->tmpWebsocketData )) {
523- $ connection ->send ($ connection ->context ->tmpWebsocketData , true );
524- $ connection ->context ->tmpWebsocketData = '' ;
525- }
526- if (strlen ($ buffer ) > $ headerLength ) {
527- return static ::input (substr ($ buffer , $ headerLength ), $ connection );
528- }
529- return 0 ;
474+ // There are data waiting to be sent.
475+ if (!empty ($ connection ->context ->tmpWebsocketData )) {
476+ $ connection ->send ($ connection ->context ->tmpWebsocketData , true );
477+ $ connection ->context ->tmpWebsocketData = '' ;
478+ }
479+ if (strlen ($ buffer ) > $ headerLength ) {
480+ return static ::input (substr ($ buffer , $ headerLength ), $ connection );
530481 }
531- // Bad websocket handshake request.
532- $ connection ->close (
533- "HTTP/1.0 400 Bad Request \r\nServer: workerman \r\n\r\n<div style= \"text-align:center \"><h1>400 Bad Request</h1><hr>workerman</div> " , true );
534482 return 0 ;
535483 }
536484}
0 commit comments