Packages
bandit
1.5.7
1.12.1
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
retired
1.9.0
1.8.0
1.7.0
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.2
1.4.1
1.4.0
1.3.0
1.2.3
1.2.2
1.2.1
1.2.0
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-pre.18
1.0.0-pre.17
1.0.0-pre.16
1.0.0-pre.15
1.0.0-pre.14
1.0.0-pre.13
1.0.0-pre.12
1.0.0-pre.11
1.0.0-pre.10
1.0.0-pre.9
1.0.0-pre.8
1.0.0-pre.7
1.0.0-pre.6
1.0.0-pre.5
1.0.0-pre.4
1.0.0-pre.3
1.0.0-pre.2
1.0.0-pre.1
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.2.3
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
A pure-Elixir HTTP server built for Plug & WebSock apps
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/bandit/http2/frame/headers.ex
defmodule Bandit.HTTP2.Frame.Headers do
@moduledoc false
import Bandit.HTTP2.Frame.Flags
defstruct stream_id: nil,
end_stream: false,
end_headers: false,
exclusive_dependency: false,
stream_dependency: nil,
weight: nil,
fragment: nil
@typedoc "An HTTP/2 HEADERS frame"
@type t :: %__MODULE__{
stream_id: Bandit.HTTP2.Stream.stream_id(),
end_stream: boolean(),
end_headers: boolean(),
exclusive_dependency: boolean(),
stream_dependency: Bandit.HTTP2.Stream.stream_id() | nil,
weight: non_neg_integer() | nil,
fragment: iodata()
}
@end_stream_bit 0
@end_headers_bit 2
@padding_bit 3
@priority_bit 5
@spec deserialize(Bandit.HTTP2.Frame.flags(), Bandit.HTTP2.Stream.stream_id(), iodata()) ::
{:ok, t()} | {:error, Bandit.HTTP2.Errors.error_code(), binary()}
def deserialize(_flags, 0, _payload) do
{:error, Bandit.HTTP2.Errors.protocol_error(),
"HEADERS frame with zero stream_id (RFC9113§6.2)"}
end
# Padding and priority
def deserialize(
flags,
stream_id,
<<padding_length::8, exclusive_dependency::1, stream_dependency::31, weight::8,
rest::binary>>
)
when set?(flags, @padding_bit) and set?(flags, @priority_bit) and
byte_size(rest) >= padding_length do
{:ok,
%__MODULE__{
stream_id: stream_id,
end_stream: set?(flags, @end_stream_bit),
end_headers: set?(flags, @end_headers_bit),
exclusive_dependency: exclusive_dependency == 0x01,
stream_dependency: stream_dependency,
weight: weight,
fragment: binary_part(rest, 0, byte_size(rest) - padding_length)
}}
end
# Padding but not priority
def deserialize(flags, stream_id, <<padding_length::8, rest::binary>>)
when set?(flags, @padding_bit) and clear?(flags, @priority_bit) and
byte_size(rest) >= padding_length do
{:ok,
%__MODULE__{
stream_id: stream_id,
end_stream: set?(flags, @end_stream_bit),
end_headers: set?(flags, @end_headers_bit),
fragment: binary_part(rest, 0, byte_size(rest) - padding_length)
}}
end
# Any other case where padding is set
def deserialize(flags, _stream_id, <<_padding_length::8, _rest::binary>>)
when set?(flags, @padding_bit) do
{:error, Bandit.HTTP2.Errors.protocol_error(),
"HEADERS frame with invalid padding length (RFC9113§6.2)"}
end
def deserialize(
flags,
stream_id,
<<exclusive_dependency::1, stream_dependency::31, weight::8, fragment::binary>>
)
when set?(flags, @priority_bit) do
{:ok,
%__MODULE__{
stream_id: stream_id,
end_stream: set?(flags, @end_stream_bit),
end_headers: set?(flags, @end_headers_bit),
exclusive_dependency: exclusive_dependency == 0x01,
stream_dependency: stream_dependency,
weight: weight,
fragment: fragment
}}
end
def deserialize(flags, stream_id, <<fragment::binary>>)
when clear?(flags, @priority_bit) and clear?(flags, @padding_bit) do
{:ok,
%__MODULE__{
stream_id: stream_id,
end_stream: set?(flags, @end_stream_bit),
end_headers: set?(flags, @end_headers_bit),
fragment: fragment
}}
end
defimpl Bandit.HTTP2.Frame.Serializable do
@end_stream_bit 0
@end_headers_bit 2
def serialize(
%Bandit.HTTP2.Frame.Headers{
exclusive_dependency: false,
stream_dependency: nil,
weight: nil
} =
frame,
max_frame_size
) do
flags = if frame.end_stream, do: [@end_stream_bit], else: []
fragment_length = IO.iodata_length(frame.fragment)
if fragment_length <= max_frame_size do
[{0x1, set([@end_headers_bit | flags]), frame.stream_id, frame.fragment}]
else
<<this_frame::binary-size(max_frame_size), rest::binary>> =
IO.iodata_to_binary(frame.fragment)
[
{0x1, set(flags), frame.stream_id, this_frame}
| Bandit.HTTP2.Frame.Serializable.serialize(
%Bandit.HTTP2.Frame.Continuation{stream_id: frame.stream_id, fragment: rest},
max_frame_size
)
]
end
end
end
end