Packages
ankh
0.0.2
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/stream.ex
defmodule Ankh.Stream do
alias Ankh.Frame
alias Ankh.Frame
defstruct [id: 0, state: :idle, hbf: <<>>, data: <<>>, window_size: 0]
def new(id), do: %__MODULE__{id: id}
#
# RECEIVING FRAMES
#
def received_frame(%__MODULE__{id: id}, %Frame{stream_id: stream_id})
when stream_id !== id do
raise "FATAL on stream #{id}: this frame has stream id #{stream_id}!"
end
# IDLE
def received_frame(%__MODULE__{state: :idle} = stream, %Frame{type: :headers})
do
{:ok, %__MODULE__{stream | state: :open}}
end
# RESERVED_LOCAL
def received_frame(%__MODULE__{state: :reserved_local} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :reserved_local} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
def received_frame(%__MODULE__{state: :reserved_local} = stream,
%Frame{type: :window_update}) do
{:ok, stream}
end
# RESERVED REMOTE
def received_frame(%__MODULE__{state: :reserved_remote} = stream,
%Frame{type: :headers}) do
{:ok, %__MODULE__{stream | state: :half_closed_local}}
end
def received_frame(%__MODULE__{state: :reserved_remote} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :reserved_remote} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
# OPEN
def received_frame(%__MODULE__{state: :open} = stream,
%Frame{type: :headers, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :half_closed_remote}}
end
def received_frame(%__MODULE__{state: :open} = stream,
%Frame{type: :data, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :half_closed_remote}}
end
def received_frame(%__MODULE__{state: :open} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :open} = stream, %Frame{}) do
{:ok, stream}
end
# HALF CLOSED LOCAL
def received_frame(%__MODULE__{state: :half_closed_local} = stream,
%Frame{type: :headers, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :half_closed_local} = stream,
%Frame{type: :data, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :half_closed_local} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :half_closed_local} = stream, %Frame{})
do
{:ok, stream}
end
# HALF CLOSED REMOTE
def received_frame(%__MODULE__{state: :half_closed_remote} = stream,
%Frame{type: :window_update}) do
{:ok, stream}
end
def received_frame(%__MODULE__{state: :half_closed_remote} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
def received_frame(%__MODULE__{state: :half_closed_remote} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def received_frame(%__MODULE__{state: :half_closed_remote}, %Frame{}) do
{:error, :stream_closed}
end
# CLOSED
def received_frame(%__MODULE__{state: :closed} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
def received_frame(%__MODULE__{state: :closed} = stream,
%Frame{type: :window_update}) do
{:ok, stream}
end
def received_frame(%__MODULE__{state: :closed} = stream,
%Frame{type: :rst_stream}) do
{:ok, stream}
end
def received_frame(%__MODULE__{state: :closed}, %Frame{}) do
{:error, :stream_closed}
end
# Stop on protocol error
def received_frame(%__MODULE__{}, %Frame{}) do
{:error, :protocol_error}
end
#
# SENDING FRAMES
#
def send_frame(%__MODULE__{id: id}, %Frame{stream_id: stream_id})
when stream_id !== id do
raise "FATAL on stream #{id}: this frame was sent on #{stream_id}!"
end
# IDLE
def send_frame(%__MODULE__{state: :idle} = stream, %Frame{type: :headers}) do
{:ok, %__MODULE__{stream | state: :open}}
end
# RESERVED LOCAL
def send_frame(%__MODULE__{state: :reserved_local} = stream,
%Frame{type: :headers})
do
{:ok, %__MODULE__{stream | state: :half_closed_remote}}
end
def send_frame(%__MODULE__{state: :reserved_local} = stream,
%Frame{type: :rst_stream})
do
{:ok, %__MODULE__{stream | state: :closed}}
end
def send_frame(%__MODULE__{state: :reserved_local} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
# RESERVED REMOTE
def send_frame(%__MODULE__{state: :reserved_remote} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def send_frame(%__MODULE__{state: :reserved_remote} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
def send_frame(%__MODULE__{state: :reserved_remote} = stream,
%Frame{type: :window_update}) do
{:ok, stream}
end
# OPEN
def send_frame(%__MODULE__{state: :open} = stream,
%Frame{type: :headers, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :half_closed_local}}
end
def send_frame(%__MODULE__{state: :open} = stream,
%Frame{type: :data, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :half_closed_local}}
end
def send_frame(%__MODULE__{state: :open} = stream, %Frame{type: :rst_stream})
do
{:ok, %__MODULE__{stream | state: :closed}}
end
def send_frame(%__MODULE__{state: :open} = stream, %Frame{}) do
{:ok, stream}
end
# HALF CLOSED LOCAL
def send_frame(%__MODULE__{state: :half_closed_local} = stream,
%Frame{type: :window_update}) do
{:ok, stream}
end
def send_frame(%__MODULE__{state: :half_closed_local} = stream,
%Frame{type: :priority}) do
{:ok, stream}
end
def send_frame(%__MODULE__{state: :half_closed_local} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
# HALF CLOSED REMOTE
def send_frame(%__MODULE__{state: :half_closed_remote} = stream,
%Frame{type: :headers, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def send_frame(%__MODULE__{state: :half_closed_remote} = stream,
%Frame{type: :data, flags: %{end_stream: true}}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def send_frame(%__MODULE__{state: :half_closed_remote} = stream,
%Frame{type: :rst_stream}) do
{:ok, %__MODULE__{stream | state: :closed}}
end
def send_frame(%__MODULE__{state: :half_closed_remote} = stream, %Frame{}) do
{:ok, stream}
end
# CLOSED
def send_frame(%__MODULE__{state: :closed} = stream, %Frame{type: :priority})
do
{:ok, stream}
end
# Stop on protocol error
def send_frame(%__MODULE__{}, %Frame{}) do
{:error, :protocol_error}
end
end