Last active
July 30, 2024 15:02
-
-
Save masakielastic/9777eaf02907b18585974ba00764aab6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class FrameHeader { | |
private $bytes; | |
public function __construct(string $bytes) | |
{ | |
$this->bytes = $bytes; | |
} | |
public static function from(int $length, int $type, int $streamId, array $flags = []) | |
{ | |
$bytes = static::lengthString($length).chr($type). | |
static::flagString($flags).static::idString($streamId); | |
return new static($bytes); | |
} | |
private static function lengthString(int $length): string | |
{ | |
return match(true) { | |
0x100 > $length => "\x00\x00", | |
0x10000 > $length => "\x00", | |
default => "" | |
}.chr($length); | |
} | |
private static function flagString(array $flags): string | |
{ | |
$flag = 0x0; | |
if (count($flags)) { | |
foreach ($flags as $value) { | |
$flag += $value; | |
} | |
} | |
return pack("c", $flag); | |
} | |
private static function idString(int $id): string | |
{ | |
return match(true) { | |
0x100 > $id => "\x00\x00\x00", | |
0x10000 > $id => "\x00\x00", | |
0x1000000 > $id => "\x00", | |
default => "" | |
}.chr($id); | |
} | |
public function getBytes(): string | |
{ | |
return $this->bytes; | |
} | |
public function getLength() | |
{ | |
return hexdec(bin2hex(substr($this->bytes, 0, 3))); | |
} | |
public function getType() | |
{ | |
return ord(substr($this->bytes, 3, 1)); | |
} | |
public function getFlag() | |
{ | |
return ord(substr($this->bytes, 4, 1)); | |
} | |
} | |
class Frame { | |
private $bytes; | |
public function __construct(string $bytes) | |
{ | |
$this->bytes = $bytes; | |
} | |
public function getBytes(): string | |
{ | |
return $this->bytes; | |
} | |
} | |
class SettingsFrame extends Frame { | |
public static function from() | |
{ | |
$bytes = FrameHeader::from(0x0, 0x4, 0x0)->getBytes(); | |
return new static($bytes); | |
} | |
} | |
class Ack extends Frame { | |
public static function from() | |
{ | |
$bytes = FrameHeader::from(0x0, 0x4, 0x0, [0x01])->getBytes(); | |
return new static($bytes); | |
} | |
} | |
class HeadersFrame extends Frame { | |
public static function from(array $headers, array $flags = [], int $streamId) | |
{ | |
$payload = ''; | |
foreach ($headers as $header) { | |
$name = pack("c", strlen($header[0])).$header[0]; | |
$value = pack("c", strlen($header[1])).$header[1]; | |
$payload .= chr(0x0).$name.$value; | |
} | |
$header = FrameHeader::from(strlen($payload), 0x1, $streamId, $flags)->getBytes(); | |
return new static($header.$payload); | |
} | |
} | |
class DataFrame extends Frame { | |
public static function from(string $data, int $streamId, array $flags = []) | |
{ | |
$header = FrameHeader::from(strlen($data), 0x0, $streamId, $flags)->getBytes(); | |
return new static($header.$data); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class FrameParser implements \IteratorAggregate { | |
public function __construct(private string $bytes) | |
{ | |
} | |
public function getIterator(): \Generator | |
{ | |
$bytesSize = strlen($this->bytes); | |
$index = 0; | |
$current = 0; | |
$next = 0; | |
while (true) { | |
if ($next >= $bytesSize) { | |
break; | |
} | |
$size = hexdec(bin2hex(substr($this->bytes, $next, 3))) + 9; | |
$next += $size; | |
yield $index => substr($this->bytes, $current, $size); | |
$current = $next; | |
++$index; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require 'Frame.php'; | |
require 'FrameParser.php'; | |
function request($key = null): string | |
{ | |
$headers = [ | |
[':method', 'GET'], | |
[':path', '/'], | |
[':scheme', 'http'], | |
[':authority', 'localhost'] | |
]; | |
$ret = [ | |
'settings' => SettingsFrame::from()->getBytes(), | |
'ack' => Ack::from()->getBytes(), | |
'headers' => HeadersFrame::from($headers, 0x1, [0x1, 0x4])->getBytes() | |
]; | |
return empty($key) ? implode($ret) : $ret[$key]; | |
} | |
$bytes = request(); | |
$iter = new FrameParser($bytes); | |
$ret = []; | |
foreach ($iter as $index => $value) { | |
$ret[] = $value; | |
} | |
var_dump( | |
request('settings') === $ret[0], | |
request('ack') === $ret[1], | |
request('headers') === $ret[2] | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require 'Frame.php'; | |
$settings = SettingsFrame::from()->getBytes(); | |
$ack = Ack::from()->getBytes(); | |
$headers = [ | |
[':method', 'GET'], | |
[':path', '/'], | |
[':scheme', 'http'], | |
[':authority', 'localhost'] | |
]; | |
$header = HeadersFrame::from($headers, 0x1, [0x1, 0x4])->getBytes(); | |
$data = DataFrame::from("Hello\n", 0x1, [0x1])->getBytes(); | |
$ret = "\x00\x00\x3a". | |
"\x01". | |
"\x05". | |
"\x00\x00\x00\x01". | |
"\x00". | |
"\x07:method". // 7 :method | |
"\x03\x47\x45\x54". // 3 GET | |
"\x00". | |
"\x05\x3a\x70\x61\x74\x68". // 5 :path | |
"\x01\x2f". // 1 / | |
"\x00". | |
"\x07\x3a\x73\x63\x68\x65\x6d\x65". // 7 :scheme | |
"\x04http". // 4 http | |
"\x00". | |
"\x0a\x3a\x61\x75\x74\x68\x6f\x72\x69\x74\x79". // 10 :authority | |
"\x09localhost"; // 9 localhost | |
var_dump( | |
"\x00\x00\x00\x04\x00\x00\x00\x00\x00" === $settings, | |
"\x00\x00\x00\x04\x01\x00\x00\x00\x00" === $ack, | |
$ret === $header, | |
"\x00\x00\x06". | |
"\x00". | |
"\x01". | |
"\x00\x00\x00\x01". | |
"\x48\x65\x6c\x6c\x6f\x0a" === $data | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment