Current section

Files

Jump to
multipartkit src multipartkit@content_disposition.erl
Raw

src/multipartkit@content_disposition.erl

-module(multipartkit@content_disposition).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/multipartkit/content_disposition.gleam").
-export([parse/1]).
-export_type([content_disposition/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type content_disposition() :: {content_disposition,
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
list({binary(), binary()})}.
-file("src/multipartkit/content_disposition.gleam", 122).
-spec find_param_ci(list({binary(), binary()}), binary()) -> gleam@option:option(binary()).
find_param_ci(Params, Key) ->
case Params of
[] ->
none;
[{K, V} | Rest] ->
case multipartkit@internal@text:equals_ci(K, Key) of
true ->
{some, V};
false ->
find_param_ci(Rest, Key)
end
end.
-file("src/multipartkit/content_disposition.gleam", 177).
-spec ascii_byte_to_string(integer()) -> binary().
ascii_byte_to_string(Byte) ->
gleam@result:unwrap(gleam@bit_array:to_string(<<Byte>>), <<""/utf8>>).
-file("src/multipartkit/content_disposition.gleam", 166).
-spec code_point_to_string(integer()) -> binary().
code_point_to_string(Byte) ->
case Byte < 16#80 of
true ->
ascii_byte_to_string(Byte);
false ->
High = 16#C0 + (Byte div 64),
Low = 16#80 + (Byte rem 64),
gleam@result:unwrap(
gleam@bit_array:to_string(<<High, Low>>),
<<""/utf8>>
)
end.
-file("src/multipartkit/content_disposition.gleam", 158).
-spec latin1_to_utf8(bitstring(), binary()) -> binary().
latin1_to_utf8(Bytes, Acc) ->
case Bytes of
<<>> ->
Acc;
<<B, Rest/binary>> ->
latin1_to_utf8(
Rest,
<<Acc/binary, (code_point_to_string(B))/binary>>
);
_ ->
Acc
end.
-file("src/multipartkit/content_disposition.gleam", 149).
-spec decode_with_charset(binary(), bitstring()) -> {ok, binary()} |
{error, nil}.
decode_with_charset(Charset, Bytes) ->
Lower = multipartkit@internal@text:ascii_lowercase(Charset),
case Lower of
<<"utf-8"/utf8>> ->
gleam@bit_array:to_string(Bytes);
<<"iso-8859-1"/utf8>> ->
{ok, latin1_to_utf8(Bytes, <<""/utf8>>)};
_ ->
{error, nil}
end.
-file("src/multipartkit/content_disposition.gleam", 210).
-spec hex_digit(binary()) -> {ok, integer()} | {error, nil}.
hex_digit(Grapheme) ->
case Grapheme of
<<"0"/utf8>> ->
{ok, 0};
<<"1"/utf8>> ->
{ok, 1};
<<"2"/utf8>> ->
{ok, 2};
<<"3"/utf8>> ->
{ok, 3};
<<"4"/utf8>> ->
{ok, 4};
<<"5"/utf8>> ->
{ok, 5};
<<"6"/utf8>> ->
{ok, 6};
<<"7"/utf8>> ->
{ok, 7};
<<"8"/utf8>> ->
{ok, 8};
<<"9"/utf8>> ->
{ok, 9};
<<"a"/utf8>> ->
{ok, 10};
<<"A"/utf8>> ->
{ok, 10};
<<"b"/utf8>> ->
{ok, 11};
<<"B"/utf8>> ->
{ok, 11};
<<"c"/utf8>> ->
{ok, 12};
<<"C"/utf8>> ->
{ok, 12};
<<"d"/utf8>> ->
{ok, 13};
<<"D"/utf8>> ->
{ok, 13};
<<"e"/utf8>> ->
{ok, 14};
<<"E"/utf8>> ->
{ok, 14};
<<"f"/utf8>> ->
{ok, 15};
<<"F"/utf8>> ->
{ok, 15};
_ ->
{error, nil}
end.
-file("src/multipartkit/content_disposition.gleam", 204).
-spec hex_pair(binary(), binary()) -> {ok, integer()} | {error, nil}.
hex_pair(High, Low) ->
gleam@result:'try'(
hex_digit(High),
fun(H) ->
gleam@result:'try'(hex_digit(Low), fun(L) -> {ok, (H * 16) + L} end)
end
).
-file("src/multipartkit/content_disposition.gleam", 185).
-spec percent_decode_loop(list(binary()), bitstring()) -> {ok, bitstring()} |
{error, nil}.
percent_decode_loop(Remaining, Acc) ->
case Remaining of
[] ->
{ok, Acc};
[<<"%"/utf8>>, High, Low | Rest] ->
case hex_pair(High, Low) of
{error, _} ->
{error, nil};
{ok, Byte} ->
percent_decode_loop(Rest, <<Acc/bitstring, Byte>>)
end;
[<<"%"/utf8>> | _] ->
{error, nil};
[Other | Rest@1] ->
Chunk = gleam_stdlib:identity(Other),
percent_decode_loop(Rest@1, <<Acc/bitstring, Chunk/bitstring>>)
end.
-file("src/multipartkit/content_disposition.gleam", 181).
-spec percent_decode(binary()) -> {ok, bitstring()} | {error, nil}.
percent_decode(Input) ->
percent_decode_loop(gleam@string:to_graphemes(Input), <<>>).
-file("src/multipartkit/content_disposition.gleam", 135).
?DOC(
" Decode a RFC 5987 / 8187 `charset 'lang' value` parameter into a Gleam\n"
" `String`. Supports UTF-8 and ISO-8859-1.\n"
).
-spec decode_rfc5987(binary()) -> {ok, binary()} | {error, nil}.
decode_rfc5987(Input) ->
case gleam@string:split_once(Input, <<"'"/utf8>>) of
{error, _} ->
{error, nil};
{ok, {Charset, After_first}} ->
case gleam@string:split_once(After_first, <<"'"/utf8>>) of
{error, _} ->
{error, nil};
{ok, {_, Encoded_value}} ->
gleam@result:'try'(
percent_decode(Encoded_value),
fun(Bytes) -> decode_with_charset(Charset, Bytes) end
)
end
end.
-file("src/multipartkit/content_disposition.gleam", 102).
-spec pick_convenience(list({binary(), binary()}), binary(), binary()) -> {ok,
gleam@option:option(binary())} |
{error, multipartkit@error:multipart_error()}.
pick_convenience(Params, Base_name, Original) ->
Star = <<Base_name/binary, "*"/utf8>>,
case find_param_ci(Params, Star) of
{some, Raw} ->
case decode_rfc5987(Raw) of
{ok, Value} ->
{ok, {some, Value}};
{error, _} ->
{error, {invalid_content_disposition, Original}}
end;
none ->
case find_param_ci(Params, Base_name) of
{some, Raw@1} ->
{ok, {some, Raw@1}};
none ->
{ok, none}
end
end.
-file("src/multipartkit/content_disposition.gleam", 80).
-spec parse_one_param(binary(), list({binary(), binary()}), binary()) -> {ok,
list({binary(), binary()})} |
{error, multipartkit@error:multipart_error()}.
parse_one_param(Rest, Acc, Original) ->
Inner_rest = multipartkit@internal@text:skip_ows(Rest),
{Key, After_key} = multipartkit@internal@text:read_token(Inner_rest),
case Key of
<<""/utf8>> ->
{error, {invalid_content_disposition, Original}};
_ ->
case gleam_stdlib:string_pop_grapheme(After_key) of
{ok, {<<"="/utf8>>, Value_rest}} ->
case multipartkit@internal@text:read_token_or_quoted(
Value_rest
) of
{error, nil} ->
{error, {invalid_content_disposition, Original}};
{ok, {Raw_value, Tail}} ->
parse_params(
Tail,
[{Key, Raw_value} | Acc],
Original
)
end;
_ ->
{error, {invalid_content_disposition, Original}}
end
end.
-file("src/multipartkit/content_disposition.gleam", 64).
-spec parse_params(binary(), list({binary(), binary()}), binary()) -> {ok,
list({binary(), binary()})} |
{error, multipartkit@error:multipart_error()}.
parse_params(Input, Acc, Original) ->
After_ows = multipartkit@internal@text:skip_ows(Input),
case After_ows of
<<""/utf8>> ->
{ok, lists:reverse(Acc)};
_ ->
case gleam_stdlib:string_pop_grapheme(After_ows) of
{ok, {<<";"/utf8>>, Rest}} ->
parse_one_param(Rest, Acc, Original);
_ ->
{error, {invalid_content_disposition, Original}}
end
end.
-file("src/multipartkit/content_disposition.gleam", 35).
?DOC(
" Parse a Content-Disposition header value.\n"
"\n"
" Returns `Error(InvalidContentDisposition(value))` for unparseable input.\n"
).
-spec parse(binary()) -> {ok, content_disposition()} |
{error, multipartkit@error:multipart_error()}.
parse(Value) ->
Original = Value,
Rest = multipartkit@internal@text:skip_ows(Value),
{Token, Rest_after_token} = multipartkit@internal@text:read_token(Rest),
case Token of
<<""/utf8>> ->
{error, {invalid_content_disposition, Original}};
_ ->
case parse_params(Rest_after_token, [], Original) of
{error, Err} ->
{error, Err};
{ok, Params} ->
Disposition = multipartkit@internal@text:ascii_lowercase(
Token
),
Name_value = pick_convenience(
Params,
<<"name"/utf8>>,
Original
),
Filename_value = pick_convenience(
Params,
<<"filename"/utf8>>,
Original
),
case {Name_value, Filename_value} of
{{error, Err@1}, _} ->
{error, Err@1};
{_, {error, Err@2}} ->
{error, Err@2};
{{ok, Name}, {ok, Filename}} ->
{ok,
{content_disposition,
Disposition,
Name,
Filename,
Params}}
end
end
end.