Skip to content

Commit

Permalink
Merge pull request #1 from nhs-riak/nhse-d34-otp26
Browse files Browse the repository at this point in the history
Nhse d34 otp26
  • Loading branch information
martinsumner authored Sep 9, 2024
2 parents adb632e + 278ef89 commit e83530d
Show file tree
Hide file tree
Showing 20 changed files with 427 additions and 106 deletions.
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ insert_final_newline = true
[*.{erl,src,hrl}]
indent_style = space
indent_size = 4
tab_width = 8
28 changes: 16 additions & 12 deletions .github/workflows/erlang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,35 @@ name: Erlang CI

on:
push:
branches: [ develop ]
branches:
- nhse-develop
- nhse-develop-3.2
- nhse-develop-3.4
pull_request:
branches: [ develop ]
branches:
- nhse-develop
- nhse-develop-3.2
- nhse-develop-3.4


jobs:

build:

runs-on: ubuntu-latest
name: Test on ${{ matrix.os }} with OTP ${{ matrix.otp }}
runs-on: ${{ matrix.os }}

container:
image: erlang:${{matrix.otp}}

strategy:
fail-fast: false
matrix:
otp:
- "25.1"
- "24.3"
- "22.3"

container:
image: erlang:${{ matrix.otp }}
otp: [24, 26]
os: [ubuntu-latest]

steps:
- uses: lukka/get-cmake@latest
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Compile
run: ./rebar3 compile
- name: Run xref and dialyzer
Expand Down
36 changes: 36 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
Version 3.2.2 released 2024-03-21

* Use single quotes around 'maybe' atom for compatibility with OTP 27
https://github.com/mochi/mochiweb/pull/262
* Update Erlang CI images
https://github.com/mochi/mochiweb/pull/261

Version 3.2.1 released 2023-09-22

* mochinum:digits/1: fix handling of -0.0 for OTP-26.1/27.0
https://github.com/mochi/mochiweb/pull/260

Version 3.2.0 released 2023-08-31

* Add new mochiweb_request:is_closed/1 function
https://github.com/mochi/mochiweb/pull/258

Version 3.1.2 released 2023-04-20

* Fix rebar edoc settings
https://github.com/mochi/mochiweb/pull/257

Version 3.1.1 released 2022-10-11

* OTP 25 added to test matrix
https://github.com/mochi/mochiweb/pull/251
* Fix for chunk length parsing edge case
https://github.com/mochi/mochiweb/pull/249

Version 3.1.0 released 2022-08-13

* Leading and trailing whitespace in header values are now trimmed
for better RFC 7230 compliance.
https://github.com/mochi/mochiweb/pull/247
https://github.com/mochi/mochiweb/pull/248

Version 3.0.0 released 2022-05-09

* rebar3 is now the preferred build tool (finally)
Expand Down
52 changes: 44 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,56 @@
# MochiWeb
MochiWeb is an Erlang library for building lightweight HTTP servers.

The latest version of MochiWeb is available at https://github.com/mochi/mochiweb
## Overview
MochiWeb provides a lightweight and fast solution for building HTTP servers in Erlang. The library provides features for building robust and scalable HTTP servers.

The mailing list for MochiWeb is at https://groups.google.com/group/mochiweb/
## Getting Started
Before you can use MochiWeb, you'll need to have [Erlang OTP](https://www.erlang.org/) installed. Once you have Erlang OTP installed, you can download the latest version of MochiWeb from the [GitHub repository](https://github.com/mochi/mochiweb).

Erlang OTP is required for setting up the MochiWeb environment and is available at https://www.erlang.org/
For a MochiWeb project, first obtain a copy of MochiWeb using Git by running the command.

To create a new mochiweb using project see the `example_project` in the `examples/` folder.

Information about Rebar (Erlang build tool) is available at https://github.com/erlang/rebar3
```erlang-repl
$ git clone git://github.com/mochi/mochiweb.git.
```
To create a project.

MochiWeb is currently tested with Erlang/OTP 18.3 through 24.0,
versions older than 3.0.0 may still be compatible back to R15B-03.
```erlang-repl
$ cd mochiweb
$ make app PROJECT=exampleName
```

# OTP 21.2, 21.2.1, 21.2.2 warning
You can now start the project with.

```erlang-repl
$ cd ../exampleName/
$ make
$ ./start-dev.sh
```

You can access the app by navigating to http://localhost:8080 in your browser.

For an example, view the `example_project` in the `examples/` folder.


## Benefits
* Lightweight: MochiWeb is designed to be lightweight and fast, making it ideal for use in resource-constrained environments.

* Easy to use: MochiWeb provides a simple and intuitive API that makes it easy to get started with building HTTP servers.

* Robust: MochiWeb provides a comprehensive set of features for building robust and scalable HTTP servers.

## Documentations and Resources
[Information about Rebar (Erlang build tool)](https://github.com/erlang/rebar3)

[Mailing list](https://groups.google.com/group/mochiweb/)

## OTP 21.2, 21.2.1, 21.2.2 warning

OTP 21.2 (up to and including 21.2.2) introduced an SSL regression that
makes these releases unsafe to use. See [ERL-830](https://bugs.erlang.org/browse/ERL-830).
This issue was resolved in OTP 21.2.3.


## Contributing
MochiWeb is an open-source project and welcomes contributions from the community.
5 changes: 5 additions & 0 deletions erlang_ls.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apps_dirs:
- "_build/default/lib/*"
include_dirs:
- "_build/default/lib/*/include"
- "include"
1 change: 1 addition & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
{test, [{deps, [meck]}]},
{gha, [{erl_opts, [{d, 'GITHUBEXCLUDE'}]}]}
]}.
{edoc_opts, [{preprocess, true}]}.
{dialyzer_opts, [{warnings, [no_return,
no_unused,
no_improper_lists,
Expand Down
5 changes: 3 additions & 2 deletions src/mochijson2.erl
Original file line number Diff line number Diff line change
Expand Up @@ -966,8 +966,9 @@ decode_map_test() ->
?assertEqual(M, decode(Json, [{format, map}])).

encode_map_test() ->
M = <<"{\"a\":1,\"b\":{\"c\":2}}">>,
?assertEqual(M, iolist_to_binary(encode(#{a => 1, b => #{ c => 2}}))).
?assertEqual(<<"{\"a\":1}">>, iolist_to_binary(encode(#{a => 1}))),
M = #{<<"a">> => 1, <<"b">> => #{<<"c">> => 2}},
?assertEqual(M, decode(iolist_to_binary(encode(#{a => 1, b => #{ c => 2}})), [{format, map}])).

encode_empty_map_test() ->
?assertEqual(<<"{}">>, encode(#{})).
Expand Down
4 changes: 3 additions & 1 deletion src/mochinum.erl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
%% human-readable output, or compact ASCII serializations for floats.
digits(N) when is_integer(N) ->
integer_to_list(N);
digits(0.0) ->
digits(Float) when Float == 0.0 ->
"0.0";
digits(Float) ->
{Frac1, Exp1} = frexp_int(Float),
Expand Down Expand Up @@ -287,6 +287,8 @@ digits_test() ->
digits(0)),
?assertEqual("0.0",
digits(0.0)),
?assertEqual("0.0",
digits(-0.0)),
?assertEqual("1.0",
digits(1.0)),
?assertEqual("-1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/mochiweb.app.src
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%% This is generated from src/mochiweb.app.src
{application, mochiweb,
[{description, "MochiMedia Web Server"},
{vsn, "3.0.0"},
{vsn, "3.2.2"},
{modules, []},
{registered, []},
{env, []},
Expand Down
18 changes: 14 additions & 4 deletions src/mochiweb_headers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ lookup(K, T) ->
%% @doc Insert the pair into the headers if it does not already exist.
default(K, V, T) ->
K1 = normalize(K),
V1 = any_to_list(V),
V1 = trim_leading_and_trailing_ws(any_to_list(V)),
try gb_trees:insert(K1, {K, V1}, T)
catch
error:{key_exists, _} ->
Expand All @@ -185,15 +185,15 @@ default(K, V, T) ->
%% @doc Insert the pair into the headers, replacing any pre-existing key.
enter(K, V, T) ->
K1 = normalize(K),
V1 = any_to_list(V),
V1 = trim_leading_and_trailing_ws(any_to_list(V)),
gb_trees:enter(K1, {K, V1}, T).

%% @spec insert(key(), value(), headers()) -> headers()
%% @doc Insert the pair into the headers, merging with any pre-existing key.
%% A merge is done with Value = V0 ++ ", " ++ V1.
insert(K, V, T) ->
K1 = normalize(K),
V1 = any_to_list(V),
V1 = trim_leading_and_trailing_ws(any_to_list(V)),
try gb_trees:insert(K1, {K, V1}, T)
catch
error:{key_exists, _} ->
Expand All @@ -215,6 +215,9 @@ tokenize_header_value(undefined) ->
tokenize_header_value(V) ->
reversed_tokens(trim_and_reverse(V, false), [], []).

trim_leading_and_trailing_ws(S) ->
trim_and_reverse(trim_and_reverse(S, false), false).

trim_and_reverse([S | Rest], Reversed) when S=:=$ ; S=:=$\n; S=:=$\t ->
trim_and_reverse(Rest, Reversed);
trim_and_reverse(V, false) ->
Expand Down Expand Up @@ -242,7 +245,7 @@ reversed_tokens([C | Rest], Token, Acc) when C=:=$ ;C=:=$\n;C=:=$\t;C=:=$, ->
reversed_tokens([C | Rest], Token, Acc) ->
reversed_tokens(Rest, [C | Token], Acc);
reversed_tokens(_, _, _) ->
undefeined.
undefined.

extract_quoted_string([], _Acc) ->
undefined;
Expand Down Expand Up @@ -364,6 +367,13 @@ set_cookie_test() ->
to_list(H)),
ok.

whitespace_headers_test() ->
%% Check RFC 7230 whitespace compliance
H = ?MODULE:make([{"X-Auth-Roles", " test, test2,test3, test4, test5 , test6 "}]),
?assertEqual(
[{"X-Auth-Roles", "test, test2,test3, test4, test5 , test6"}],
to_list(H)).

headers_test() ->
H = ?MODULE:make([{hdr, foo}, {"Hdr", "bar"}, {'Hdr', 2}]),
[{hdr, "foo, bar, 2"}] = ?MODULE:to_list(H),
Expand Down
12 changes: 6 additions & 6 deletions src/mochiweb_multipart.erl
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ feed_mp(body,
C1 = Callback({body, Data}),
feed_mp(headers,
State#mp{callback = C1(body_end), buffer = Rest});
{maybe, Start} ->
{'maybe', Start} ->
<<Data:Start/binary, Rest/binary>> = Buffer,
feed_mp(body,
read_more(State#mp{callback = Callback({body, Data}),
Expand Down Expand Up @@ -328,15 +328,15 @@ find_boundary(Prefix, Data) ->
{end_boundary, Skip, size(Prefix) + 4};
_ when size(Data) < PrefixSkip + 4 ->
%% Underflow
{maybe, Skip};
{'maybe', Skip};
_ ->
%% False positive
not_found
end;
{partial, Skip, Length}
when Skip + Length =:= size(Data) ->
%% Underflow
{maybe, Skip};
{'maybe', Skip};
_ -> not_found
end.

Expand Down Expand Up @@ -695,8 +695,8 @@ find_boundary_test() ->
{end_boundary, 1, 9} = find_boundary(B,
<<"!\r\n--X--\r\nRest">>),
not_found = find_boundary(B, <<"--X\r\nRest">>),
{maybe, 0} = find_boundary(B, <<"\r\n--X\r">>),
{maybe, 1} = find_boundary(B, <<"!\r\n--X\r">>),
{'maybe', 0} = find_boundary(B, <<"\r\n--X\r">>),
{'maybe', 1} = find_boundary(B, <<"!\r\n--X\r">>),
P = <<"\r\n-----------------------------160374543510"
"82272548568224146">>,
B0 = <<55, 212, 131, 77, 206, 23, 216, 198, 35, 87, 252,
Expand All @@ -705,7 +705,7 @@ find_boundary_test() ->
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 49, 54, 48, 51,
55, 52, 53, 52, 51, 53, 49>>,
{maybe, 30} = find_boundary(P, B0),
{'maybe', 30} = find_boundary(P, B0),
not_found = find_boundary(B, <<"\r\n--XJOPKE">>),
ok.

Expand Down
23 changes: 13 additions & 10 deletions src/mochiweb_request.erl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
-export([accepted_content_types/2,
accepts_content_type/2]).

-export([is_closed/1]).

-define(SAVE_QS, mochiweb_request_qs).

-define(SAVE_PATH, mochiweb_request_path).
Expand Down Expand Up @@ -710,7 +712,7 @@ parse_post({?MODULE,

%% @spec stream_chunked_body(integer(), fun(), term(), request()) -> term()
%% @doc The function is called for each chunk.
%% Used internally by read_chunked_body.
%% Used internally by stream_body.
stream_chunked_body(MaxChunkSize, Fun, FunState,
{?MODULE,
[_Socket, _Opts, _Method, _RawPath, _Version,
Expand Down Expand Up @@ -769,7 +771,7 @@ read_chunk_length({?MODULE,
[{packet,
raw}])),
Splitter = fun (C) ->
C =/= $\r andalso C =/= $\n andalso C =/= $\n
C =/= $\r andalso C =/= $\n andalso C =/= $\s
end,
{Hex, _Rest} = lists:splitwith(Splitter,
binary_to_list(Header)),
Expand Down Expand Up @@ -1145,11 +1147,12 @@ accept_header({?MODULE,
Value -> Value
end.

%%
%% Tests
%%
-ifdef(TEST).

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

-endif.
%% @spec is_closed(request()) -> true | false | undefined
%% @doc Check if a request connection is closing or already closed. This may be
%% useful when processing long running request callbacks, when the client
%% disconnects after a short timeout. This function works on Linux, NetBSD,
%% OpenBSD, FreeBSD and MacOS. On other operating systems, like Windows for
%% instance, it will return undefined.
is_closed({?MODULE,
[Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
mochiweb_socket:is_closed(Socket).
Loading

0 comments on commit e83530d

Please sign in to comment.