-module(multipartkit@header). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/multipartkit/header.gleam"). -export([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, {<<<>/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", 140). -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", 132). -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", 121). -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", 107). -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.