WFC Demo
-
-
- Websocket Chatroom -
- Websocket Echo Test +
-
+ Websocket demos that work
+
+
-
+
- Echo +
+ - + Don't work + + +
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
+
+
+
+
+ Websockets echo test
-
+
+
+
+
+
+
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 @@
Tetris
+ + +
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};