Current section
Files
Jump to
Current section
Files
src/multipartkit@header.erl
-module(multipartkit@header).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/multipartkit/header.gleam").
-export([validate_boundary/1, boundary/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/multipartkit/header.gleam", 40).
-spec parse_media_type(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
parse_media_type(Input) ->
{Type_token, Rest} = multipartkit@internal@text:read_token(Input),
case Type_token of
<<""/utf8>> ->
{error, nil};
_ ->
case gleam_stdlib:string_pop_grapheme(Rest) of
{ok, {<<"/"/utf8>>, Rest_after_slash}} ->
{Subtype_token, Tail} = multipartkit@internal@text:read_token(
Rest_after_slash
),
case Subtype_token of
<<""/utf8>> ->
{error, nil};
_ ->
{ok,
{<<<<Type_token/binary, "/"/utf8>>/binary,
Subtype_token/binary>>,
Tail}}
end;
_ ->
{error, nil}
end
end.
-file("src/multipartkit/header.gleam", 58).
-spec is_multipart(binary()) -> boolean().
is_multipart(Media_type) ->
Lower = multipartkit@internal@text:ascii_lowercase(Media_type),
gleam_stdlib:string_starts_with(Lower, <<"multipart/"/utf8>>) andalso (string:length(
Lower
)
> string:length(<<"multipart/"/utf8>>)).
-file("src/multipartkit/header.gleam", 144).
-spec is_bchar_alnum(binary()) -> boolean().
is_bchar_alnum(Grapheme) ->
case Grapheme of
<<"0"/utf8>> ->
true;
<<"1"/utf8>> ->
true;
<<"2"/utf8>> ->
true;
<<"3"/utf8>> ->
true;
<<"4"/utf8>> ->
true;
<<"5"/utf8>> ->
true;
<<"6"/utf8>> ->
true;
<<"7"/utf8>> ->
true;
<<"8"/utf8>> ->
true;
<<"9"/utf8>> ->
true;
<<"a"/utf8>> ->
true;
<<"b"/utf8>> ->
true;
<<"c"/utf8>> ->
true;
<<"d"/utf8>> ->
true;
<<"e"/utf8>> ->
true;
<<"f"/utf8>> ->
true;
<<"g"/utf8>> ->
true;
<<"h"/utf8>> ->
true;
<<"i"/utf8>> ->
true;
<<"j"/utf8>> ->
true;
<<"k"/utf8>> ->
true;
<<"l"/utf8>> ->
true;
<<"m"/utf8>> ->
true;
<<"n"/utf8>> ->
true;
<<"o"/utf8>> ->
true;
<<"p"/utf8>> ->
true;
<<"q"/utf8>> ->
true;
<<"r"/utf8>> ->
true;
<<"s"/utf8>> ->
true;
<<"t"/utf8>> ->
true;
<<"u"/utf8>> ->
true;
<<"v"/utf8>> ->
true;
<<"w"/utf8>> ->
true;
<<"x"/utf8>> ->
true;
<<"y"/utf8>> ->
true;
<<"z"/utf8>> ->
true;
<<"A"/utf8>> ->
true;
<<"B"/utf8>> ->
true;
<<"C"/utf8>> ->
true;
<<"D"/utf8>> ->
true;
<<"E"/utf8>> ->
true;
<<"F"/utf8>> ->
true;
<<"G"/utf8>> ->
true;
<<"H"/utf8>> ->
true;
<<"I"/utf8>> ->
true;
<<"J"/utf8>> ->
true;
<<"K"/utf8>> ->
true;
<<"L"/utf8>> ->
true;
<<"M"/utf8>> ->
true;
<<"N"/utf8>> ->
true;
<<"O"/utf8>> ->
true;
<<"P"/utf8>> ->
true;
<<"Q"/utf8>> ->
true;
<<"R"/utf8>> ->
true;
<<"S"/utf8>> ->
true;
<<"T"/utf8>> ->
true;
<<"U"/utf8>> ->
true;
<<"V"/utf8>> ->
true;
<<"W"/utf8>> ->
true;
<<"X"/utf8>> ->
true;
<<"Y"/utf8>> ->
true;
<<"Z"/utf8>> ->
true;
_ ->
false
end.
-file("src/multipartkit/header.gleam", 136).
-spec is_bchar(binary()) -> boolean().
is_bchar(Grapheme) ->
case Grapheme of
<<"'"/utf8>> ->
true;
<<"("/utf8>> ->
true;
<<")"/utf8>> ->
true;
<<"+"/utf8>> ->
true;
<<"_"/utf8>> ->
true;
<<","/utf8>> ->
true;
<<"-"/utf8>> ->
true;
<<"."/utf8>> ->
true;
<<"/"/utf8>> ->
true;
<<":"/utf8>> ->
true;
<<"="/utf8>> ->
true;
<<"?"/utf8>> ->
true;
<<" "/utf8>> ->
true;
Other ->
is_bchar_alnum(Other)
end.
-file("src/multipartkit/header.gleam", 125).
-spec list_all_bcharsnospace(list(binary())) -> boolean().
list_all_bcharsnospace(Graphemes) ->
case Graphemes of
[] ->
true;
[First | Rest] ->
case is_bchar(First) of
true ->
list_all_bcharsnospace(Rest);
false ->
false
end
end.
-file("src/multipartkit/header.gleam", 111).
?DOC(
" Returns `True` when `value` satisfies the RFC 2046 §5.1.1 `boundary`\n"
" grammar (1-70 `bchars` ending in a `bcharsnospace`). Used by `boundary/1`\n"
" on the parse side and by the encoder on the encode side so both ends\n"
" reject the same set of strings.\n"
).
-spec validate_boundary(binary()) -> boolean().
validate_boundary(Value) ->
Length = string:length(Value),
case (Length >= 1) andalso (Length =< 70) of
false ->
false;
true ->
case gleam_stdlib:string_ends_with(Value, <<" "/utf8>>) of
true ->
false;
false ->
_pipe = gleam@string:to_graphemes(Value),
list_all_bcharsnospace(_pipe)
end
end.
-file("src/multipartkit/header.gleam", 80).
-spec read_parameter(binary(), binary(), gleam@option:option(binary())) -> {ok,
gleam@option:option(binary())} |
{error, multipartkit@error:multipart_error()}.
read_parameter(Input, Original, Found) ->
After_ows = multipartkit@internal@text:skip_ows(Input),
{Key, Rest} = multipartkit@internal@text:read_token(After_ows),
case Key of
<<""/utf8>> ->
{error, {invalid_content_type, Original}};
_ ->
case gleam_stdlib:string_pop_grapheme(Rest) of
{ok, {<<"="/utf8>>, Value_rest}} ->
case multipartkit@internal@text:read_token_or_quoted(
Value_rest
) of
{error, _} ->
{error, {invalid_content_type, Original}};
{ok, {Raw_value, Tail}} ->
Next_found = case {multipartkit@internal@text:equals_ci(
Key,
<<"boundary"/utf8>>
),
Found} of
{true, none} ->
{some, Raw_value};
{_, _} ->
Found
end,
scan_for_boundary(Tail, Original, Next_found)
end;
_ ->
{error, {invalid_content_type, Original}}
end
end.
-file("src/multipartkit/header.gleam", 64).
-spec scan_for_boundary(binary(), binary(), gleam@option:option(binary())) -> {ok,
gleam@option:option(binary())} |
{error, multipartkit@error:multipart_error()}.
scan_for_boundary(Input, Original, Found) ->
After_ows = multipartkit@internal@text:skip_ows(Input),
case After_ows of
<<""/utf8>> ->
{ok, Found};
_ ->
case gleam_stdlib:string_pop_grapheme(After_ows) of
{ok, {<<";"/utf8>>, Rest}} ->
read_parameter(Rest, Original, Found);
_ ->
{error, {invalid_content_type, Original}}
end
end.
-file("src/multipartkit/header.gleam", 18).
?DOC(
" Extract the `boundary` parameter from a `Content-Type` header value.\n"
"\n"
" The error priority documented for `parse` is enforced here:\n"
"\n"
" 1. `InvalidContentType(value)` — value cannot be parsed as a media type.\n"
" 2. `UnsupportedMediaType(media_type)` — top-level media type is not\n"
" `multipart/*`.\n"
" 3. `MissingBoundary` — the `boundary` parameter is absent.\n"
" 4. `InvalidBoundary(value)` — present but violates the RFC 2046 grammar.\n"
).
-spec boundary(binary()) -> {ok, binary()} |
{error, multipartkit@error:multipart_error()}.
boundary(Content_type) ->
Original = Content_type,
Rest = multipartkit@internal@text:skip_ows(Content_type),
case parse_media_type(Rest) of
{error, _} ->
{error, {invalid_content_type, Original}};
{ok, {Media_type, After_type}} ->
case is_multipart(Media_type) of
false ->
{error, {unsupported_media_type, Media_type}};
true ->
case scan_for_boundary(After_type, Original, none) of
{error, Err} ->
{error, Err};
{ok, none} ->
{error, missing_boundary};
{ok, {some, Value}} ->
case validate_boundary(Value) of
true ->
{ok, Value};
false ->
{error, {invalid_boundary, Value}}
end
end
end
end.