Packages
ankh
0.0.5
0.17.0
0.16.0
0.15.0
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.1
0.12.0
0.11.0
0.10.0
0.9.0
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.1
0.3.0
0.1.1
0.1.0
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Pure Elixir HTTP/2 implementation
Current section
Files
Jump to
Current section
Files
lib/ankh/frame.ex
defmodule Ankh.Frame do
@moduledoc """
HTTP/2 frame structure
"""
alias Ankh.Frame.Encoder
@typedoc """
- length: payload length in bytes
- type: frame type
- flags: `Ankh.Frame.Encoder` structure for flags
- stream_id: Stream ID of the frame
- payload: - flags: `Ankh.Frame.Encoder` structure for the payload
"""
@type t :: %__MODULE__{length: Integer.t, type: :data | :headers | :priority |
:rst_stream | :settings | :push_primise | :ping | :goaway | :window_update |
:continuation | atom, flags: Encoder.t, stream_id: Integer.t,
payload: Encoder.t}
defstruct [length: 0, type: nil, flags: nil, stream_id: 0, payload: nil]
end
defimpl Ankh.Frame.Encoder, for: Ankh.Frame do
alias Ankh.Frame
alias Ankh.Frame.Encoder
@reserved 0x0
@data 0x0
@headers 0x1
@priority 0x2
@rst_stream 0x3
@settings 0x4
@push_promise 0x5
@ping 0x6
@goaway 0x7
@window_update 0x8
@continuation 0x9
def decode!(frame, <<0::24, type::8, flags::binary-size(1), 0x0::1, id::31>>,
options) do
type = decode_type!(type)
flags = Encoder.decode!(flags_for_type!(type), flags, options)
%Frame{frame | type: type, stream_id: id, flags: flags}
end
def decode!(frame, <<length::24, type::8, flags::binary-size(1), 0x0::1,
id::31, payload::binary>>, options) do
type = decode_type!(type)
flags = Encoder.decode!(flags_for_type!(type), flags, options)
payload_opts = [flags: flags] ++ options
%Frame{frame | length: length, type: type, stream_id: id, flags: flags,
payload: Encoder.decode!(payload_for_type!(type), payload, payload_opts)}
end
def encode!(%Frame{type: type, flags: flags, stream_id: id, payload: nil},
options) do
flags = Encoder.encode!(flags, options)
<<0::24, encode_type!(type)::8>> <> flags <> <<@reserved::1, id::31>>
end
def encode!(%Frame{type: type, flags: nil, stream_id: id, payload: payload},
options) do
type = encode_type!(type)
payload = Encoder.encode!(payload, options)
length = byte_size(payload)
<<length::24, type::8, 0::8, @reserved::1, id::31>> <> payload
end
def encode!(%Frame{type: type, stream_id: id, flags: flags, payload: payload},
options) do
type = encode_type!(type)
payload = Encoder.encode!(payload, [flags: flags] ++ options)
length = byte_size(payload)
flags = Encoder.encode!(flags, options)
<<length::24, type::8>> <> flags <> <<@reserved::1, id::31>> <> payload
end
defp encode_type!(:data), do: @data
defp encode_type!(:headers), do: @headers
defp encode_type!(:priority), do: @priority
defp encode_type!(:rst_stream), do: @rst_stream
defp encode_type!(:settings), do: @settings
defp encode_type!(:push_promise), do: @push_promise
defp encode_type!(:ping), do: @ping
defp encode_type!(:goaway), do: @goaway
defp encode_type!(:window_update), do: @window_update
defp encode_type!(:continuation), do: @continuation
defp decode_type!(@data), do: :data
defp decode_type!(@headers), do: :headers
defp decode_type!(@priority), do: :priority
defp decode_type!(@rst_stream), do: :rst_stream
defp decode_type!(@settings), do: :settings
defp decode_type!(@push_promise), do: :push_promise
defp decode_type!(@ping), do: :ping
defp decode_type!(@goaway), do: :goaway
defp decode_type!(@window_update), do: :window_update
defp decode_type!(@continuation), do: :continuation
defp decode_type!(_), do: :unknown
defp flags_for_type!(:data), do: %Frame.Data.Flags{}
defp flags_for_type!(:headers), do: %Frame.Headers.Flags{}
defp flags_for_type!(:settings), do: %Frame.Settings.Flags{}
defp flags_for_type!(:push_promise), do: %Frame.PushPromise.Flags{}
defp flags_for_type!(:ping), do: %Frame.Ping.Flags{}
defp flags_for_type!(:continuation), do: %Frame.Continuation.Flags{}
defp flags_for_type!(_), do: Any
defp payload_for_type!(:data), do: %Frame.Data.Payload{}
defp payload_for_type!(:headers), do: %Frame.Headers.Payload{}
defp payload_for_type!(:priority), do: %Frame.Priority.Payload{}
defp payload_for_type!(:rst_stream), do: %Frame.RstStream.Payload{}
defp payload_for_type!(:settings), do: %Frame.Settings.Payload{}
defp payload_for_type!(:push_promise), do: %Frame.PushPromise.Payload{}
defp payload_for_type!(:ping), do: %Frame.Ping.Payload{}
defp payload_for_type!(:goaway), do: %Frame.GoAway.Payload{}
defp payload_for_type!(:window_update), do: %Frame.WindowUpdate.Payload{}
defp payload_for_type!(:continuation), do: %Frame.Continuation.Payload{}
defp payload_for_type!(_), do: Any
end