📖

【PHP】HTTP/2 の Settings フレームペイロードの生成

2024/08/02に公開

Settings フレームのペイロードは2バイトの識別子と4バイトの値で構成される。識別子として次のものが定義される。

  • SETTINGS_HEADER_TABLE_SIZE (0x01)
  • SETTINGS_ENABLE_PUSH (0x02)
  • SETTINGS_MAX_CONCURRENT_STREAMS (0x03)
  • SETTINGS_INITIAL_WINDOW_SIZE (0x04)
  • SETTINGS_MAX_FRAME_SIZE (0x05)
  • SETTINGS_MAX_HEADER_LIST_SIZE (0x06)

6つの識別子をすべて使うならペイロードのサイズは36バイト(6 * 6)となる。次のテストコードのデータは SETTINGS_ENABLE_PUSH (0x02) をオフにする、SETTINGS_MAX_CONCURRENT_STREAMS (0x03) の値を 100 (0x64) にするというものである。

<?php
// https://gist.github.com/masakielastic/8e93e3ad771be0cef0081f23bd9b35a2
require 'h2utils.php';

$options = [
    [0x2, 0x0],
    [0x3, 0x64]
];

$settings = [
   "length"   => "\x00\x00\x0C",
   "type"     => "\x04",
   "flag"     => "\x00",
   "streamId" => "\x00\x00\x00\x00",
   "payload"  => "\x00\x02"."\x00\x00\x00\x00".
                 "\x00\x03"."\x00\x00\x00\x64"
];

var_dump(
    $settings['payload'] === createSettingsFramePayload($options),
    $options === settingsFramePayloadToArray($settings['payload']),
    implode($settings) === createSettingsFrame($options)
);

function createSettingsFrame(array $options = [], int $flag = 0x0): string
{
    $payload = createSettingsFramePayload($options);
    $length = strlen($payload);
    return createFrameHeader($length, 0x4, $flag, 0x0).$payload;
}

function createSettingsFramePayload(array $options): string
{
    $ret = '';

    foreach ($options as $values) {
        $ret .= int16ToBin($values[0]).int32ToBin($values[1]);
    }

    return $ret;
}

function settingsFramePayloadToArray(string $bytes): array
{
    $size = strlen($bytes);
    $pos = 0;
    $ret = [];

    while ($pos < $size) {
        $ret[] = [
                     binToInt16(substr($bytes, $pos, 2)),
                     binToInt32(substr($bytes, $pos + 2, 4))
                 ];

        $pos += 6;
    }

    return $ret;
}

Discussion