-module(internal@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/internal/parser.gleam"). -export([parse_method/1, new_parsed_request/0, new_parser/0, pretty_print_parsed/1, parse_request/1]). -export_type([parse_error/0, stage/0, body_type/0, http_version/0, parsed_request/0, parser/0]). -type parse_error() :: {incomplete, parser()} | invalid | too_large | unsupported_version | host_missing | multi_line_header_unsupported. -type stage() :: request_line | headers | {body, body_type()} | trailers | done. -type body_type() :: {content_length, integer()} | {chunked, gleam@option:option(integer())} | empty. -type http_version() :: http11. -type parsed_request() :: {parsed_request, gleam@option:option(gleam@http:method()), gleam@option:option(gleam@uri:uri()), gleam@option:option(http_version()), gleam@option:option(gleam@dict:dict(binary(), binary())), gleam@option:option(gleam@set:set(binary())), gleam@option:option(bitstring()), integer()}. -type parser() :: {parser, gleam@http@request:request(bitstring()), gleam@dict:dict(binary(), binary()), gleam@set:set(binary()), integer(), stage(), bitstring()}. -file("src/internal/parser.gleam", 57). -spec parse_method(bitstring()) -> {ok, gleam@http:method()} | {error, parse_error()}. parse_method(Method) -> case Method of <<"GET"/utf8>> -> {ok, get}; <<"POST"/utf8>> -> {ok, post}; <<"PUT"/utf8>> -> {ok, put}; <<"DELETE"/utf8>> -> {ok, delete}; <<"PATCH"/utf8>> -> {ok, patch}; <<"OPTIONS"/utf8>> -> {ok, options}; <<"HEAD"/utf8>> -> {ok, head}; _ -> {error, invalid} end. -file("src/internal/parser.gleam", 86). -spec new_parsed_request() -> parsed_request(). new_parsed_request() -> {parsed_request, none, none, none, none, none, none, 0}. -file("src/internal/parser.gleam", 109). -spec new_parser() -> parser(). new_parser() -> {parser, begin _pipe = gleam@http@request:new(), gleam@http@request:set_body(_pipe, <<>>) end, maps:new(), gleam@set:new(), 0, request_line, <<>>}. -file("src/internal/parser.gleam", 120). -spec pretty_print_parsed(gleam@http@request:request(bitstring())) -> nil. pretty_print_parsed(Request) -> gleam_stdlib:println( <<"\n================================================"/utf8>> ), gleam_stdlib:println(<<"Request:"/utf8>>), gleam_stdlib:println( <<"Method: "/utf8, (begin _pipe = erlang:element(2, Request), gleam@http:method_to_string(_pipe) end)/binary>> ), gleam_stdlib:println( <<"Path: "/utf8, ((erlang:element(8, Request)))/binary>> ), gleam_stdlib:println( <<"Query: "/utf8, (begin _pipe@1 = erlang:element(9, Request), gleam@option:unwrap(_pipe@1, <<"-"/utf8>>) end)/binary>> ), gleam_stdlib:println(<<"Headers:"/utf8>>), _pipe@2 = erlang:element(3, Request), gleam@list:each( _pipe@2, fun(Header) -> gleam_stdlib:println( <<<<<<" "/utf8, ((erlang:element(1, Header)))/binary>>/binary, ": "/utf8>>/binary, ((erlang:element(2, Header)))/binary>> ) end ), gleam_stdlib:println(<<"Body:"/utf8>>), gleam_stdlib:println( <<" "/utf8, (begin _pipe@3 = erlang:element(4, Request), _pipe@4 = gleam@bit_array:to_string(_pipe@3), gleam@result:unwrap(_pipe@4, <<"-"/utf8>>) end)/binary>> ). -file("src/internal/parser.gleam", 169). -spec handle_request_line(parser()) -> {ok, parser()} | {error, parse_error()}. handle_request_line(Parser) -> Request_parts = case binary:split( erlang:element(7, Parser), <<"\r\n"/utf8>>, [] ) of [Request_line, Remaining] -> {ok, {Request_line, Remaining}}; _ -> {error, {incomplete, Parser}} end, gleam@result:'try'( Request_parts, fun(_use0) -> {Request_line@1, Remaining@1} = _use0, gleam@bool:guard( erlang:byte_size(Request_line@1) > 8192, {error, too_large}, fun() -> Global = erlang:binary_to_atom(<<"global"/utf8>>), Request_line_parts = case binary:split( Request_line@1, <<" "/utf8>>, [Global] ) of [Method, Target, Version] -> {ok, {Method, Target, Version}}; _ -> {error, invalid} end, gleam@result:'try'( Request_line_parts, fun(_use0@1) -> {Method@1, Target@1, Version@1} = _use0@1, gleam@bool:guard( erlang:byte_size(Target@1) > 8000, {error, too_large}, fun() -> gleam@result:'try'( parse_method(Method@1), fun(Method@2) -> gleam@result:'try'( begin _pipe = gleam@bit_array:to_string( Target@1 ), _pipe@1 = gleam@result:map( _pipe, fun gleam_stdlib:uri_parse/1 ), _pipe@2 = gleam@result:flatten( _pipe@1 ), gleam@result:replace_error( _pipe@2, invalid ) end, fun(Target@2) -> gleam@result:'try'( case Version@1 of <<"HTTP/1.1"/utf8>> -> {ok, http11}; <<"HTTP/"/utf8, _/binary>> -> {error, unsupported_version}; _ -> {error, invalid} end, fun(_) -> Request = begin _record = erlang:element( 2, Parser ), {request, Method@2, erlang:element( 3, _record ), erlang:element( 4, _record ), http, begin _pipe@3 = erlang:element( 4, Target@2 ), gleam@option:unwrap( _pipe@3, <<"localhost"/utf8>> ) end, erlang:element( 5, Target@2 ), erlang:element( 6, Target@2 ), erlang:element( 7, Target@2 )} end, {ok, {parser, Request, erlang:element( 3, Parser ), erlang:element( 4, Parser ), erlang:element( 5, Parser ), headers, Remaining@1}} end ) end ) end ) end ) end ) end ) end ). -file("src/internal/parser.gleam", 271). -spec handle_header(parser()) -> {ok, parser()} | {error, parse_error()}. handle_header(Parser) -> Header_parts = case binary:split( erlang:element(7, Parser), <<"\r\n"/utf8>>, [] ) of [Header, Remaining] -> {ok, {Header, Remaining}}; _ -> {error, {incomplete, Parser}} end, gleam@result:'try'( Header_parts, fun(_use0) -> {Header@1, Remaining@1} = _use0, gleam@bool:guard( erlang:byte_size(Header@1) > 8192, {error, too_large}, fun() -> Header_parts@1 = case binary:split( Header@1, <<":"/utf8>>, [] ) of [Name, Value] -> {ok, {Name, Value}}; _ -> {error, invalid} end, gleam@result:'try'( Header_parts@1, fun(_use0@1) -> {Name@1, Value@1} = _use0@1, gleam@result:'try'( begin _pipe = gleam@bit_array:to_string(Name@1), _pipe@1 = gleam@result:map( _pipe, fun string:lowercase/1 ), gleam@result:replace_error(_pipe@1, invalid) end, fun(Name@2) -> gleam@bool:guard( gleam_stdlib:contains_string( Name@2, <<" "/utf8>> ), {error, invalid}, fun() -> Skip = case erlang:element( 6, Parser ) of trailers -> not gleam@set:contains( erlang:element( 4, Parser ), Name@2 ); _ -> false end, case Skip of true -> {ok, {parser, erlang:element( 2, Parser ), erlang:element( 3, Parser ), erlang:element( 4, Parser ), erlang:element( 5, Parser ), erlang:element( 6, Parser ), Remaining@1}}; false -> gleam@result:'try'( begin _pipe@2 = gleam@bit_array:to_string( Value@1 ), _pipe@3 = gleam@result:map( _pipe@2, fun gleam@string:trim/1 ), gleam@result:replace_error( _pipe@3, invalid ) end, fun(Value@2) -> gleam@bool:guard( erlang:byte_size( Value@2 ) > 4096, {error, too_large}, fun() -> Headers = gleam@dict:upsert( erlang:element( 3, Parser ), Name@2, fun( Exists ) -> case Exists of {some, Acc} -> <<<>/binary, Value@2/binary>>; none -> Value@2 end end ), Trailers = case Name@2 of <<"trailer"/utf8>> -> _pipe@4 = gleam@string:split( Value@2, <<","/utf8>> ), gleam@list:fold( _pipe@4, erlang:element( 4, Parser ), fun( Acc@1, Trailer ) -> gleam@set:insert( Acc@1, begin _pipe@5 = gleam@string:trim( Trailer ), string:lowercase( _pipe@5 ) end ) end ); _ -> erlang:element( 4, Parser ) end, Parser@1 = {parser, erlang:element( 2, Parser ), Headers, Trailers, erlang:element( 5, Parser ), erlang:element( 6, Parser ), Remaining@1}, {ok, Parser@1} end ) end ) end end ) end ) end ) end ) end ). -file("src/internal/parser.gleam", 349). -spec handle_body(parser(), integer()) -> {ok, parser()} | {error, parse_error()}. handle_body(Parser, Content_length) -> gleam@bool:guard( Content_length > 10485760, {error, too_large}, fun() -> case erlang:element(7, Parser) of <> -> Request = begin _record = erlang:element(2, Parser), {request, erlang:element(2, _record), erlang:element(3, _record), Body, erlang:element(5, _record), erlang:element(6, _record), erlang:element(7, _record), erlang:element(8, _record), erlang:element(9, _record)} end, {ok, {parser, Request, erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), done, erlang:element(7, Parser)}}; <<_:Content_length/binary, _>> -> {error, invalid}; _ -> {error, {incomplete, Parser}} end end ). -file("src/internal/parser.gleam", 365). -spec handle_chunked_body(parser(), gleam@option:option(integer())) -> {ok, parser()} | {error, parse_error()}. handle_chunked_body(Parser, Chunk_size) -> gleam@bool:guard( erlang:element(5, Parser) > 10485760, {error, too_large}, fun() -> case Chunk_size of none -> case binary:split( erlang:element(7, Parser), <<"\r\n"/utf8>>, [] ) of [Possible_size, Remaining] -> gleam@result:'try'( begin _pipe = gleam@bit_array:to_string( Possible_size ), _pipe@1 = gleam@result:map( _pipe, fun(_capture) -> gleam@int:base_parse(_capture, 16) end ), _pipe@2 = gleam@result:flatten(_pipe@1), gleam@result:replace_error(_pipe@2, invalid) end, fun(Chunk_size@1) -> Parser@1 = {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), {body, {chunked, {some, Chunk_size@1}}}, Remaining}, handle_chunked_body( Parser@1, {some, Chunk_size@1} ) end ); _ -> {error, {incomplete, Parser}} end; {some, 0} -> case erlang:element(7, Parser) of <<"\r\n"/utf8>> -> {ok, {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), done, erlang:element(7, Parser)}}; Trailers -> {ok, {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), trailers, Trailers}} end; {some, Size} -> gleam@bool:guard( (Size > (10485760 div 10)) orelse ((erlang:element( 5, Parser ) + Size) > 10485760), {error, too_large}, fun() -> case erlang:element(7, Parser) of <> -> Request = begin _record = erlang:element(2, Parser), {request, erlang:element(2, _record), erlang:element(3, _record), <<(erlang:element( 4, erlang:element(2, Parser) ))/bitstring, Chunk/bitstring>>, erlang:element(5, _record), erlang:element(6, _record), erlang:element(7, _record), erlang:element(8, _record), erlang:element(9, _record)} end, Parser@2 = {parser, Request, erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser) + Size, {body, {chunked, none}}, Remaining@1}, handle_chunked_body(Parser@2, none); _ -> {error, {incomplete, Parser}} end end ) end end ). -file("src/internal/parser.gleam", 222). -spec handle_headers(parser()) -> {ok, parser()} | {error, parse_error()}. handle_headers(Parser) -> gleam@bool:guard( maps:size(erlang:element(3, Parser)) > 100, {error, too_large}, fun() -> case {erlang:element(7, Parser), erlang:element(6, Parser)} of {<<"\r\n"/utf8, Remaining/bitstring>>, headers} -> Content_length = begin _pipe = gleam_stdlib:map_get( erlang:element(3, Parser), <<"content-length"/utf8>> ), _pipe@1 = gleam@result:map( _pipe, fun gleam_stdlib:parse_int/1 ), gleam@result:flatten(_pipe@1) end, Transfer_encoding = gleam_stdlib:map_get( erlang:element(3, Parser), <<"transfer-encoding"/utf8>> ), Parser@1 = case {Transfer_encoding, Content_length} of {{ok, <<"chunked"/utf8>>}, _} -> {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), {body, {chunked, none}}, Remaining}; {_, {ok, Content_length@1}} -> {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), {body, {content_length, Content_length@1}}, Remaining}; {_, _} -> {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), {body, empty}, Remaining} end, {ok, Parser@1}; {<<"\r\n"/utf8>>, trailers} -> Request = begin _record = erlang:element(2, Parser), {request, erlang:element(2, _record), begin _pipe@2 = erlang:element(3, Parser), maps:to_list(_pipe@2) end, erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record), erlang:element(7, _record), erlang:element(8, _record), erlang:element(9, _record)} end, {ok, {parser, Request, erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), done, erlang:element(7, Parser)}}; {<<"\r\n"/utf8, _/bitstring>>, trailers} -> {error, invalid}; {<<"\t"/utf8, _/bitstring>>, headers} -> {error, multi_line_header_unsupported}; {<<" "/utf8, _/bitstring>>, headers} -> {error, multi_line_header_unsupported}; {_, _} -> case handle_header(Parser) of {ok, Parser@2} -> handle_headers(Parser@2); {error, Error} -> {error, Error} end end end ). -file("src/internal/parser.gleam", 142). -spec parse_request(parser()) -> {ok, gleam@http@request:request(bitstring())} | {error, parse_error()}. parse_request(Parser) -> {Stage_parsed, Finished} = case erlang:element(6, Parser) of request_line -> {handle_request_line(Parser), false}; headers -> {handle_headers(Parser), false}; {body, empty} -> {{ok, {parser, erlang:element(2, Parser), erlang:element(3, Parser), erlang:element(4, Parser), erlang:element(5, Parser), done, erlang:element(7, Parser)}}, false}; {body, {content_length, Content_length}} -> {handle_body(Parser, Content_length), false}; {body, {chunked, Chunk_size}} -> {handle_chunked_body(Parser, Chunk_size), false}; trailers -> {handle_headers(Parser), false}; done -> {{ok, Parser}, true} end, case {Stage_parsed, Finished} of {{ok, Parser@1}, false} -> parse_request(Parser@1); {{ok, Parser@2}, true} -> {ok, erlang:element(2, Parser@2)}; {{error, Error}, _} -> {error, Error} end.