diff --git a/include/http.hrl b/include/http.hrl index 4af646a..14ae611 100644 --- a/include/http.hrl +++ b/include/http.hrl @@ -23,3 +23,10 @@ -type body() :: {partial, binary()} | {multipart, [body_part()]} | zj:value() | binary(). -type body_part() :: {Field :: binary(), Data :: binary()} | {Field :: binary(), Name :: binary(), Data :: binary()}. + + +-type request() :: #request{}. +-type response() :: #response{}. +-type tcp_error() :: closed + | {timeout, RestData :: binary() | erlang:iovec()} + | inet:posix(). diff --git a/priv/static/chat.html b/priv/static/chat.html index 895393b..c8474cd 100644 --- a/priv/static/chat.html +++ b/priv/static/chat.html @@ -3,7 +3,7 @@ Chat with Websockets - +
diff --git a/priv/static/default.css b/priv/static/css/default.css similarity index 100% rename from priv/static/default.css rename to priv/static/css/default.css diff --git a/priv/static/index.html b/priv/static/index.html index e040762..74b4386 100644 --- a/priv/static/index.html +++ b/priv/static/index.html @@ -3,15 +3,28 @@ WF Compiler Demo - +

WFC Demo

diff --git a/priv/static/js/dist/libfewd.d.ts b/priv/static/js/dist/libfewd.d.ts index 1e36154..6334565 100644 --- a/priv/static/js/dist/libfewd.d.ts +++ b/priv/static/js/dist/libfewd.d.ts @@ -3,4 +3,6 @@ * * @module */ -export {}; +export { auto_resize, auto_scroll_to_bottom }; +declare function auto_resize(checkbox_element: HTMLInputElement, target_element: HTMLTextAreaElement, max_height: number): void; +declare function auto_scroll_to_bottom(checkbox_element: HTMLInputElement, target_element: HTMLTextAreaElement): void; diff --git a/priv/static/js/dist/libfewd.js b/priv/static/js/dist/libfewd.js index f609044..c537d72 100644 --- a/priv/static/js/dist/libfewd.js +++ b/priv/static/js/dist/libfewd.js @@ -3,5 +3,22 @@ * * @module */ -export {}; +export { auto_resize, auto_scroll_to_bottom }; +function auto_resize(checkbox_element, target_element, max_height) { + // if the user has manually resized their output, we do nothing + if (checkbox_element.checked) { + let target_height = target_element.scrollHeight; + // resize it automagically up to 500px + if (target_height < max_height) + target_element.style.height = String(target_height) + 'px'; + else + target_element.style.height = String(max_height) + 'px'; + } +} +function auto_scroll_to_bottom(checkbox_element, target_element) { + if (checkbox_element.checked) { + // scroll to bottom + target_element.scrollTop = target_element.scrollHeight; + } +} //# sourceMappingURL=libfewd.js.map \ No newline at end of file diff --git a/priv/static/js/dist/libfewd.js.map b/priv/static/js/dist/libfewd.js.map index 516a45a..83dbe5c 100644 --- a/priv/static/js/dist/libfewd.js.map +++ b/priv/static/js/dist/libfewd.js.map @@ -1 +1 @@ -{"version":3,"file":"libfewd.js","sourceRoot":"","sources":["../ts/libfewd.ts"],"names":[],"mappings":"AAAA;;;;GAIG"} \ No newline at end of file +{"version":3,"file":"libfewd.js","sourceRoot":"","sources":["../ts/libfewd.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,WAAW,EACX,qBAAqB,EACxB,CAAC;AAGF,SACA,WAAW,CACN,gBAAmC,EACnC,cAAsC,EACtC,UAAyB;IAG1B,+DAA+D;IAC/D,IAAI,gBAAgB,CAAC,OAAO,EAAE,CAAC;QAC3B,IAAI,aAAa,GAAW,cAAc,CAAC,YAAY,CAAC;QACxD,sCAAsC;QACtC,IAAI,aAAa,GAAG,UAAU;YAC1B,cAAc,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;;YAE3D,cAAc,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAChE,CAAC;AACL,CAAC;AAGD,SACA,qBAAqB,CAChB,gBAAmC,EACnC,cAAsC;IAGvC,IAAI,gBAAgB,CAAC,OAAO,EAAE,CAAC;QAC3B,mBAAmB;QACnB,cAAc,CAAC,SAAS,GAAG,cAAc,CAAC,YAAY,CAAC;IAC3D,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/priv/static/js/dist/tetris.d.ts b/priv/static/js/dist/tetris.d.ts new file mode 100644 index 0000000..c11d6ac --- /dev/null +++ b/priv/static/js/dist/tetris.d.ts @@ -0,0 +1,6 @@ +/** + * Tetris + * + * @module + */ +export {}; diff --git a/priv/static/js/dist/tetris.js b/priv/static/js/dist/tetris.js new file mode 100644 index 0000000..8d3a122 --- /dev/null +++ b/priv/static/js/dist/tetris.js @@ -0,0 +1,30 @@ +/** + * Tetris + * + * @module + */ +main(); +async function main() { + let ws = new WebSocket("/ws/tetris"); + let elt_tetris_state = document.getElementById('tetris-state'); + ws.onmessage = + (e) => { + handle_evt(e, elt_tetris_state); + }; +} +//----------------------------------------------------- +// Tetris +//----------------------------------------------------- +/** + * take the entire tetris state, render the html elements + * + * then fish out the element in the document, and replace it + * + * blitting basically + */ +async function handle_evt(e, oelt) { + let state_str = e.data; + oelt.value = state_str; +} +export {}; +//# sourceMappingURL=tetris.js.map \ No newline at end of file diff --git a/priv/static/js/dist/tetris.js.map b/priv/static/js/dist/tetris.js.map new file mode 100644 index 0000000..8e6afcc --- /dev/null +++ b/priv/static/js/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../ts/tetris.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,IAAI,EAAE,CAAC;AAEP,KAAK,UACL,IAAI;IAIA,IAAI,EAAE,GAAuC,IAAI,SAAS,CAAC,YAAY,CAAC,CAAqC;IAC7G,IAAI,gBAAgB,GAAyB,QAAQ,CAAC,cAAc,CAAC,cAAc,CAAwB,CAAE;IAE7G,EAAE,CAAC,SAAS;QACR,CAAC,CAAe,EAAE,EAAE;YAChB,UAAU,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACpC,CAAC,CAAA;AACT,CAAC;AAED,uDAAuD;AACvD,SAAS;AACT,uDAAuD;AAGvD;;;;;;GAMG;AACH,KAAK,UACL,UAAU,CACL,CAAmB,EACnB,IAA0B;IAG3B,IAAI,SAAS,GAAY,CAAC,CAAC,IAAc,CAAC;IAC1C,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;AAC3B,CAAC"} \ No newline at end of file diff --git a/priv/static/js/ts/libfewd.ts b/priv/static/js/ts/libfewd.ts index fedf3b7..202bf2d 100644 --- a/priv/static/js/ts/libfewd.ts +++ b/priv/static/js/ts/libfewd.ts @@ -5,6 +5,39 @@ */ export { + auto_resize, + auto_scroll_to_bottom }; +function +auto_resize + (checkbox_element : HTMLInputElement, + target_element : HTMLTextAreaElement, + max_height : number) + : void +{ + // if the user has manually resized their output, we do nothing + if (checkbox_element.checked) { + let target_height: number = target_element.scrollHeight; + // resize it automagically up to 500px + if (target_height < max_height) + target_element.style.height = String(target_height) + 'px'; + else + target_element.style.height = String(max_height) + 'px'; + } +} + + +function +auto_scroll_to_bottom + (checkbox_element : HTMLInputElement, + target_element : HTMLTextAreaElement) + : void +{ + if (checkbox_element.checked) { + // scroll to bottom + target_element.scrollTop = target_element.scrollHeight; + } +} + diff --git a/priv/static/js/ts/tetris.ts b/priv/static/js/ts/tetris.ts new file mode 100644 index 0000000..b2c2004 --- /dev/null +++ b/priv/static/js/ts/tetris.ts @@ -0,0 +1,49 @@ +/** + * Tetris + * + * @module + */ + +export { + +}; + +import * as libfewd from './libfewd.js'; + +main(); + +async function +main + () + : Promise +{ + let ws : WebSocket = new WebSocket("/ws/tetris") ; + let elt_tetris_state : HTMLTextAreaElement = document.getElementById('tetris-state') as HTMLTextAreaElement ; + + ws.onmessage = + (e: MessageEvent) => { + handle_evt(e, elt_tetris_state); + } +} + +//----------------------------------------------------- +// Tetris +//----------------------------------------------------- + + +/** + * take the entire tetris state, render the html elements + * + * then fish out the element in the document, and replace it + * + * blitting basically + */ +async function +handle_evt + (e : MessageEvent, + oelt : HTMLTextAreaElement) + : Promise +{ + let state_str : string = e.data as string; + oelt.value = state_str; +} diff --git a/priv/static/tetris.html b/priv/static/tetris.html new file mode 100644 index 0000000..a600aef --- /dev/null +++ b/priv/static/tetris.html @@ -0,0 +1,18 @@ + + + + + Tetris with Websockets + + + + +
+

Tetris

+ + +
+ + + + diff --git a/priv/static/ws-test-echo.html b/priv/static/ws-test-echo.html index 2c3d47d..9c2f9f3 100644 --- a/priv/static/ws-test-echo.html +++ b/priv/static/ws-test-echo.html @@ -3,7 +3,7 @@ Websockets echo test - +
diff --git a/src/fd_client.erl b/src/fd_client.erl index f5e7fcb..cd93919 100644 --- a/src/fd_client.erl +++ b/src/fd_client.erl @@ -32,7 +32,7 @@ -record(s, {socket = none :: none | gen_tcp:socket(), - next = none :: none | binary()}). + next = <<>> :: binary()}). %% An alias for the state record above. Aliasing state can smooth out annoyances @@ -128,27 +128,20 @@ listen(Parent, Debug, ListenSocket) -> %% The service loop itself. This is the service state. The process blocks on receive %% of Erlang messages, TCP segments being received themselves as Erlang messages. -loop(Parent, Debug, State = #s{socket = Socket, next = Next}) -> +loop(Parent, Debug, State = #s{socket = Socket, next = Next0}) -> ok = inet:setopts(Socket, [{active, once}]), receive {tcp, Socket, Message} -> - tell("~p Next = ~p", [?LINE, Next]), - Received = - case Next of - none -> Message; - _ -> <> - end, - tell("qhl_parse(Socket, ~tp)", [Received]), + Received = <>, case qhl:parse(Socket, Received) of - {ok, Req, NewNext} -> - tell("qhl return: {ok, ~p, ~p}", [Req, NewNext]), - handle_request(Socket, Req), - NewState = State#s{next = NewNext}, + {ok, Req, Next1} -> + Next2 = handle_request(Socket, Req, Next1), + NewState = State#s{next = Next2}, loop(Parent, Debug, NewState); Error -> %% should trigger bad request - io:format("~p QHL parse error: ~tp", [?LINE, Error]), - io:format("~p bad request:~n~ts", [?LINE, Received]), + tell(error, "~p QHL parse error: ~tp", [?LINE, Error]), + tell(error, "~p bad request:~n~ts", [?LINE, Received]), http_err(Socket, 400), gen_tcp:shutdown(Socket, read_write), exit(normal) @@ -217,29 +210,57 @@ system_replace_state(StateFun, State) -> %%% http request handling -handle_request(Sock, R = #request{method = M, path = P}) when M =/= undefined, P =/= undefined -> - tell("~p ~ts", [M, P]), - route(Sock, M, P, R). +-spec handle_request(Sock, Request, Received) -> NewReceived + when Sock :: gen_tcp:socket(), + Request :: request(), + Received :: binary(), + NewReceived :: binary(). + +handle_request(Sock, R = #request{method = M, path = P}, Received) when M =/= undefined, P =/= undefined -> + tell("~tp ~tp ~ts", [self(), M, P]), + route(Sock, M, P, R, Received). -route(Sock, get, Route, Request) -> + +-spec route(Sock, Method, Route, Request, Received) -> NewReceived + when Sock :: gen_tcp:socket(), + Method :: get | post, + Route :: binary(), + Request :: request(), + Received :: binary(), + NewReceived :: binary(). + +route(Sock, get, Route, Request, Received) -> case Route of - <<"/ws/echo">> -> ws_echo(Sock, Request); - <<"/">> -> route_static(Sock, <<"/index.html">>); - _ -> route_static(Sock, Route) + <<"/ws/tetris">> -> ws_tetris(Sock, Request, Received); + <<"/ws/echo">> -> ws_echo(Sock, Request) , Received; + <<"/">> -> route_static(Sock, <<"/index.html">>) , Received; + _ -> route_static(Sock, Route) , Received end; -route(Sock, post, Route, Request) -> +route(Sock, post, Route, Request, Received) -> case Route of - <<"/wfcin">> -> wfcin(Sock, Request); - _ -> http_err(Sock, 404) + <<"/wfcin">> -> wfcin(Sock, Request) , Received; + _ -> http_err(Sock, 404) , Received end; -route(Sock, _, _, _) -> - http_err(Sock, 404). +route(Sock, _, _, _, Received) -> + http_err(Sock, 404), + Received. + +-spec route_static(Socket, Route) -> ok + when Socket :: gen_tcp:socket(), + Route :: binary(). + route_static(Sock, Route) -> respond_static(Sock, fd_sfc:query(Route)). + + +-spec respond_static(Sock, MaybeEty) -> ok + when Sock :: gen_tcp:socket(), + MaybeEty :: fd_sfc:maybe_entry(). + respond_static(Sock, {found, Entry}) -> % -record(e, {fs_path :: file:filename(), % last_modified :: file:date_time(), @@ -259,6 +280,91 @@ respond_static(Sock, not_found) -> http_err(Sock, 404). +%% ------------------------------ +%% tetris +%% ------------------------------ + +-spec ws_tetris(Sock, Request, Received) -> NewReceived + when Sock :: gen_tcp:socket(), + Request :: request(), + Received :: binary(), + NewReceived :: binary(). + +ws_tetris(Sock, Request, Received) -> + try + ws_tetris2(Sock, Request, Received) + catch + X:Y:Z -> + tell(error, "CRASH ws_tetris: ~tp:~tp:~tp", [X, Y, Z]), + http_err(Sock, 500) + end. + + + +-spec ws_tetris2(Sock, Request, Received) -> NewReceived + when Sock :: gen_tcp:socket(), + Request :: request(), + Received :: binary(), + NewReceived :: binary(). + +ws_tetris2(Sock, Request, Received) -> + %tell("~p: ws_tetris request: ~tp", [?LINE, Request]), + case fd_ws:handshake(Request) of + {ok, Response} -> + respond(Sock, Response), + tetris_init(Sock), + ws_tetris_loop(Sock, [], Received); + Error -> + tell("ws_tetris: error: ~tp", [Error]), + http_err(Sock, 400) + end. + + +-spec ws_tetris_loop(Sock, Frames, Received) -> NewReceived + when Sock :: gen_tcp:socket(), + Frames :: [fd_ws:frame()], + Received :: binary(), + NewReceived :: binary(). + +ws_tetris_loop(Sock, Frames, Received) -> + tell("~p:ws_tetris_loop(Sock, ~p, ~p)", [?MODULE, Frames, Received]), + %% create tetris state + case inet:setopts(Sock, [{active, once}]) of + ok -> + receive + {tcp, Sock, Bin} -> + Rcv1 = <>, + tell("~p:~p rcv1: ~tp", [?MODULE, ?LINE, Rcv1]), + ws_tetris_loop(Sock, Frames, <<>>); + {tetris, State} -> + tell("tetris: ~p", [State]), + fd_ws:send(Sock, {text, State}), + ws_tetris_loop(Sock, Frames, Received); + {tcp_closed, Sock} -> {error, tcp_closed}; + {tcp_error, Sock, Reason} -> {error, {tcp_error, Reason}} + after 30_000 -> + {error, timeout} + end; + {error, Reason} -> + {error, {inet, Reason}} + end. + +tetris_init(_Sock) -> + tell("~p tetris_init", [self()]), + Parent = self(), + _Child = spawn_link(fun() -> poop(Parent) end), + ok. + +poop(Parent) -> + tell("~p poop(~p)", [self(), Parent]), + Parent ! {tetris, "poop\n"}, + timer:sleep(3_000), + poop(Parent). + +%% ------------------------------ +%% echo +%% ------------------------------ + ws_echo(Sock, Request) -> try ws_echo2(Sock, Request) @@ -269,12 +375,9 @@ ws_echo(Sock, Request) -> end. ws_echo2(Sock, Request) -> - tell("~p: ws_echo request: ~tp", [?LINE, Request]), case fd_ws:handshake(Request) of {ok, Response} -> - tell("~p: ws_echo response: ~tp", [?LINE, Response]), respond(Sock, Response), - tell("~p: ws_echo: entering loop", [?LINE]), ws_echo_loop(Sock); Error -> tell("ws_echo: error: ~tp", [Error]), @@ -285,15 +388,15 @@ ws_echo_loop(Sock) -> ws_echo_loop(Sock, [], <<>>). ws_echo_loop(Sock, Frames, Received) -> - tell("~p: ws_echo_loop: entering loop", [?LINE]), + tell("~p ws_echo_loop(Sock, ~tp, ~tp)", [self(), Frames, Received]), case fd_ws:recv(Sock, Received, 5*fd_ws:min(), Frames) of Result = {ok, Message, NewFrames, NewReceived} -> - tell("~p: ws_echo_loop ok: ~tp", [?LINE, Result]), + tell("~p echo message: ~tp", [self(), Message]), % send the same message back ok = fd_ws:send(Sock, Message), ws_echo_loop(Sock, NewFrames, NewReceived); Error -> - tell("ws_echo_loop: error: ~tp", [Error]), + tell(error, "ws_echo_loop: error: ~tp", [Error]), fd_ws:send(Sock, {close, <<>>}), error(Error) end. @@ -333,6 +436,12 @@ wfcin(Sock, Request) -> http_err(Sock, 400). + +-spec ctx(Cookies) -> {Cookie, Context} + when Cookies :: #{binary() := Cookie}, + Cookie :: binary(), + Context :: wfc_eval_context:context(). + ctx(#{<<"wfc">> := Cookie}) -> case fd_cache:query(Cookie) of {ok, Context} -> {Cookie, Context}; @@ -341,17 +450,40 @@ ctx(#{<<"wfc">> := Cookie}) -> ctx(_) -> {new_cookie(), wfc_eval_context:default()}. + + +-spec new_cookie() -> Cookie + when Cookie :: binary(). + new_cookie() -> binary:encode_hex(crypto:strong_rand_bytes(8)). + + +-spec jsgud(JSON) -> Encodable + when JSON :: zj:value(), + Encodable :: JSON. + jsgud(X) -> #{"ok" => true, "result" => X}. + + +-spec jsbad(JSON) -> JSBad + when JSON :: zj:value(), + JSBad :: zj:value(). + jsbad(X) -> #{"ok" => false, "error" => X}. + + +-spec http_err(Socket, ErrorCode) -> ok + when Socket :: gen_tcp:socket(), + ErrorCode :: integer(). + http_err(Sock, N) -> Slogan = qhl:slogan(N), Body = ["" @@ -372,10 +504,21 @@ http_err(Sock, N) -> respond(Sock, Resp). -respond(Sock, Response) -> + +-spec respond(Sock, Response) -> ok + when Sock :: gen_tcp:socket(), + Response :: response(). + +respond(Sock, Response = #response{code = Code}) -> + tell("~tp ~tp ~ts", [self(), Code, qhl:slogan(Code)]), gen_tcp:send(Sock, fmtresp(Response)). + +-spec fmtresp(Response) -> Formatted + when Response :: response(), + Formatted :: iolist(). + fmtresp(#response{type = page, %% no idea what {data, String} is version = http11, code = Code, @@ -389,6 +532,12 @@ fmtresp(#response{type = page, %% no idea what {data, String} is Body]. + +-spec add_headers(Existing, Body) -> Hdrs + when Existing :: [{iolist(), iolist()}], + Body :: iolist(), + Hdrs :: [{iolist(), iolist()}]. + %% body needed just for size add_headers(Hs, Body) -> Defaults = default_headers(Body), @@ -396,6 +545,11 @@ add_headers(Hs, Body) -> proplists:from_map(maps:merge(Defaults, Hs2)). + +-spec default_headers(Body) -> HdrsMap + when Body :: iolist(), + HdrsMap :: #{iolist() := iolist()}. + default_headers(Body) -> BodySize = byte_size(iolist_to_binary(Body)), #{"Server" => "fewd 0.1.0", diff --git a/src/fd_sfc.erl b/src/fd_sfc.erl index addf308..04a76d0 100644 --- a/src/fd_sfc.erl +++ b/src/fd_sfc.erl @@ -3,6 +3,11 @@ -behavior(gen_server). +-export_type([ + entry/0, + maybe_entry/0 +]). + -export([ %% caller context base_path/0, @@ -16,6 +21,9 @@ -include("$zx_include/zx_logger.hrl"). +-type entry() :: fd_sfc_entry:entry(). +-type maybe_entry() :: {found, fd_sfc_entry:entry()} | not_found. + -record(s, {base_path = base_path() :: file:filename(), cache = fd_sfc_cache:new(base_path()) :: fd_sfc_cache:cache(), @@ -27,15 +35,22 @@ %% caller context %%----------------------------------------------------------------------------- +-spec base_path() -> file:filename(). base_path() -> filename:join([zx:get_home(), "priv", "static"]). +-spec renew() -> ok. renew() -> gen_server:cast(?MODULE, renew). + +-spec query(HttpPath) -> MaybeEntry + when HttpPath :: binary(), + MaybeEntry :: maybe_entry(). query(Path) -> gen_server:call(?MODULE, {query, Path}). + start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, none, []). diff --git a/src/fd_sfc_cache.erl b/src/fd_sfc_cache.erl index 462cb96..c09dbf9 100644 --- a/src/fd_sfc_cache.erl +++ b/src/fd_sfc_cache.erl @@ -57,18 +57,11 @@ new2(BasePath) -> true -> filename:absname(BasePath); false -> filename:absname(filename:dirname(BasePath)) end, - %% hacky, fuck you - RemovePrefix = - fun (Prefix, Size, From) -> - <> = From, - Rest - end, BBaseDir = unicode:characters_to_binary(BaseDir), - BBS = byte_size(BBaseDir), HandlePath = fun(AbsPath, AccCache) -> BAbsPath = unicode:characters_to_binary(AbsPath), - HttpPath = RemovePrefix(BBaseDir, BBS, BAbsPath), + HttpPath = remove_prefix(BBaseDir, BAbsPath), NewCache = case fd_sfc_entry:new(AbsPath) of {found, Entry} -> maps:put(HttpPath, Entry, AccCache); @@ -81,3 +74,8 @@ new2(BasePath) -> _recursive = true, _fun = HandlePath, _init_acc = #{}). + +remove_prefix(Prefix, From) -> + Size = byte_size(Prefix), + <> = From, + Rest. diff --git a/src/fd_ws.erl b/src/fd_ws.erl index a77f562..8d642fd 100644 --- a/src/fd_ws.erl +++ b/src/fd_ws.erl @@ -21,11 +21,6 @@ -include("http.hrl"). -include("$zx_include/zx_logger.hrl"). --type request() :: #request{}. --type response() :: #response{}. --type tcp_error() :: closed - | {timeout, RestData :: binary() | erlang:iovec()} - | inet:posix(). -define(MAX_PAYLOAD_SIZE, ((1 bsl 63) - 1)). diff --git a/src/qhl.erl b/src/qhl.erl index a57869f..607d97e 100644 --- a/src/qhl.erl +++ b/src/qhl.erl @@ -49,62 +49,52 @@ parse(Socket, Received) -> %% socket. parse(Socket, Received, M = #request{method = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_method(Socket, Received) of {ok, Method, Rest} -> parse(Socket, Rest, M#request{method = Method}); Error -> Error end; parse(Socket, Received, M = #request{path = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_path(Socket, Received) of {ok, Path, Rest} -> parse(Socket, Rest, M#request{path = Path}); Error -> Error end; parse(Socket, Received, M = #request{qargs = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_qargs(Socket, Received) of {ok, Qargs, Rest} -> parse(Socket, Rest, M#request{qargs = Qargs}); Error -> Error end; parse(Socket, Received, M = #request{fragment = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_fragment(Socket, Received) of {ok, Fragment, Rest} -> parse(Socket, Rest, M#request{fragment = Fragment}); Error -> Error end; parse(Socket, Received, M = #request{version = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_version(Socket, Received) of {ok, Version, Rest} -> parse(Socket, Rest, M#request{version = Version}); Error -> Error end; parse(Socket, Received, M = #request{headers = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_headers(Socket, Received) of {ok, Headers, Rest} -> parse(Socket, Rest, M#request{headers = Headers}); Error -> Error end; parse(Socket, Received, M = #request{enctype = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_enctype(M) of {ok, Enctype} -> parse(Socket, Received, M#request{enctype = Enctype}); Error -> Error end; parse(Socket, Received, M = #request{cookies = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_cookies(M) of {ok, Cookies} -> parse(Socket, Received, M#request{cookies = Cookies}); Error -> Error end; parse(Socket, Received, M = #request{size = undefined}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_size(M) of {ok, 0} -> {ok, M#request{size = 0}, none}; {ok, Size} -> parse(Socket, Received, M#request{size = Size}); Error -> Error end; parse(Socket, Received, M = #request{method = get, body = undefined, size = Size}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_body(Received, Size) of {ok, Body} -> {ok, M#request{body = Body}, none}; {ok, Body, Next} -> {ok, M#request{body = Body}, Next}; @@ -117,7 +107,6 @@ parse(Socket, method = post, enctype = urlencoded, size = Size}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_body(Received, Size) of {ok, Body} -> {ok, M#request{body = parts_to_map(posted(Body))}, none}; @@ -141,7 +130,6 @@ parse(Socket, method = post, enctype = {multipart, Boundary}, size = Size}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_multipart(Socket, Received, Boundary, Size) of {ok, Parts} -> {ok, M#request{body = parts_to_map(Parts)}, none}; {ok, Parts, Next} -> {ok, M#request{body = parts_to_map(Parts)}, Next}; @@ -153,12 +141,10 @@ parse(Socket, method = post, enctype = json, size = Size}) -> - io:format("~p parse(~p, ~p, ~p)~n", [?LINE, Socket, Received, M]), case read_body(Received, Size) of {ok, Body} -> read_json(M#request{body = Body}, none); {ok, Body, Next} -> read_json(M#request{body = Body}, Next); {incomplete, Body} -> - io:format("~p {incomplete, ~p}~n", [?LINE, Body]), case accumulate(Socket, M#request{body = Body}) of {ok, NewM = #request{body = NewBody}} -> read_json(NewM#request{body = NewBody}, none); @@ -528,7 +514,6 @@ read_size(#request{method = options}) -> read_body(Received, Size) -> - io:format("~p read_body(~p, ~p)~n", [?LINE, Received, Size]), case Received of <> -> {ok, Bin}; @@ -826,11 +811,9 @@ accumulate(Socket, M = #request{size = Size, body = Body}) -> end. accumulate(Socket, Remaining, Received) when Remaining > 0 -> - io:format("~p accumulate(~p, ~p, ~p)~n", [?LINE, Socket, Remaining, Received]), ok = inet:setopts(Socket, [{active, once}]), receive {tcp, Socket, Bin} -> - io:format("~p~n", [?LINE]), Size = byte_size(Bin), if Size == Remaining -> @@ -845,16 +828,12 @@ accumulate(Socket, Remaining, Received) when Remaining > 0 -> {ok, NewReceived, Next} end; {tcp_closed, Socket} -> - io:format("~p~n", [?LINE]), {error, tcp_closed}; {tcp_error, Socket, Reason} -> - io:format("~p~n", [?LINE]), - {error, {tcp_error, Reason}}; - X -> - io:format("~p raseevd: ~p~n", [?LINE, X]) - after 10_000 -> - io:format("~p~n", [?LINE]), - {error, timeout} + {error, {tcp_error, Reason}} + %X -> + after 3_000 -> + {error, timeout} end; accumulate(_, 0, Received) -> {ok, Received};