diff options
Diffstat (limited to 'src/cow_capsule.erl')
-rw-r--r-- | src/cow_capsule.erl | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/cow_capsule.erl b/src/cow_capsule.erl new file mode 100644 index 0000000..542262f --- /dev/null +++ b/src/cow_capsule.erl @@ -0,0 +1,98 @@ +%% Copyright (c) Loïc Hoguin <[email protected]> +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-module(cow_capsule). + +%% Parsing. +-export([parse/1]). + +%% Building. +-export([wt_drain_session/0]). +-export([wt_close_session/2]). + +-type capsule() :: + wt_drain_session | + {wt_close_session, cow_http3:wt_app_error_code(), binary()}. + +%% Parsing. + +-spec parse(binary()) + -> {ok, capsule(), binary()} + | {ok, binary()} %% Unknown capsule gets skipped. + | more + | {skip, non_neg_integer()} %% Unknown capsule; remaining length to skip. + | error. + +%% @todo Handle DATAGRAM capsules. {datagram, binary()} +parse(<<2:2, 16#78ae:30, 0, Rest/bits>>) -> + {ok, wt_drain_session, Rest}; +parse(<<1:2, 16#2843:14, Rest0/bits>>) when byte_size(Rest0) >= 5 -> + LenOrError = case Rest0 of + <<0:2, Len0:6, Rest1/bits>> -> + {Len0, Rest1}; + <<1:2, Len0:14, Rest1/bits>> when Len0 =< 1028 -> + {Len0, Rest1}; + %% AppCode is 4 bytes and AppMsg is up to 1024 bytes. + _ -> + error + end, + case LenOrError of + {Len1, Rest2} -> + AppMsgLen = Len1 - 4, + case Rest2 of + <<AppCode:32, AppMsg:AppMsgLen/binary, Rest/bits>> -> + {ok, {wt_close_session, AppCode, AppMsg}, Rest}; + _ -> + more + end; + error -> + error + end; +parse(<<>>) -> + more; +%% Skip unknown capsules. +parse(Data) -> + %% @todo This can use maybe_expr in OTP-25+. + case cow_http3:parse_int(Data) of + more -> + more; + {_Type, Rest0} -> + case cow_http3:parse_int(Rest0) of + more -> + more; + {Len, Rest1} -> + case Rest1 of + <<_:Len/unit:8, Rest>> -> + {ok, Rest}; + _ -> + {skip, Len - byte_size(Rest1)} + end + end + end. + +%% Building. + +-spec wt_drain_session() -> binary(). + +%% @todo Where should I put capsules? +wt_drain_session() -> + <<2:2, 16#78ae:30, 0>>. + +-spec wt_close_session(cow_http3:wt_app_error_code(), iodata()) -> iodata(). + +wt_close_session(AppCode, <<>>) -> + <<1:2, 16#2843:14, 4, AppCode:32>>; +wt_close_session(AppCode, AppMsg) -> + Len = 4 + iolist_size(AppMsg), + [<<1:2, 16#2843:14>>, cow_http3:encode_int(Len), <<AppCode:32>>, AppMsg]. |