The WebSocket protocol establishes a two-way communication channel via TCP.
Messages are made up of one or more dataframes, and are delineated by
frames with the fin
bit set.
This page hosts a formal specification of WebSocket using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
/**
* The WebSocket protocol establishes a two-way communication channel via TCP.
* Messages are made up of one or more dataframes, and are delineated by
* frames with the `fin` bit set.
*/
type Websocket_Opcode int
const (
Websocket_Opcode__Continuation Websocket_Opcode = 0
Websocket_Opcode__Text Websocket_Opcode = 1
Websocket_Opcode__Binary Websocket_Opcode = 2
Websocket_Opcode__Reserved3 Websocket_Opcode = 3
Websocket_Opcode__Reserved4 Websocket_Opcode = 4
Websocket_Opcode__Reserved5 Websocket_Opcode = 5
Websocket_Opcode__Reserved6 Websocket_Opcode = 6
Websocket_Opcode__Reserved7 Websocket_Opcode = 7
Websocket_Opcode__Close Websocket_Opcode = 8
Websocket_Opcode__Ping Websocket_Opcode = 9
Websocket_Opcode__Pong Websocket_Opcode = 10
Websocket_Opcode__ReservedControlB Websocket_Opcode = 11
Websocket_Opcode__ReservedControlC Websocket_Opcode = 12
Websocket_Opcode__ReservedControlD Websocket_Opcode = 13
Websocket_Opcode__ReservedControlE Websocket_Opcode = 14
Websocket_Opcode__ReservedControlF Websocket_Opcode = 15
)
var values_Websocket_Opcode = map[Websocket_Opcode]struct{}{0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}, 9: {}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}, 15: {}}
func (v Websocket_Opcode) isDefined() bool {
_, ok := values_Websocket_Opcode[v]
return ok
}
type Websocket struct {
InitialFrame *Websocket_InitialFrame
TrailingFrames []*Websocket_Dataframe
_io *kaitai.Stream
_root *Websocket
_parent kaitai.Struct
}
func NewWebsocket() *Websocket {
return &Websocket{
}
}
func (this Websocket) IO_() *kaitai.Stream {
return this._io
}
func (this *Websocket) Read(io *kaitai.Stream, parent kaitai.Struct, root *Websocket) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1 := NewWebsocket_InitialFrame()
err = tmp1.Read(this._io, this, this._root)
if err != nil {
return err
}
this.InitialFrame = tmp1
if (this.InitialFrame.Header.Finished != true) {
for i := 1;; i++ {
tmp2 := NewWebsocket_Dataframe()
err = tmp2.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp2
this.TrailingFrames = append(this.TrailingFrames, _it)
if _it.Header.Finished {
break
}
}
}
return err
}
type Websocket_Dataframe struct {
Header *Websocket_FrameHeader
PayloadBytes []byte
PayloadText string
_io *kaitai.Stream
_root *Websocket
_parent *Websocket
}
func NewWebsocket_Dataframe() *Websocket_Dataframe {
return &Websocket_Dataframe{
}
}
func (this Websocket_Dataframe) IO_() *kaitai.Stream {
return this._io
}
func (this *Websocket_Dataframe) Read(io *kaitai.Stream, parent *Websocket, root *Websocket) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp3 := NewWebsocket_FrameHeader()
err = tmp3.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Header = tmp3
if (this._root.InitialFrame.Header.Opcode != Websocket_Opcode__Text) {
tmp4, err := this.Header.LenPayload()
if err != nil {
return err
}
tmp5, err := this._io.ReadBytes(int(tmp4))
if err != nil {
return err
}
tmp5 = tmp5
this.PayloadBytes = tmp5
}
if (this._root.InitialFrame.Header.Opcode == Websocket_Opcode__Text) {
tmp6, err := this.Header.LenPayload()
if err != nil {
return err
}
tmp7, err := this._io.ReadBytes(int(tmp6))
if err != nil {
return err
}
tmp7 = tmp7
this.PayloadText = string(tmp7)
}
return err
}
type Websocket_FrameHeader struct {
Finished bool
Reserved uint64
Opcode Websocket_Opcode
IsMasked bool
LenPayloadPrimary uint64
LenPayloadExtended1 uint16
LenPayloadExtended2 uint32
MaskKey uint32
_io *kaitai.Stream
_root *Websocket
_parent kaitai.Struct
_f_lenPayload bool
lenPayload int
}
func NewWebsocket_FrameHeader() *Websocket_FrameHeader {
return &Websocket_FrameHeader{
}
}
func (this Websocket_FrameHeader) IO_() *kaitai.Stream {
return this._io
}
func (this *Websocket_FrameHeader) Read(io *kaitai.Stream, parent kaitai.Struct, root *Websocket) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp8, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.Finished = tmp8 != 0
tmp9, err := this._io.ReadBitsIntBe(3)
if err != nil {
return err
}
this.Reserved = tmp9
tmp10, err := this._io.ReadBitsIntBe(4)
if err != nil {
return err
}
this.Opcode = Websocket_Opcode(tmp10)
tmp11, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.IsMasked = tmp11 != 0
tmp12, err := this._io.ReadBitsIntBe(7)
if err != nil {
return err
}
this.LenPayloadPrimary = tmp12
this._io.AlignToByte()
if (this.LenPayloadPrimary == 126) {
tmp13, err := this._io.ReadU2be()
if err != nil {
return err
}
this.LenPayloadExtended1 = uint16(tmp13)
}
if (this.LenPayloadPrimary == 127) {
tmp14, err := this._io.ReadU4be()
if err != nil {
return err
}
this.LenPayloadExtended2 = uint32(tmp14)
}
if (this.IsMasked) {
tmp15, err := this._io.ReadU4be()
if err != nil {
return err
}
this.MaskKey = uint32(tmp15)
}
return err
}
func (this *Websocket_FrameHeader) LenPayload() (v int, err error) {
if (this._f_lenPayload) {
return this.lenPayload, nil
}
this._f_lenPayload = true
var tmp16 uint64;
if (this.LenPayloadPrimary <= 125) {
tmp16 = this.LenPayloadPrimary
} else {
var tmp17 uint16;
if (this.LenPayloadPrimary == 126) {
tmp17 = this.LenPayloadExtended1
} else {
tmp17 = this.LenPayloadExtended2
}
tmp16 = tmp17
}
this.lenPayload = int(tmp16)
return this.lenPayload, nil
}
type Websocket_InitialFrame struct {
Header *Websocket_FrameHeader
PayloadBytes []byte
PayloadText string
_io *kaitai.Stream
_root *Websocket
_parent *Websocket
}
func NewWebsocket_InitialFrame() *Websocket_InitialFrame {
return &Websocket_InitialFrame{
}
}
func (this Websocket_InitialFrame) IO_() *kaitai.Stream {
return this._io
}
func (this *Websocket_InitialFrame) Read(io *kaitai.Stream, parent *Websocket, root *Websocket) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp18 := NewWebsocket_FrameHeader()
err = tmp18.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Header = tmp18
if (this.Header.Opcode != Websocket_Opcode__Text) {
tmp19, err := this.Header.LenPayload()
if err != nil {
return err
}
tmp20, err := this._io.ReadBytes(int(tmp19))
if err != nil {
return err
}
tmp20 = tmp20
this.PayloadBytes = tmp20
}
if (this.Header.Opcode == Websocket_Opcode__Text) {
tmp21, err := this.Header.LenPayload()
if err != nil {
return err
}
tmp22, err := this._io.ReadBytes(int(tmp21))
if err != nil {
return err
}
tmp22 = tmp22
this.PayloadText = string(tmp22)
}
return err
}