HTTP/3 and QPACK event definitions for qlog の紹介

本記事ではIETFで標準化が行われている、QUICなどのロギングを行うフォーマットであるqlogの、HTTP/3とQPACKに関するイベントを定義している「[HTTP/3 and QPACK event definitions for qlog](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-h3-events-00)」について紹介します。

# HTTP/3 and QPACK event definitions for qlog とは
qlogには発生したイベントをロギングする仕組みがあります。「HTTP/3 and QPACK event definitions for qlog」は、qlogにHTTP/3とQPACKのイベントを記録するための情報を定義しています。

具体手的には、イベントの種類を特定するための`name` (`category` + `event`)とそのイベントをロギングするときに含むデータが定義されています。また、それぞれのイベントにはImportance という情報も定義されています。

なお、qlogの提案自体は2019年ころから行われていましたが、「HTTP/3 and QPACK event definitions for qlog」まだWG Draftになって間もない状態です。また、HTTP/3は[Draft-34](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34)、QPACKは[Draft-21](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21)を参照しています。

本記事は、[Draft-00](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-h3-events-00)を参照しています。そのため今後の議論によって内容が大きく変わる可能性があります。

ドラフトのベースとなっているドキュメントがあるレポジトリや、議論されているIssueの状況は下記から参照可能です。

レポジトリ
https://github.com/quicwg/qlog

議論
https://github.com/quicwg/qlog/issues

# qlog main schemaのおさらい
「HTTP/3 and QPACK event definitions for qlog 」を読む上で必要になるqlogの基礎知識は別記事にまとめてあります。

[qlog main schemaのおさらい](https://qiita.com/neko-suki/items/604095f60ec5f334d896#qlog-main-schema%E3%81%AE%E3%81%8A%E3%81%95%E3%82%89%E3%81%84)

[nameについて](https://qiita.com/neko-suki/items/604095f60ec5f334d896#name%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

[イベントのImportanceについて](https://qiita.com/neko-suki/items/604095f60ec5f334d896#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AEimportance%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

# QUICとHTTP/3・QPACKのログを同時に出力したい場合
qlogには、HTTP/3・QPACKのログとQUICのログを同時に出力することもできます。逆に、HTTP/3・QPACKのみ出力することやQUICのみ出力することもできます。

QUICと一緒に使う場合は、推奨されるファイル名やサーバーやクライアントのトレースの分割方法は、QUICのイベント定義のドキュメントを（Destination Connection IDの使用を推奨しています）優先します。

QUICと一緒に使わない場合、HTTP/3の接続にグローバルで一意なIDを設定することが推奨されます。そのIDは、qlogのgroup_idや、ファイル名、ファイル識別子、vantagepoint typeのサフィックスに使います。例えば、abcd1234_server.qlogは、接続のGUIDがabcd1234のサーバーサイドのトレースを含みます。


# qlog main schemaとのつながり
このドキュメントでは、main schemaで定義されたフィールド（例えば、name, category, type, data, group_id, protocol_type, 時間に関連するフィールド、importance, RawInfoなど）が再利用されます。

このドキュメントでHTTP/3やQPACKのために定義されているイベントをトレースファイルに含める場合、protocol_typeの配列には"HTTP/3"を含める必要があります。

## Raw packet and frame information
qlogのメインスキーマで定義されている、`RawInfo`は再利用されます。

`RawInfo` は生のバイト長やバイトを保存しておくことで、パケタイゼーションの振る舞いの調査やチューニング、エンコードやフレーミングのオーバーヘッドの確認などに使うために定義されています。

HTTP/3の場合、ヘッダ長 `header_length` は

`header_length = RawIngo:length - RawInfo:payload_length`

で計算されるため定義はされていません。

```ts
class RawInfo {
    length?:uint64; // the full byte length of the entity (e.g., packet or frame) including headers and trailers
    payload_length?:uint64; // the byte length of the entity's payload, without headers or trailers

    data?:bytes; // the contents of the full entity, including headers and trailers
}
```


いくつかの場合で、lengthフィールドは、明示的にフレームのヘッダに反映されます。例えば、すべてのHTTP/3フレームは、明示的のペイロード長をヘッダの中に持ちます。

参考: [DATAフレーム](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-h3-events-00#appendix-A.1.1)の定義

```
   DATA Frame {
     Type (i) = 0x0,
     Length (i),
     Data (..),
   }
```

# HTTP/3 and QPACK event definitions
現時点では、HTTP/3とQPACKそれぞれに`http`、`qpack` というカテゴリが割り当てられています。

HTTP/3に対するイベントは、`http:parameters_set` のような形式で定義されます。

QPACKに対するイベントは、`qpack:state_updated` のような形式で定義されています。


## http
HTTP/3 には以下のようなイベントが定義されています。

|event type|Importance| サマリー|
|-|-|-|
|parameters_set|Base|SETTINGSフレームで設定されるHTTP/3やQPACKの設定が含まれます|
|parameters_restored|Base|0-RTT接続するときに、再利用するパラメータを記録します|
|stream_type_set|Base|ストリームの種類を記録します。|
|frame_created|Core|HTTP/3のフレームが生成されたことを記録します|
|frame_parsed|Core|HTTP/3のフレームを解析したことを記録します|
|push_resolved|Extra|プッシュされたリソースが上位から要求されたことを記録します|


### parameters_set
Importance: Base

`parameters_set` はHTTP/3とQPACKの設定を含みます。

多くの場合これらの設定はHTTP/3のSETTINGSフレームによって受信されます。

HTTP/3の設定は、[SETTINGS_MAX_FIELD_SECTION_SIZE](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.4.1) があります。SETTINGS_MAX_FIELD_SECTION_SIZEは1つのHTTPメッセージに含まれるヘッダのサイズを制限します。

QPACKの設定は、[5.  Configuration](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-5) に書かれているSETTINGS_QPACK_MAX_TABLE_CAPACITYとSETTINGS_QPACK_BLOCKED_STREAMSが含まれます。

SETTINGS_QPACK_MAX_TABLE_CAPACITY は、デコーダー側が決めるQPACKで使用する動的テーブルのサイズの最大値になります。

SETTINGS_QPACK_BLOCKED_STREAMSはブロックされるストリームの上限を設定します。QUICはストリームの到着順序を保証していないため、ダイナミックテーブルのエントリーが参照しても即座に処理できない場合があります。そしてそのような場合ストリームはブロックされます。この値によってそのストリームの数の上限が決まります。

これらのパラメータは一度設定されたら変更されない場合が多いです。しかし、典型的には接続の異なるタイミングで設定されます。なので、このイベントは異なるフィールドを持った複数のインスタンスが記録される可能性があります。


設定には、ローカルで設定されるものとリモートのピアから設定されるものがあります。どちらが設定したかは`owner`フィールドに反映されます。

`owner` フィールドは必ず含まれなければいけない設定ではないですが、もし含めるのであれば、単一のイベントインスタンスに含まれるすべての設定に対して`owner`が正しい必要があります。したがって、もしクライアントとサーバーの二つの側からの設定を明示的にログに残したい場合は、二つの別々のイベントインスタンスを発行する必要があります。

このイベントは仕様書には記されないフィールドを持つことが可能です。これは、例えば、unknown (greased)な設定や、パラメータの拡張を含むことが可能です。

```ts
Data:
{
    owner?:"local" | "remote",

    max_header_list_size?:uint64, // from SETTINGS_MAX_HEADER_LIST_SIZE
    max_table_capacity?:uint64, // from SETTINGS_QPACK_MAX_TABLE_CAPACITY
    blocked_streams_count?:uint64, // from SETTINGS_QPACK_BLOCKED_STREAMS

    // qlog-defined
    waits_for_settings?:boolean // indicates whether this implementation waits for a SETTINGS frame before processing requests
}
```

#### サーバープッシュの設定について
サーバープッシュは、HTTP/3の設定やパラメータによって使用可能になるわけではありません。

その代わりに、MAX_PUSH_IDフレームのやり取りによって決まります。

クライアントが、送信したMAX_PUSH_IDよりサイズの大きいPushIDを持ったストリームは使えません。

参考: https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.7

> A client MUST treat receipt of a push stream as  a connection error of type H3_ID_ERROR (Section 8) when no MAX_PUSH_ID frame has been sent or when the stream references a Push ID that is greater than the maximum Push ID.

なので、サーバープッシュの設定は`frame_created`と`frame_parsed` イベントによるMAX_PUSH_IDフレームの生成・解析によって記録されます。

### parameters_restored
Importance: Base

QUICの0-RTTを使うときに、HTTP/3のクライアントは以前の接続のサーバーの設定を保持して再利用することが可能です。

参考: https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.4.2

>    When a 0-RTT QUIC connection is being used, the initial value of each server setting is the value used in the previous session.  Clients    SHOULD store the settings the server provided in the HTTP/3    connection where resumption information was provided, but MAY opt not    to store settings in certain cases (e.g., if the session ticket is    received before the SETTINGS frame).  A client MUST comply with    stored settings -- or default values, if no values are stored -- when    attempting 0-RTT.  Once a server has provided new settings, clients    MUST comply with those values.


このイベントは、HTTP/3の設定を復元して0-RTT接続で利用されることを示します。

```ts
   Data:

   {
       max_header_list_size?:uint64,
       max_table_capacity?:uint64,
       blocked_streams_count?:uint64
   }
```

このイベントは`parameters_set`と同様に、このドキュメントで定義されていないフィールドやカスタムの設定を含むことができます。


### stream_type_set
Importance: Base

このイベントはストリームタイプが既知になったときに記録されます。典型的には、ストリームが開かれて、ストリームタイプを表す情報が送信または受信されたときにログを発行します。

Bidirectional Streamは、`data` ストリームになります。

Unidirectional Streamはいくつかの種類があります。

HTTP/3 で規定されているものは以下の二つです。

- [Control Stream](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-6.2.1)
- [Push Stream](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-6.2.2)

また、"0x1f * N + 0x21"のIDを使う[Reserved Stream Types](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-6.2.3)というのもあります。

QPACKでは、以下の二つが定義されています。
- Encoder Stream
- Decoder Stream

参考: https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.2

ストリームIDはQUICのレベルで分割されているため、多くの情報はストリームIDを見ることで推測できるようです。
そうだとしても、 この情報が明確に示されているとデバッグに大いに役立つため、このイベントには"Base"を割り当てられています。

```ts
   {
       stream_id:uint64,

       owner?:"local"|"remote"

       old?:StreamType,
       new:StreamType,

       associated_push_id?:uint64 // only when new == "push"
   }

   enum StreamType {
       data, // bidirectional request-response streams
       control,
       push,
       reserved,
       qpack_encode,
       qpack_decode
   }
```


### frame_created
Importance: Core

このイベントは、HTTP/3のフレームを作成したときに発行されます。そのタイミングはHTTP/3のデータがQUICのレイヤに渡されたのと同じタイミングである必要はありません。

QUICレイヤに渡されたタイミングに関するイベントは[`data_moved`](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.3.15) イベントで定義されています。

```ts
   Data:

   {
       stream_id:uint64,
       length?:uint64, // payload byte length of the frame
       frame:HTTP3Frame, // see appendix for the definitions,

       raw?:RawInfo
   }
```

HTTP/3では、ヘッダのオーバーヘッドを減らすためDATAフレームは任意の長さを持つことが可能です。そのような場合、DATAフレームは、多くのQUICパケットにまたがりストリーミングされる形になります。

この場合は、`frame_created`イベントはフレームヘッダのために1回だけ発行されます。そして、それ以降にストリームされるデータは、`data_moved`イベントでログに記録されます。


### frame_parsed
Importance: Core

このイベントはHTTP/3のフレームがパースされたタイミングで発行されます。

これは、QUICレイヤでHTTP/3のデータが実際に受信されたタイミングと同じである必要はありません。

QUICレイヤからデータを受け取るタイミングに関するイベントは[`data_moved`](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.3.15) イベントで定義されています。

```ts
   Data:

   {
       stream_id:uint64,
       length?:uint64, // payload byte length of the frame
       frame:HTTP3Frame, // see appendix for the definitions,

       raw?:RawInfo
   }
```

HTTP/3では、DATAフレームはフレームヘッダのオーバーヘッドを減らすために任意の長さを設定できます。`frame_created`と同様に、DATAフレームは複数のQUICパケットにまたがります。そして、ストリーミングされる形になります。

この場合、`frame_parsed`イベントはフレームヘッダに対して1回だけ発行され、ストリームされたデータは [`data_moved`](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-quic-events-00#section-3.3.15) で記録をします。

### push_resolved
Importance: Extra

このイベントは、プッシュされたリソースがウェブブラウザなどのHTTP/3の上位のアプリケーションから要求される（使用される）場合か、捨てられる場合に発行されます。

このイベントは、予期されないPushの振る舞いをデバッグするのに役立ちます。

```ts
{
    push_id?:uint64,
    stream_id?:uint64, // in case this is logged from a place that does not have access to the push_id

    decision:"claimed"|"abandoned"
}
```


##  qpack
QPACKに関するイベントは、主に低レベルのQPACKの問題のデバッグに役に立ちます。

高レベルでは、プレインテキストのヘッダの値はHTTPの`frame_created`と`frame_parsed`に記録されるべきです。

`qpack` のカテゴリには以下のようなイベントがあります。

|event type|Importance| サマリー|
|-|-|-|
|state_updated|Base|QPACKの内部変数が変わったことを記録します|
|stream_state_updated|Core|ストリームがブロック・アンブロックされたことを記録します|
|dynamic_table_updated|Extra|ダイナミックテーブルへのエントリーの挿入・削除を記録します|
|headers_encoded|Base|ヘッダブロックがエンコードされたことを記録します|
|headers_decoded|Base|ヘッダブロックがデコードされたことを記録します|
|instruction_created|Base|QPACKのinstructionが生成されてEncoder/Decoderストリームに追加されたことを記録します|
|instruction_parsed|Base|QPACKのinstructionがEncoder/Decoderストリームから読み込まれたことを記録します|


`qpack`に対する `parameter_set` は定義されていません。
QPACKの仕組みをHTTP/3の拡張としてとらえています（HTTP/3の規格に載っていないという意味ととらえるとよさそうです）。そのため、自身では`paramsets_set` のイベントは持たず、httpの`parameters_set`に統合されています。

他のHTTP/3の拡張は、SETTINGSフレームにhttp.parameters_set に記録されるかもしれませんし、独自のイベントとして記録されるかもしれません。



### state_updated
Importance: Base

このイベントは、一つまたは複数のQPACK内部の変数が変わったときに発行されます。

現状で記述されているのは、ダイナミックテーブルのキャパシティ、サイズ、[Known Received Count](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-2.1.4)、Insert Count(ダイナミックテーブルに挿入されたエントリーの合計数)などがあります。

設定には、ローカルで設定されるものとリモートのピアから設定されるものがあります。どちらが設定したかは`owner`フィールドに反映されます。

`owner` フィールドは必ず含まれなければいけない設定ではないですが、もし含めるのであれば、単一のイベントインスタンスに含まれるすべてのセッティングに対して`owner`が正しい必要があります。したがって、もしクライアントとサーバーの二つの側からの設定を明示的にログに残したい場合は二つの別々のイベントインスタンスを発行する必要があります。

```ts
   Data:
{
    owner:"local" | "remote",

    dynamic_table_capacity?:uint64,
    dynamic_table_size?:uint64, // effective current size, sum of all the entries

    known_received_count?:uint64,
    current_insert_count?:uint64
}
```


### stream_state_updated
Importance: Core

このイベントは、ヘッダーデコーディングリクエストまたはQPACK instructionによって、ストリームがブロック・アンブロックされた場合に発行されます。

このイベントは、HTTP/3の性能を観測する場合に影響が大きいためImportanceはCoreにされています。


```ts
Data:

{
    stream_id:uint64,

    state:"blocked"|"unblocked" // streams are assumed to start "unblocked" until they become "blocked"
}
```

###  dynamic_table_updated
Importance: Extra

このイベントは、QPACKのダイナミックテーブルの一つまたは複数のエントリーが挿入あるいは削除されたときに発行されます。

```ts
 Data:

{
    owner:"local" | "remote", // local = the encoder's dynamic table. remote = the decoder's dynamic table

    update_type:"inserted"|"evicted",

    entries:Array<DynamicTableEntry>
}

class DynamicTableEntry {
    index:uint64;
    name?:string | bytes;
    value?:string | bytes;
}
```

### headers_encoded
Importance: Base

このイベントは、圧縮されていないヘッダブロックがエンコードされたときに発行されます。

このイベントの`headers`フィールドに含まれるHeadersFrameは`http.frame_craeted`と重複します。実装者は、両方のイベントを発行するときに`headers`フィールドをこのイベントから排除するかもしれません。

```ts
Data:
   {
       stream_id?:uint64,

       headers?:Array<HTTPHeader>,

       block_prefix:QPackHeaderBlockPrefix,
       header_block:Array<QPackHeaderBlockRepresentation>,

       length?:uint32,
       raw?:bytes
   }
```

### headers_decoded
Importance: Base

このイベントは、圧縮されたヘッダブロックがデコードされたときに発行されます。

このイベントの`headers`フィールドに含まれるHeadersFrameは`frame_parsed`と重複します。実装者は、両方のイベントを発行するときに`headers`フィールドをこのイベントから排除するかもしれません

```ts
Data:

   {
       stream_id?:uint64,

       headers?:Array<HTTPHeader>,

       block_prefix:QPackHeaderBlockPrefix,
       header_block:Array<QPackHeaderBlockRepresentation>,

       length?:uint32,
       raw?:bytes
   }
```

### instruction_created
Importance: Base

このイベントは、QPACKのinstructionが生成されてencoder/decoderストリームに追加されたときに発行します

Instructionには、[4.3.  Encoder Instructions](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.3) と [4.4.  Decoder Instructions](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.4) があります。


```ts
Data:
   {
       instruction:QPackInstruction // see appendix for the definitions,

       length?:uint32,
       raw?:bytes
   }
```

### instruction_parsed
Importance: Base

このイベントは、QPACKのinstruction (decoderとencoderの両方）が、encoder/decoderストリームから読まれたときに発行されます。

```ts
Data:

   {
       instruction:QPackInstruction // see appendix for the definitions,

       length?:uint32,
       raw?:bytes
   }
```

## HTTP/3 data field definitions
ここでは、HTTP/3のフレームと、エラーコードの記録方法を定義しています。

### HTTP/3 Frames
HTTP/3で定義されているフレームに対応する構造がログ用に定義されます。

```ts
type HTTP3Frame = DataFrame | HeadersFrame | PriorityFrame | CancelPushFrame | SettingsFrame | PushPromiseFrame | GoAwayFrame | MaxPushIDFrame | DuplicatePushFrame | ReservedFrame | UnknownFrame;
```

#### DataFrame
[DATA](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.1) フレ―ムの定義です

```ts
   class DataFrame{
       frame_type:string = "data";

       raw?:bytes;
   }
```

#### HeadersFrame
[HEADERS](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.2) フレームの定義です。
`HeadersFrame`には、QPACKの圧縮が適用されていない状態のplaintext のHTTP ヘッダを格納します。

```ts
headers: [{"name":":path","value":"/"},{"name":":method","value":"GET"},{"name":":authority","value":"127.0.0.1:4433"},{"name":":scheme","value":"https"}]

   class HeadersFrame{
       frame_type:string = "header";
       headers:Array<HTTPHeader>;
   }

   class HTTPHeader {
       name:string;
       value:string;
   }
```


#### CancelPushFrame
[CANCEL_PUSH](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.2) フレームの定義です。

```ts
   class CancelPushFrame{
       frame_type:string = "cancel_push";
       push_id:uint64;
   }
```

#### SettingsFrame
[SETTINGS](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.4) フレームの定義です。

```ts
   class SettingsFrame{
       frame_type:string = "settings";
       settings:Array<Setting>;
   }

   class Setting{
       name:string;
       value:string;
   }
```

#### PushPromiseFrame
[PUSH_PROMISE](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.5) フレームの定義です。

```ts
   class PushPromiseFrame{
       frame_type:string = "push_promise";
       push_id:uint64;

       headers:Array<HTTPHeader>;
   }
```

#### GoAwayFrame
[GOAWAY](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.6) フレームの定義です。

```ts
   class GoAwayFrame{
       frame_type:string = "goaway";
       stream_id:uint64;
   }
```

#### MaxPushIDFrame
[MAX_PUSH_ID](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.7) の定義です。

```ts
   class MaxPushIDFrame{
       frame_type:string = "max_push_id";
       push_id:uint64;
   }
```

####  DuplicatePushFrame
DUPLICATE_PUSH フレームは[ドラフト26以降](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#appendix-B.8)で削除されたようです。


```ts
   class DuplicatePushFrame{
       frame_type:string = "duplicate_push";
       push_id:uint64;
   }
```

### ReservedFrame
[Reserved Frame Types](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-7.2.8) の定義です。

```ts
   class ReservedFrame{
       frame_type:string = "reserved";
   }
```

#### UnknownFrame
QUICのUnknownFrameと値や使い方が被るので定義を再利用します。

```ts
   class UnknownFrame{
       frame_type:string = "unknown";
       raw_frame_type:uint64;

       raw_length?:uint32;
       raw?:bytes;
   }
```

###  ApplicationError
[8.1.  HTTP/3 Error Codes](https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-8.1) で定義されているエラーコードに対応しています。

```ts
   enum ApplicationError{
       http_no_error,
       http_general_protocol_error,
       http_internal_error,
       http_stream_creation_error,
       http_closed_critical_stream,
       http_frame_unexpected,
       http_frame_error,
       http_excessive_load,
       http_id_error,
       http_settings_error,
       http_missing_settings,
       http_request_rejected,
       http_request_cancelled,
       http_request_incomplete,
       http_early_response,
       http_connect_error,
       http_version_fallback
   }
```

# QPACK DATA type definitions
ここでは、QPACKのinstructionsと[Field Line Representations](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5) の記録方法が定義されています。

## QPACK Instructions
QPACKの[Encoder Instruction](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.3)と[Decoder Instruction](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.4) に対応しています。

instructionは、名前や機能からEncoderのinstructionか、Decoderのinstructionかが一意に定まるので、Encoder/Decoder instructionを一つのtypeに含めているようです。

```ts
type QPackInstruction = SetDynamicTableCapacityInstruction | InsertWithNameReferenceInstruction | InsertWithoutNameReferenceInstruction | DuplicateInstruction | HeaderAcknowledgementInstruction | StreamCancellationInstruction | InsertCountIncrementInstruction;
```

### SetDynamicTableCapacityInstruction
[Set Dynamic Table Capacity](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.3.1) の定義です。

```ts
   class SetDynamicTableCapacityInstruction {
       instruction_type:string = "set_dynamic_table_capacity";

       capacity:uint32;
   }
```

### InsertWithNameReferenceInstruction
[Insert With Name Reference](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.3.2) の定義です。

```ts
  class InsertWithNameReferenceInstruction {
       instruction_type:string = "insert_with_name_reference";

       table_type:"static"|"dynamic";

       name_index:uint32;

       huffman_encoded_value:boolean;

       value_length?:uint32;
       value?:string;
   }
```

### InsertWithoutNameReferenceInstruction
[Insert With Literal Name](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.3.3) に該当します。

```ts
   class InsertWithoutNameReferenceInstruction {
       instruction_type:string = "insert_without_name_reference";

       huffman_encoded_name:boolean;

       name_length?:uint32;
       name?:string;

       huffman_encoded_value:boolean;

       value_length?:uint32;
       value?:string;
   }
```

### DuplicateInstruction
[Duplicate](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.3.4) に関する定義です。

```ts
   class DuplicateInstruction {
       instruction_type:string = "duplicate";

       index:uint32;
   }
```

### HeaderAcknowledgementInstruction
[Section Acknowledgment](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.4.1) に該当していそうです。

```ts
   class HeaderAcknowledgementInstruction {
       instruction_type:string = "header_acknowledgement";

       stream_id:uint64;
   }
```

### StreamCancellationInstruction
[Stream Cancellation](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.4.2) に該当します。

```ts
   class StreamCancellationInstruction {
       instruction_type:string = "stream_cancellation";

       stream_id:uint64;
   }
```

### InsertCountIncrementInstruction
[Insert Count Increment](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.4.3) に該当します。

```ts
   class InsertCountIncrementInstruction {
       instruction_type:string = "insert_count_increment";

       increment:uint32;
   }
```

## QPACK Header compression
おそらく、[Field Line Representations](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5) に該当します。

```ts
type QPackHeaderBlockRepresentation = IndexedHeaderField | LiteralHeaderFieldWithName | LiteralHeaderFieldWithoutName;
```

### IndexedHeaderField
[Indexed Field Line](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.2) と、[base](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.1.2)の値から動的テーブルのインデックスを識別する [Indexed Field Line](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.3) が含まれます。

```ts
class IndexedHeaderField {
    header_field_type:string = "indexed_header";

    table_type:"static"|"dynamic"; // MUST be "dynamic" if is_post_base is true
    index:uint32;

    is_post_base:boolean = false; // to represent the "indexed header field with post-base index" header field type
}
```

### LiteralHeaderFieldWithName
[Literal Field Line With Name Reference](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.3)と、[Literal Field Line With Post-Base Name Reference](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.5) が含まれます。


```ts
class LiteralHeaderFieldWithName {
    header_field_type:string = "literal_with_name";

    preserve_literal:boolean; // the 3rd "N" bit
    table_type:"static"|"dynamic"; // MUST be "dynamic" if is_post_base is true
    name_index:uint32;

    huffman_encoded_value:boolean;
    value_length?:uint32;
    value?:string;

    is_post_base:boolean = false; // to represent the "Literal header field with post-base name reference" header field type
}
```

### LiteralHeaderFieldWithoutName
[Literal Field Line With Literal Name](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.6) のことではないかと思います。

```ts
   class LiteralHeaderFieldWithoutName {
       header_field_type:string = "literal_without_name";

       preserve_literal:boolean; // the 3rd "N" bit

       huffman_encoded_name:boolean;
       name_length?:uint32;
       name?:string;

       huffman_encoded_value:boolean;
       value_length?:uint32;
       value?:string;
   }
```

### QPackHeaderBlockPrefix
[Encoded Field Section Prefix](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21#section-4.5.6) ではないかと思います。

```ts
   class QPackHeaderBlockPrefix {
       required_insert_count:uint32;
       sign_bit:boolean;
       delta_base:uint32;
   }
```


# 終わりに
「HTTP/3 and QPACK event definitions for qlog」でこれから定義しようとしている、qlogにHTTP/3やQPACKのイベントを記録するための定義について紹介しました。

これから標準化が進んでいくと思われるので、今後も注目です。