Packages
ace
0.14.3
0.19.0
0.18.10
0.18.9
0.18.8
0.18.7
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.8
0.16.7
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
retired
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
retired
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
HTTP web server and client, supports http1 and http2
Current section
Files
Jump to
Current section
Files
lib/ace/http2/frame/4_settings.ex
defmodule Ace.HTTP2.Frame.Settings do
@moduledoc false
@enforce_keys [:ack]
@parameter_keys [
:header_table_size,
:enable_push,
:max_concurrent_streams,
:initial_window_size,
:max_frame_size,
:max_header_list_size
]
defstruct @enforce_keys ++ @parameter_keys
def new(parameters \\ []) do
parameters = Enum.into(parameters, %{})
%__MODULE__{ack: false} |> Map.merge(parameters)
end
def ack() do
%__MODULE__{ack: true}
end
def decode({4, <<_::7, 0::1>>, 0, payload}) do
case parse_settings(payload) do
{:ok, settings} ->
{:ok, new(settings)}
{:error, reason} ->
{:error, reason}
end
end
def decode({4, <<_::7, 1::1>>, 0, ""}) do
{:ok, %__MODULE__{ack: true}}
end
def serialize(frame = %{ack: false}) do
type = 4
flags = 0
stream_id = 0
payload = Enum.reduce(@parameter_keys, [], fn(key, acc) ->
case Map.get(frame, key) do
nil ->
acc
value ->
[setting_parameter(key, value) | acc]
end
end)
|> Enum.reverse()
|> :erlang.iolist_to_binary
length = :erlang.iolist_size(payload)
<<length::24, type::8, flags::8, 0::1, stream_id::31, payload::binary>>
end
def serialize(%{ack: true}) do
type = 4
<<0::24, type::8, 1::8, 0::1, 0::31>>
end
def parse_settings(binary, settings \\ %{})
def parse_settings(<<>>, settings) do
{:ok, settings}
end
def parse_settings(<<identifier::16, value::32, rest::binary>>, settings) do
case cast_setting(identifier, value) do
{:ok, {:unknown_setting, _value}} ->
{:ok, settings}
{:ok, {setting, value}} ->
settings = Map.put(settings, setting, value)
parse_settings(rest, settings)
{:error, reason} ->
{:error, reason}
end
end
def cast_setting(1, value) do
{:ok, {:header_table_size, value}}
end
def cast_setting(2, 0) do
{:ok, {:enable_push, false}}
end
def cast_setting(2, 1) do
{:ok, {:enable_push, true}}
end
def cast_setting(2, _) do
{:error, {:protocol_error, "invalid value for enable_push setting"}}
end
def cast_setting(3, value) do
{:ok, {:max_concurrent_streams, value}}
end
# DEBT is minumum 0 or 1
def cast_setting(4, value) when 0 <= value and value <= 2_147_483_647 do
{:ok, {:initial_window_size, value}}
end
def cast_setting(4, _value) do
{:error, {:protocol_error, "invalid value for initial_window_size setting"}}
end
def cast_setting(5, value) when 16_384 <= value and value <= 16_777_215 do
{:ok, {:max_frame_size, value}}
end
def cast_setting(5, _value) do
{:error, {:protocol_error, "invalid value for max_frame_size setting"}}
end
def cast_setting(6, value) do
{:ok, {:max_header_list_size, value}}
end
def cast_setting(identifier, value) when identifier > 6 do
{:ok, {:unknown_setting, value}}
end
def setting_parameter(:header_table_size, value) do
<<1::16, value::32>>
end
def setting_parameter(:enable_push, false) do
<<2::16, 0::32>>
end
def setting_parameter(:enable_push, true) do
<<2::16, 1::32>>
end
def setting_parameter(:max_concurrent_streams, value) do
<<3::16, value::32>>
end
def setting_parameter(:initial_window_size, value) do
<<4::16, value::32>>
end
def setting_parameter(:max_frame_size, value) do
<<5::16, value::32>>
end
def parameters_to_payload(parameters, payload \\ [])
def parameters_to_payload([], payload) do
Enum.reverse(payload)
|> :erlang.iolist_to_binary
end
def parameters_to_payload([{:header_table_size, value} | rest], payload) do
payload = [<<1::16, value::32>> | payload]
parameters_to_payload(rest, payload)
end
def parameters_to_payload([{:max_frame_size, value} | rest], payload) do
payload = [<<5::16, value::32>> | payload]
parameters_to_payload(rest, payload)
end
end
defimpl Inspect, for: Ace.HTTP2.Frame.Settings do
@parameter_keys [
:header_table_size,
:enable_push,
:max_concurrent_streams,
:initial_window_size,
:max_frame_size,
:max_header_list_size
]
def inspect(%{ack: true}, _opts) do
"SETTINGS(ack: true)"
end
def inspect(settings = %{ack: false}, _opts) do
setting_params = Enum.flat_map(@parameter_keys, fn
(key) ->
case Map.fetch(settings, key) do
{:ok, nil} ->
[]
{:ok, value} ->
["#{key}: #{value}"]
end
end)
"SETTINGS(#{setting_params |> Enum.join(", ")})"
end
end