Skip to content
Permalink
Browse files
Merge pull request #239 from mochi/minimum-otp-18
Set minimum OTP to 18
  • Loading branch information
etrepum committed May 6, 2022
2 parents fce80ef + 73f9244 commit 83fd22d620bbefd8779ccb6ea21706bb8a1e0ed2
Showing 13 changed files with 24 additions and 133 deletions.
@@ -13,20 +13,16 @@ jobs:
os:
- ubuntu-latest
otp:
- "24.0.2"
- "23.3.1"
- "24.3.3"
- "23.3.4.5"
- "22.3.4.9"
- "21.3.8.17"
- "20.3.8.26"
include:
- os: ubuntu-18.04
otp: "21.2.7"
- os: ubuntu-18.04
otp: "19.3.6.13"
- os: ubuntu-18.04
otp: "18.3.4.11"
- os: ubuntu-18.04
otp: "16.b.2.basho10"
steps:
- uses: actions/checkout@v2.3.2
- run: |

This file was deleted.

@@ -1,5 +1,10 @@
New version
Version 3.0.0 released 2022-XX-XX

* Minimum OTP version is now 18, which
allows us to remove a number of backwards
compatibility hacks while still supporting
almost 7 years of Erlang releases.
https://github.com/mochi/mochiweb/pull/239
* Crashing client processes now exit with reason
`{shutdown, Error}`. This ensures processes
linked to the connection process are also
@@ -15,7 +15,7 @@ To create a new mochiweb using project in a specific directory:
Information about Rebar (Erlang build tool) is available at https://github.com/rebar/rebar

MochiWeb is currently tested with Erlang/OTP 18.3 through 24.0,
but may still be compatible back to R15B-03.
versions older than 3.0.0 may still be compatible back to R15B-03.

# OTP 21.2, 21.2.1, 21.2.2 warning

@@ -1,13 +1,8 @@
% -*- mode: erlang -*-
{erl_opts, [debug_info,
{platform_define, "^R15", 'gen_tcp_r15b_workaround'},
{platform_define, "^(R14|R15|R16B-)", 'crypto_compatibility'},
{platform_define, "^(R14|R15|R16|17|18|19|20|21|22)", new_crypto_unavailable},
{platform_define, "^(R14|R15|R16B|17)", 'rand_mod_unavailable'},
{platform_define, "^(R14|R15|R16B|17)", 'sni_unavailable'},
{platform_define, "^(R14|R15|R16)", 'map_unavailable'},
{platform_define, "^(R14|R15|R16|17|18|19|20)", 'ssl_handshake_unavailable'},
{platform_define, "^21-", 'otp_21'}]}.
{platform_define, "^(18|19|20|21|22)", new_crypto_unavailable},
{platform_define, "^(18|19|20)", ssl_handshake_unavailable},
{platform_define, "^21-", otp_21}]}.
{cover_enabled, true}.
{eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}.
{dialyzer_opts, [{warnings, [no_return,
@@ -82,11 +82,6 @@
-define(IS_WHITESPACE(C),
(C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).

-ifdef(map_unavailable).
-define(IS_MAP(_), false).
-else.
-define(IS_MAP(X), is_map(X)).
-endif.

%% @type json_string() = atom | binary()
%% @type json_number() = integer() | float()
@@ -159,14 +154,8 @@ parse_decoder_options([{format, Format} | Rest], State)
when Format =:= struct orelse Format =:= eep18 orelse Format =:= proplist ->
parse_decoder_options(Rest, State#decoder{object_hook=Format}).

-ifdef(map_unavailable).
make_object_hook_for_map() ->
exit({json_decode, {bad_format, map_unavailable}}).
-else.
make_object_hook_for_map() ->
fun ({struct, P}) -> maps:from_list(P) end.
-endif.


json_encode(true, _State) ->
<<"true">>;
@@ -194,7 +183,7 @@ json_encode(Array, State) when is_list(Array) ->
json_encode_array(Array, State);
json_encode({array, Array}, State) when is_list(Array) ->
json_encode_array(Array, State);
json_encode(M, State) when ?IS_MAP(M) ->
json_encode(M, State) when is_map(M) ->
json_encode_map(M, State);
json_encode({json, IoList}, _State) ->
IoList;
@@ -223,11 +212,6 @@ json_encode_proplist(Props, State) ->
[$, | Acc1] = lists:foldl(F, "{", Props),
lists:reverse([$\} | Acc1]).

-ifdef(map_unavailable).
json_encode_map(Bad, _State) ->
%% IS_MAP definition guarantees that this branch is dead
exit({json_encode, {bad_term, Bad}}).
-else.
json_encode_map(Map, _State) when map_size(Map) =:= 0 ->
<<"{}">>;
json_encode_map(Map, State) ->
@@ -238,7 +222,6 @@ json_encode_map(Map, State) ->
end,
[$, | Acc1] = maps:fold(F, "{", Map),
lists:reverse([$\} | Acc1]).
-endif.

json_encode_string(A, State) when is_atom(A) ->
json_encode_string(atom_to_binary(A, latin1), State);
@@ -977,8 +960,6 @@ utf8_non_character_test_() ->
[{"roundtrip escaped", ?_assertEqual(S, decode(encode(S)))},
{"roundtrip utf8", ?_assertEqual(S, decode((encoder([{utf8, true}]))(S)))}].

-ifndef(map_unavailable).

decode_map_test() ->
Json = "{\"var1\": 3, \"var2\": {\"var3\": 7}}",
M = #{<<"var1">> => 3,<<"var2">> => #{<<"var3">> => 7}},
@@ -992,5 +973,3 @@ encode_empty_map_test() ->
?assertEqual(<<"{}">>, encode(#{})).

-endif.

-endif.
@@ -1,7 +1,7 @@
%% This is generated from src/mochiweb.app.src
{application, mochiweb,
[{description, "MochiMedia Web Server"},
{vsn, "2.22.0"},
{vsn, "3.0.0"},
{modules, []},
{registered, []},
{env, []},
@@ -43,16 +43,6 @@

-define(DEFAULTS, [{name, ?MODULE}, {port, 8888}]).

-ifdef(gen_tcp_r15b_workaround).

r15b_workaround() -> false.

-else.

r15b_workaround() -> false.

-endif.

parse_options(Options) ->
{loop, HttpLoop} = proplists:lookup(loop, Options),
Loop = {?MODULE, loop, [HttpLoop]},
@@ -118,8 +108,8 @@ request(Socket, Opts, Body) ->
request(Socket, Opts, Body);
{tcp_closed = Error, _} ->
mochiweb_socket:close(Socket), exit({shutdown, Error});
{tcp_error, _, emsgsize} = Other ->
handle_invalid_msg_request(Other, Socket, Opts);
{tcp_error, _, emsgsize} ->
handle_invalid_request(Socket, Opts);
{ssl_closed = Error, _} ->
mochiweb_socket:close(Socket), exit({shutdown, Error})
after ?REQUEST_RECV_TIMEOUT ->
@@ -155,9 +145,8 @@ headers(Socket, Opts, Request, Headers, Body,
[{Name, Value} | Headers], Body, 1 + HeaderCount);
{tcp_closed = Error, _} ->
mochiweb_socket:close(Socket), exit({shutdown, Error});
{tcp_error, _, emsgsize} = Other ->
handle_invalid_msg_request(Other, Socket, Opts, Request,
Headers)
{tcp_error, _, emsgsize} ->
handle_invalid_request(Socket, Opts, Request, Headers)
after ?HEADERS_RECV_TIMEOUT ->
mochiweb_socket:close(Socket), exit({shutdown, headers_recv_timeout})
end.
@@ -167,27 +156,11 @@ call_body({M, F, A}, Req) when is_atom(M) ->
call_body({M, F}, Req) when is_atom(M) -> M:F(Req);
call_body(Body, Req) -> Body(Req).

-spec handle_invalid_msg_request(term(), term(),
term()) -> no_return().

handle_invalid_msg_request(Msg, Socket, Opts) ->
handle_invalid_msg_request(Msg, Socket, Opts,
-spec handle_invalid_request(term(), term()) -> no_return().
handle_invalid_request(Socket, Opts) ->
handle_invalid_request(Socket, Opts,
{'GET', {abs_path, "/"}, {0, 9}}, []).

-spec handle_invalid_msg_request(term(), term(), term(),
term(), term()) -> no_return().

handle_invalid_msg_request(Msg, Socket, Opts, Request,
RevHeaders) ->
case {Msg, r15b_workaround()} of
{{tcp_error, _, emsgsize}, true} ->
%% R15B02 returns this then closes the socket, so close and exit
mochiweb_socket:close(Socket),
exit({shutdown, {tcp_error, emsgsize}});
_ ->
handle_invalid_request(Socket, Opts, Request,
RevHeaders)
end.

-spec handle_invalid_request(term(), term(), term(),
term()) -> no_return().
@@ -119,26 +119,6 @@ ensure_binary(B) when is_binary(B) ->
ensure_binary(L) when is_list(L) ->
iolist_to_binary(L).

-ifdef(crypto_compatibility).
-spec encrypt_data(binary(), binary()) -> binary().
encrypt_data(Data, Key) ->
IV = crypto:strong_rand_bytes(16),
Crypt = crypto:aes_cfb_128_encrypt(Key, IV, Data),
<<IV/binary, Crypt/binary>>.

-spec decrypt_data(binary(), binary()) -> binary().
decrypt_data(<<IV:16/binary, Crypt/binary>>, Key) ->
crypto:aes_cfb_128_decrypt(Key, IV, Crypt).

-spec gen_key(iolist(), iolist()) -> binary().
gen_key(ExpirationTime, ServerKey) ->
crypto:md5_mac(ServerKey, [ExpirationTime]).

-spec gen_hmac(iolist(), binary(), iolist(), binary()) -> binary().
gen_hmac(ExpirationTime, Data, SessionKey, Key) ->
crypto:sha_mac(Key, [ExpirationTime, Data, SessionKey]).

-else.
-ifdef(new_crypto_unavailable).
-spec encrypt_data(binary(), binary()) -> binary().
encrypt_data(Data, Key) ->
@@ -178,7 +158,6 @@ gen_hmac(ExpirationTime, Data, SessionKey, Key) ->
crypto:mac(hmac, sha, Key, [ExpirationTime, Data, SessionKey]).

-endif.
-endif.

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
@@ -627,13 +627,8 @@ normalize_path("/" ++ Path, "/" ++ _ = Acc) ->
normalize_path([C|Path], Acc) ->
normalize_path(Path, [C|Acc]).

-ifdef(rand_mod_unavailable).
rand_uniform(Start, End) ->
crypto:rand_uniform(Start, End).
-else.
rand_uniform(Start, End) ->
Start + rand:uniform(End - Start) - 1.
-endif.

%%
%% Tests
@@ -9,15 +9,10 @@ id(X) ->
X,
mochiweb_base64url:decode(
binary_to_list(mochiweb_base64url:encode(binary_to_list(X))))).
-ifdef(rand_mod_unavailable).
random_binary(Short,Long) ->
<< <<(random:uniform(256) - 1)>>
|| _ <- lists:seq(1, Short + random:uniform(1 + Long - Short) - 1) >>.
-else.

random_binary(Short,Long) ->
<< <<(rand:uniform(256) - 1)>>
|| _ <- lists:seq(1, Short + rand:uniform(1 + Long - Short) - 1) >>.
-endif.

empty_test() ->
id(<<>>).
@@ -2,16 +2,6 @@

-include_lib("eunit/include/eunit.hrl").

-ifdef(gen_tcp_r15b_workaround).

-define(SHOULD_HAVE_BUG, true).

-else.

-define(SHOULD_HAVE_BUG, false).

-endif.

has_acceptor_bug_test_() ->
{setup, fun start_server/0, fun mochiweb_http:stop/1,
fun has_acceptor_bug_tests/1}.
@@ -27,7 +17,7 @@ has_acceptor_bug_tests(Server) ->
[{"1000 should be fine even with the bug",
?_assertEqual(false, (has_bug(Port, 1000)))},
{"10000 should trigger the bug if present",
?_assertEqual((?SHOULD_HAVE_BUG),
?_assertEqual(false,
(has_bug(Port, 10000)))}].

responder(Req) ->
@@ -47,5 +37,6 @@ has_bug(Port, Len) ->
{{"HTTP/1.1", 200, "OK"}, _,
"<html><body>Hello</body></html>"}} ->
false;
%% It is expected that the request will fail because the header is too long
{ok, {{"HTTP/1.1", 400, "Bad Request"}, _, []}} -> false
end.
@@ -25,13 +25,8 @@ with_server(Transport, ServerFun, ClientFun) ->
mochiweb_http:stop(Server),
Res.

-ifdef(sni_unavailable).
ssl_client_opts(Opts) ->
[{ssl_imp, new} | Opts].
-else.
ssl_client_opts(Opts) ->
[{server_name_indication, disable} | Opts].
-endif.

sock_fun(Transport, Port) ->
Opts = [binary, {active, false}, {packet, http}],

0 comments on commit 83fd22d

Please sign in to comment.