From c3dc71ba4db84f0acc21179b34fb908ccff0bba1 Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Wed, 19 Jan 2022 21:47:34 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20=E4=BB=A3=E7=A0=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/wsCom.hrl | 6 ++-- rebar.config | 1 - src/eWSrv.erl | 19 +++++++++--- src/test/wsEgHer.erl | 8 ++--- src/test/wsTc.erl | 4 +-- src/wsSrv/wsHttp.erl | 58 +++++++++++++++++++++--------------- src/wsSrv/wsHttpProtocol.erl | 31 +++++++++---------- src/wsSrv/wsNet.erl | 1 + src/wsSrv/wsUtil.erl | 11 +++++++ 9 files changed, 86 insertions(+), 53 deletions(-) diff --git a/include/wsCom.hrl b/include/wsCom.hrl index 9e9da7b..d43b513 100644 --- a/include/wsCom.hrl +++ b/include/wsCom.hrl @@ -8,7 +8,7 @@ -define(DefWsOpts, [ binary - , {packet, 4} + , {packet, raw} , {active, false} , {reuseaddr, true} , {nodelay, false} @@ -16,7 +16,7 @@ , {send_timeout, 15000} , {keepalive, true} , {exit_on_close, true} - , {back_log, 1024} + , {backlog, 4096} ]). -define(IIF(Cond, Then, That), case Cond of true -> Then; _ -> That end). @@ -42,7 +42,7 @@ , socket :: undefined | wsNet:socket() , isSsl = false :: boolean() , wsMod :: module() - , maxSize = 0 :: pos_integer() %% 允许接收的最大长度 + , maxSize = infinity :: pos_integer() %% 允许接收的最大长度 , maxChunkCnt = 0 :: pos_integer() %% 允许接收的最大chunk 数量 , maxRecvCnt = 0 :: pos_integer() %% 允许允许recv最大的次数 }). diff --git a/rebar.config b/rebar.config index b933d35..2800bb1 100644 --- a/rebar.config +++ b/rebar.config @@ -1,7 +1,6 @@ {erl_opts, [ debug_info, {i, "include"}, - verbose, warn_export_vars, warn_shadow_vars, warn_obsolete_guard, diff --git a/src/eWSrv.erl b/src/eWSrv.erl index 749175d..52172a7 100644 --- a/src/eWSrv.erl +++ b/src/eWSrv.erl @@ -3,14 +3,26 @@ -include("wsCom.hrl"). -export([ - startWSrv/3 + start/0 + , stop/0 + , startWSrv/3 , stopWSrv/1 ]). +start() -> + application:ensure_all_started(eWSrv). + +stop() -> + application:stop(eWSrv). + startWSrv(WSrvName, Port, WsOpts) -> - TWsOpts = lists:keystore(conMod, 1, WsOpts, {conMod, wsHttp}), + T1WsOpts = lists:keystore(conMod, 1, WsOpts, {conMod, wsHttp}), WsMod = ?wsGLV(wsMod, WsOpts, wsEgHer), - LWsOpts = lists:keystore(conArgs, 1, TWsOpts, {conArgs, WsMod}), + T2WsOpts = lists:keystore(conArgs, 1, T1WsOpts, {conArgs, WsMod}), + TcpOpts = ?wsGLV(tcpOpts, T2WsOpts, []), + NewTcpOpts = wsUtil:mergeOpts(?DefWsOpts, TcpOpts), + LWsOpts = lists:keystore(tcpOpts, 1, T2WsOpts, {tcpOpts, NewTcpOpts}), + case ?wsGLV(sslOpts, WsOpts, false) of false -> {ok, _} = eNet:openTcp(WSrvName, Port, LWsOpts); @@ -18,7 +30,6 @@ startWSrv(WSrvName, Port, WsOpts) -> {ok, _} = eNet:openSsl(WSrvName, Port, LWsOpts) end. - stopWSrv(WSrvName) -> ListenName = wsUtil:lsName(WSrvName), eNet:close(ListenName), diff --git a/src/test/wsEgHer.erl b/src/test/wsEgHer.erl index 9b54118..946a773 100644 --- a/src/test/wsEgHer.erl +++ b/src/test/wsEgHer.erl @@ -14,13 +14,13 @@ ]). -spec handle(Method :: method(), Path :: path(), WsReq :: wsReq()) -> wsHer:response(). -handle('GET', <<"hello/world">>, WsReq) -> - io:format("receive WsReq: ~p~n", [WsReq]), +handle('GET', <<"/hello/world">>, WsReq) -> + io:format("IMY************XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ~n receive WsReq: ~p~n", [WsReq]), %% Reply with a normal response. - timer:sleep(1000), + %timer:sleep(1000), {ok, [], <<"Hello World!">>}; -handle('GET', <<"hello">>, WsReq) -> +handle('GET', <<"/hello">>, WsReq) -> io:format("receive WsReq: ~p~n", [WsReq]), %% Fetch a GET argument from the URL. Name = wsReq:get_arg(<<"name">>, WsReq, <<"undefined">>), diff --git a/src/test/wsTc.erl b/src/test/wsTc.erl index 74eef5c..e2a9632 100644 --- a/src/test/wsTc.erl +++ b/src/test/wsTc.erl @@ -206,9 +206,9 @@ test(N) -> timer:sleep(N), M2 = erlang:monotonic_time(), Time = cvrTimeUnit(M2 - M1, native, nanosecond), - io:format("IMY******************111 ~p~n", [Time]), + io:format("time222 ~p~n", [Time]), S1 = erlang:system_time(nanosecond), timer:sleep(N), S2 = erlang:system_time(nanosecond), - io:format("IMY******************222 ~p~n", [S2 - S1]). + io:format("time222 ~p~n", [S2 - S1]). diff --git a/src/wsSrv/wsHttp.erl b/src/wsSrv/wsHttp.erl index 7dd0004..bede01a 100644 --- a/src/wsSrv/wsHttp.erl +++ b/src/wsSrv/wsHttp.erl @@ -16,7 +16,7 @@ ]). %% eNet callback --export([newCon/2]). +-export([newConn/2]). -export([ init_it/2 @@ -26,7 +26,7 @@ , system_terminate/4 ]). -newCon(_Sock, WsMod) -> +newConn(_Sock, WsMod) -> ?MODULE:start_link(WsMod). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -77,8 +77,7 @@ loop(Parent, State) -> {ok, NewState} -> loop(Parent, NewState); {stop, Reason} -> - terminate(Reason, State), - exit(Reason) + terminate(Reason, State) end end. @@ -89,6 +88,7 @@ init(WsMod) -> {ok, #wsState{wsMod = WsMod}}. handleMsg({tcp, _Socket, Data}, State) -> + ?wsWarn("IMY***************tcp data ~p ~n XXXXXXXXXXXX ~p ~n", [Data, State]), #wsState{stage = Stage, buffer = Buffer, socket = Socket} = State, case wsHttpProtocol:request(Stage, <>, State) of {ok, _NewState} = LRet -> @@ -98,17 +98,22 @@ handleMsg({tcp, _Socket, Data}, State) -> #wsState{buffer = Buffer, socket = Socket, temHeader = TemHeader, method = Method} = NewState, case doResponse(Response, Socket, TemHeader, Method) of keep_alive -> - handleMsg({tcp, _Socket, Buffer}, newWsState(NewState)); + case Buffer of + <<>> -> + {ok, newWsState(NewState)}; + _ -> + handleMsg({tcp, Socket, Buffer}, newWsState(NewState)) + end; close -> - {stop, close} + {stop, normal} end; Err -> ?wsErr("recv the http data error ~p~n", [Err]), sendBadRequest(Socket), - {stop, close} + {stop, Err} end; handleMsg({tcp_closed, _Socket}, _State) -> - {stop, tcp_closed}; + {stop, normal}; handleMsg({tcp_error, _Socket, Reason}, _State) -> ?wsErr("the http tcp socket error ~p~n", [Reason]), {stop, tcp_error}; @@ -123,23 +128,28 @@ handleMsg({ssl, _Socket, Data}, State) -> #wsState{buffer = Buffer, temHeader = TemHeader, method = Method} = NewState, case doResponse(Response, Socket, TemHeader, Method) of keep_alive -> - handleMsg({tcp, Socket, Buffer}, newWsState(NewState)); + case Buffer of + <<>> -> + {ok, newWsState(NewState)}; + _ -> + handleMsg({ssl, Socket, Buffer}, newWsState(NewState)) + end; close -> - {stop, close} + {stop, normal} end; Err -> ?wsErr("recv the http data error ~p~n", [Err]), sendBadRequest(Socket), - {stop, close} + {stop, Err} end; handleMsg({ssl_closed, _Socket}, _State) -> - {stop, ssl_closed}; + {stop, normal}; handleMsg({ssl_error, _Socket, Reason}, _State) -> ?wsErr("the http ssl socket error ~p~n", [Reason]), {stop, ssl_error}; -handleMsg({?mSockReady, Sock}, _State) -> +handleMsg({?mSockReady, Sock}, State) -> inet:setopts(Sock, [{packet, raw}, {active, true}]), - {ok, #wsState{socket = Sock}}; + {ok, State#wsState{socket = Sock}}; handleMsg({?mSockReady, Sock, SslOpts, SslHSTet}, State) -> case wsSslAcceptor:handshake(Sock, SslOpts, SslHSTet) of {ok, SslSock} -> @@ -153,9 +163,9 @@ handleMsg(_Msg, _State) -> ?wsErr("~p info receive unexpect msg ~p ~n ", [?MODULE, _Msg]), kpS. -terminate(_Reason, #wsState{socket = Socket} = _State) -> +terminate(Reason, #wsState{socket = Socket} = _State) -> wsNet:close(Socket), - ok. + exit(Reason). newWsState(WsState) -> WsState#wsState{ @@ -193,19 +203,19 @@ doHandle(State) -> {HttpCode, Body} -> {response, HttpCode, [], Body}; %% Unexpected Unexpected -> - ?wsErr("handle return error ~p ~p~n", [WsReq, Unexpected]), + ?wsErr("handle return error WsReq:~p Ret:~p~n", [WsReq, Unexpected]), {response, 500, [], <<"Internal server error">>} catch throw:{ResponseCode, Headers, Body} when is_integer(ResponseCode) -> {response, ResponseCode, Headers, Body}; throw:Exc:Stacktrace -> - ?wsErr("handle catch throw ~p ~p ~p~n", [WsReq, Exc, Stacktrace]), + ?wsErr("handle catch throw WsReq:~p R:~p S:~p~n", [WsReq, Exc, Stacktrace]), {response, 500, [], <<"Internal server error">>}; error:Error:Stacktrace -> - ?wsErr("handle catch error ~p ~p ~p~n", [WsReq, Error, Stacktrace]), + ?wsErr("handle catch error WsReq:~p R:~p S:~p~n", [WsReq, Error, Stacktrace]), {response, 500, [], <<"Internal server error">>}; exit:Exit:Stacktrace -> - ?wsErr("handle catch exit ~p ~p ~p~n", [WsReq, Exit, Stacktrace]), + ?wsErr("handle catch exit WsReq:~p R:~p S:~p~n", [WsReq, Exit, Stacktrace]), {response, 500, [], <<"Internal server error">>} end. @@ -244,8 +254,8 @@ doResponse({file, ResponseCode, UserHeaders, Filename, Range}, Socket, TemHeader case Ret of ok -> closeOrKeepAlive(UserHeaders, TemHeader); - {error, Reason} -> - {stop, Reason} + _Err -> + {stop, Ret} end end. @@ -443,7 +453,7 @@ connection(UserHeaders, ReqHeader) -> end. contentLength(Headers, Body) -> - case lists:keyfind(?CONTENT_LENGTH_HEADER, Headers) of + case lists:keyfind(?CONTENT_LENGTH_HEADER, 1, Headers) of false -> {?CONTENT_LENGTH_HEADER, iolist_size(Body)}; _ -> @@ -451,7 +461,7 @@ contentLength(Headers, Body) -> end. transferEncoding(Headers) -> - case lists:keyfind(?TRANSFER_ENCODING_HEADER, Headers) of + case lists:keyfind(?TRANSFER_ENCODING_HEADER, 1, Headers) of false -> {?TRANSFER_ENCODING_HEADER, <<"chunked">>}; _ -> diff --git a/src/wsSrv/wsHttpProtocol.erl b/src/wsSrv/wsHttpProtocol.erl index 6d2f744..8603864 100644 --- a/src/wsSrv/wsHttpProtocol.erl +++ b/src/wsSrv/wsHttpProtocol.erl @@ -15,16 +15,17 @@ request(reqLine, Data, State) -> {more, _} -> {ok, State#wsState{buffer = Data}}; {ok, {http_request, Method, RawPath, Version}, Rest} -> - case byte_size(Rest) > 0 of - true -> - case parsePath(RawPath) of - {ok, Scheme, Host, Port, Path, URLArgs} -> - request(header, Rest, State#wsState{stage = header, buffer = Rest, method = Method, path = Path, wsReq = #wsReq{method = Method, path = Path, version = Version, scheme = Scheme, host = Host, port = Port, args = URLArgs}, headerCnt = 0}); - _Err -> - _Err + ?wsErr("IMY**************11111 ~p~n", [{http_request, Method, RawPath, Version}]), + case parsePath(RawPath) of + {ok, Scheme, Host, Port, Path, URLArgs} -> + case Rest of + <<>> -> + {ok, State#wsState{stage = header, buffer = <<>>, method = Method, path = Path, wsReq = #wsReq{method = Method, path = Path, version = Version, scheme = Scheme, host = Host, port = Port, args = URLArgs}, headerCnt = 0}}; + _ -> + request(header, Rest, State#wsState{stage = header, buffer = Rest, method = Method, path = Path, wsReq = #wsReq{method = Method, path = Path, version = Version, scheme = Scheme, host = Host, port = Port, args = URLArgs}, headerCnt = 0}) end; - _ -> - {ok, State#wsState{stage = header, buffer = <<>>, wsReq = #wsReq{method = Method, path = RawPath, version = Version}, headerCnt = 0}} + _Err -> + _Err end; {ok, {http_error, ErrStr}, _} -> {error, ErrStr}; @@ -79,11 +80,11 @@ request(header, Data, State) -> 0 -> {done, State#wsState{buffer = Rest, wsReq = NewWsReq}}; _ -> - case byte_size(Rest) > 0 of - true -> - request(body, Rest, State#wsState{stage = body, buffer = Rest, wsReq = NewWsReq}); + case Rest of + <<>> -> + {ok, State#wsState{stage = body, buffer = <<>>, wsReq = NewWsReq}}; _ -> - {ok, State#wsState{stage = body, buffer = <<>>, wsReq = NewWsReq}} + request(body, Rest, State#wsState{stage = body, buffer = Rest, wsReq = NewWsReq}) end end; {ok, {http_error, ErrStr}, _Rest} -> @@ -104,7 +105,7 @@ request(body, Data, State) -> Ret end; _ -> - BodySize = erlang:size(Data), + BodySize = byte_size(Data), if BodySize == CLen -> {done, State#wsState{buffer = <<>>, wsReq = WsReq#wsReq{body = Data}}}; @@ -156,7 +157,7 @@ parsePath({abs_path, FullPath}) -> Scheme = maps:get(scheme, URIMap, undefined), Path = maps:get(path, URIMap, <<>>), Query = maps:get(query, URIMap, <<>>), - Port = maps:get(port, URIMap, case Scheme of http -> 80; https -> 443; _ -> undefined end), + Port = maps:get(port, URIMap, case Scheme of http -> 80; https -> 443; _ -> 0 end), {ok, Scheme, Host, Port, Path, uri_string:dissect_query(Query)}; parsePath({absoluteURI, Scheme, Host, Port, Path}) -> {_, _Scheme, _Host, _Port, RetPath, RetQuery} = parsePath({abs_path, Path}), diff --git a/src/wsSrv/wsNet.erl b/src/wsSrv/wsNet.erl index 9ce4681..3b0665e 100644 --- a/src/wsSrv/wsNet.erl +++ b/src/wsSrv/wsNet.erl @@ -15,6 +15,7 @@ send(Socket, Data) when is_port(Socket) -> send(Socket, Data) -> ssl:send(Socket, Data). +close(undefined) -> ok; close(Socket) when is_port(Socket) -> gen_tcp:close(Socket); close(Socket) -> diff --git a/src/wsSrv/wsUtil.erl b/src/wsSrv/wsUtil.erl index 9613baf..dc3d350 100644 --- a/src/wsSrv/wsUtil.erl +++ b/src/wsSrv/wsUtil.erl @@ -6,6 +6,7 @@ -export([ gLV/3 + , mergeOpts/2 , normalizeRange/2 , encodeRange/2 , fileSize/1 @@ -23,6 +24,16 @@ gLV(Key, List, Default) -> Value end. +-spec mergeOpts(Defaults :: list(), Options :: list()) -> list(). +mergeOpts(Defaults, Options) -> + lists:foldl( + fun({Opt, Val}, Acc) -> + lists:keystore(Opt, 1, Acc, {Opt, Val}); + (Opt, Acc) -> + lists:usort([Opt | Acc]) + end, + Defaults, Options). + -type range() :: {Offset :: non_neg_integer(), Length :: non_neg_integer()}. -spec normalizeRange(RangeOrSet, Size) -> Normalized when RangeOrSet :: any(),