-module(multipartkit@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/multipartkit/parser.gleam"). -export([parse_with_limits/3, parse/2]). -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/parser.gleam", 138). -spec enforce_total(integer(), multipartkit@limit:limits()) -> {ok, nil} | {error, multipartkit@error:multipart_error()}. enforce_total(Consumed, Limits) -> case Consumed > multipartkit@limit:max_body_bytes(Limits) of true -> {error, {body_too_large, multipartkit@limit:max_body_bytes(Limits)}}; false -> {ok, nil} end. -file("src/multipartkit/parser.gleam", 53). -spec parse_loop( bitstring(), bitstring(), integer(), multipartkit@limit:limits(), list(multipartkit@part:part()), integer() ) -> {ok, list(multipartkit@part:part())} | {error, multipartkit@error:multipart_error()}. parse_loop(Body, Pattern, Cursor, Limits, Acc, Parts_count) -> case enforce_total(Cursor, Limits) of {error, Err} -> {error, Err}; {ok, _} -> case multipartkit@internal@bytes:find_blank_line(Body, Cursor) of {error, _} -> {error, unexpected_end_of_input}; {ok, {Blank_at, Body_start}} -> Header_block_size = Body_start - Cursor, case Header_block_size > multipartkit@limit:max_header_bytes( Limits ) of true -> {error, {header_too_large, multipartkit@limit:max_header_bytes(Limits)}}; false -> Header_block = multipartkit@internal@bytes:slice_or_empty( Body, Cursor, Blank_at - Cursor ), case multipartkit@internal@headers:parse_block( Header_block ) of {error, Err@1} -> {error, Err@1}; {ok, Header_list} -> case multipartkit@internal@headers:derive_meta( Header_list ) of {error, Err@2} -> {error, Err@2}; {ok, Meta} -> case multipartkit@internal@scan:find_delimiter( Body, Pattern, Body_start ) of incomplete -> {error, unexpected_end_of_input}; {found, Body_end_excl, Kind, After_delim} -> Body_size = Body_end_excl - Body_start, case Body_size > multipartkit@limit:max_part_bytes( Limits ) of true -> {error, {part_too_large, multipartkit@limit:max_part_bytes( Limits )}}; false -> Part_body = multipartkit@internal@bytes:slice_or_empty( Body, Body_start, Body_size ), New_part = multipartkit@part:unchecked_new( Header_list, erlang:element( 2, Meta ), erlang:element( 3, Meta ), erlang:element( 4, Meta ), Part_body ), New_count = Parts_count + 1, case New_count > multipartkit@limit:max_parts( Limits ) of true -> {error, {too_many_parts, multipartkit@limit:max_parts( Limits )}}; false -> case enforce_total( After_delim, Limits ) of {error, Err@3} -> {error, Err@3}; {ok, _} -> Acc@1 = [New_part | Acc], case Kind of closing -> {ok, lists:reverse( Acc@1 )}; delimiter -> parse_loop( Body, Pattern, After_delim, Limits, Acc@1, New_count ) end end end end end end end end end end. -file("src/multipartkit/parser.gleam", 26). ?DOC(" Parse a multipart body with caller-supplied limits.\n"). -spec parse_with_limits(bitstring(), binary(), multipartkit@limit:limits()) -> {ok, list(multipartkit@part:part())} | {error, multipartkit@error:multipart_error()}. parse_with_limits(Body, Content_type, Limits) -> case multipartkit@header:boundary(Content_type) of {error, Err} -> {error, Err}; {ok, Boundary_value} -> Total = erlang:byte_size(Body), case Total > multipartkit@limit:max_body_bytes(Limits) of true -> {error, {body_too_large, multipartkit@limit:max_body_bytes(Limits)}}; false -> Pattern = multipartkit@internal@scan:dash_pattern( Boundary_value ), case multipartkit@internal@scan:find_delimiter( Body, Pattern, 0 ) of incomplete -> {error, unexpected_end_of_input}; {found, _, closing, _} -> {ok, []}; {found, _, delimiter, After_first} -> parse_loop( Body, Pattern, After_first, Limits, [], 0 ) end end end. -file("src/multipartkit/parser.gleam", 18). ?DOC( " Parse a multipart body using `default_limits()`.\n" "\n" " `content_type` must be the full HTTP Content-Type value, including the\n" " `boundary` parameter — for example `multipart/form-data; boundary=abc`.\n" ). -spec parse(bitstring(), binary()) -> {ok, list(multipartkit@part:part())} | {error, multipartkit@error:multipart_error()}. parse(Body, Content_type) -> parse_with_limits(Body, Content_type, multipartkit@limit:default_limits()).