Skip to content

Commit b352336

Browse files
committed
Make Rfc6455FrameCompiler::assertState() pass with interleaved control frames
1 parent 1dc9d2c commit b352336

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

src/Parser/Rfc6455FrameCompiler.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ public function compileFrame(WebsocketFrameType $frameType, string $data, bool $
2929
$this->compressPayload = !$isFinal || \strlen($data) > $this->compressionContext->getCompressionThreshold();
3030
}
3131

32-
$this->currentFrameType = match ($frameType) {
33-
WebsocketFrameType::Text, WebsocketFrameType::Binary => $frameType,
34-
default => $this->currentFrameType,
32+
$isDataFrame = match ($frameType) {
33+
WebsocketFrameType::Text, WebsocketFrameType::Binary => true,
34+
default => false,
3535
};
36+
if ($isDataFrame) {
37+
$this->currentFrameType = $frameType;
38+
}
3639

3740
$rsv = 0;
3841

@@ -51,7 +54,7 @@ public function compileFrame(WebsocketFrameType $frameType, string $data, bool $
5154
$isFinal = true; // Reset state in finally.
5255
throw $exception;
5356
} finally {
54-
if ($isFinal) {
57+
if (($isDataFrame || $frameType === WebsocketFrameType::Continuation) && $isFinal) {
5558
$this->currentFrameType = null;
5659
$this->compressPayload = false;
5760
}

test/WebsocketClientTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,45 @@ public function testStreamMultipleChunks(): void
266266
$client->streamText($stream);
267267
}
268268

269+
public function testStreamWithInterleavedControlFrames(): void
270+
{
271+
$packets = \array_map(fn(string $packet) => [$packet], [
272+
compile(WebsocketFrameType::Text, false, false, 'chunk1'),
273+
compile(WebsocketFrameType::Continuation, false, false, 'chunk2'),
274+
compile(WebsocketFrameType::Ping, false, true, "1"),
275+
compile(WebsocketFrameType::Continuation, false, false, 'chunk3'),
276+
compile(WebsocketFrameType::Ping, false, true, "2"),
277+
compile(WebsocketFrameType::Continuation, false, true, 'chunk4'),
278+
]);
279+
280+
$socket = $this->createSocket();
281+
$future = new DeferredFuture();
282+
$socket->expects($this->any())->method("read")->willReturnCallback(function() use ($future) {
283+
$future->getFuture()->await();
284+
});
285+
$socket->expects($this->atLeastOnce())
286+
->method('write')
287+
->withConsecutive(...$packets);
288+
289+
$client = $this->createClient($socket, frameSplitThreshold: 6);
290+
291+
$stream = new ReadableIterableStream((function () use ($client) {
292+
yield 'chunk1';
293+
yield 'chunk2';
294+
yield '';
295+
$client->ping();
296+
yield 'chunk3';
297+
yield '';
298+
$client->ping();
299+
yield 'chunk4';
300+
})());
301+
302+
$client->streamText($stream);
303+
304+
$future->complete();
305+
$client->close();
306+
}
307+
269308
public function testSendWithFailedSocket(): void
270309
{
271310
$socket = $this->createSocket();

0 commit comments

Comments
 (0)