Current section
Files
Jump to
Current section
Files
src/h2_error.erl
%% @doc HTTP/2 Error Codes (RFC 7540 Section 7)
%%
%% Error codes are 32-bit integers used in RST_STREAM and GOAWAY frames.
%%
-module(h2_error).
-export([code/1, name/1, format/1]).
-include("h2.hrl").
%% Error code types
-type error_code() :: no_error | protocol_error | internal_error |
flow_control_error | settings_timeout | stream_closed |
frame_size_error | refused_stream | cancel |
compression_error | connect_error | enhance_your_calm |
inadequate_security | http_1_1_required |
{unknown, non_neg_integer()}.
-export_type([error_code/0]).
%% @doc Get the numeric code for an error name.
-spec code(error_code()) -> non_neg_integer().
code(no_error) -> ?NO_ERROR;
code(protocol_error) -> ?PROTOCOL_ERROR;
code(internal_error) -> ?INTERNAL_ERROR;
code(flow_control_error) -> ?FLOW_CONTROL_ERROR;
code(settings_timeout) -> ?SETTINGS_TIMEOUT;
code(stream_closed) -> ?STREAM_CLOSED;
code(frame_size_error) -> ?FRAME_SIZE_ERROR;
code(refused_stream) -> ?REFUSED_STREAM;
code(cancel) -> ?CANCEL;
code(compression_error) -> ?COMPRESSION_ERROR;
code(connect_error) -> ?CONNECT_ERROR;
code(enhance_your_calm) -> ?ENHANCE_YOUR_CALM;
code(inadequate_security) -> ?INADEQUATE_SECURITY;
code(http_1_1_required) -> ?HTTP_1_1_REQUIRED;
code({unknown, Code}) when is_integer(Code), Code >= 0 -> Code.
%% @doc Get the error name for a numeric code.
-spec name(non_neg_integer()) -> error_code().
name(?NO_ERROR) -> no_error;
name(?PROTOCOL_ERROR) -> protocol_error;
name(?INTERNAL_ERROR) -> internal_error;
name(?FLOW_CONTROL_ERROR) -> flow_control_error;
name(?SETTINGS_TIMEOUT) -> settings_timeout;
name(?STREAM_CLOSED) -> stream_closed;
name(?FRAME_SIZE_ERROR) -> frame_size_error;
name(?REFUSED_STREAM) -> refused_stream;
name(?CANCEL) -> cancel;
name(?COMPRESSION_ERROR) -> compression_error;
name(?CONNECT_ERROR) -> connect_error;
name(?ENHANCE_YOUR_CALM) -> enhance_your_calm;
name(?INADEQUATE_SECURITY) -> inadequate_security;
name(?HTTP_1_1_REQUIRED) -> http_1_1_required;
name(Code) when is_integer(Code), Code >= 0 -> {unknown, Code}.
%% @doc Format an error for display.
-spec format(error_code() | non_neg_integer()) -> string().
format(Code) when is_integer(Code) ->
format(name(Code));
format(no_error) ->
"NO_ERROR (0x0): Graceful shutdown";
format(protocol_error) ->
"PROTOCOL_ERROR (0x1): Protocol error detected";
format(internal_error) ->
"INTERNAL_ERROR (0x2): Implementation fault";
format(flow_control_error) ->
"FLOW_CONTROL_ERROR (0x3): Flow-control limits exceeded";
format(settings_timeout) ->
"SETTINGS_TIMEOUT (0x4): Settings not acknowledged";
format(stream_closed) ->
"STREAM_CLOSED (0x5): Frame received for closed stream";
format(frame_size_error) ->
"FRAME_SIZE_ERROR (0x6): Frame size incorrect";
format(refused_stream) ->
"REFUSED_STREAM (0x7): Stream not processed";
format(cancel) ->
"CANCEL (0x8): Stream cancelled";
format(compression_error) ->
"COMPRESSION_ERROR (0x9): Compression state not updated";
format(connect_error) ->
"CONNECT_ERROR (0xa): TCP connection error";
format(enhance_your_calm) ->
"ENHANCE_YOUR_CALM (0xb): Processing capacity exceeded";
format(inadequate_security) ->
"INADEQUATE_SECURITY (0xc): Negotiated TLS parameters not acceptable";
format(http_1_1_required) ->
"HTTP_1_1_REQUIRED (0xd): Use HTTP/1.1 for the request";
format({unknown, Code}) ->
io_lib:format("UNKNOWN (0x~.16b): Unknown error code", [Code]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
roundtrip_test_() ->
Errors = [no_error, protocol_error, internal_error, flow_control_error,
settings_timeout, stream_closed, frame_size_error, refused_stream,
cancel, compression_error, connect_error, enhance_your_calm,
inadequate_security, http_1_1_required],
[?_assertEqual(E, name(code(E))) || E <- Errors].
known_codes_test_() ->
[
?_assertEqual(0, code(no_error)),
?_assertEqual(1, code(protocol_error)),
?_assertEqual(13, code(http_1_1_required))
].
unknown_code_test_() ->
[
?_assertEqual({unknown, 100}, name(100)),
?_assertEqual(100, code({unknown, 100}))
].
format_test_() ->
[
?_assertMatch("NO_ERROR" ++ _, format(no_error)),
?_assertMatch("PROTOCOL_ERROR" ++ _, format(1)),
?_assertMatch("UNKNOWN" ++ _, format(999))
].
-endif.