Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
- Lowercase method atoms
- Use binaries both for header names and values
- Introduce `raw_headers` which preserve headers case and order. [erlang/otp#2466](erlang/otp#2466) allows to keep headers case
- Some documentation updates
- Update deps
- Update CI to run tests inside docker container
  • Loading branch information
tank-bohr committed Apr 3, 2021
1 parent a205a44 commit f885ff5
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 92 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/erlang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ on:
jobs:

tests:
name: OTP ${{ matrix.otp }}

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

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

strategy:
matrix:
otp: [20.3, 21.3, 22.2]
otp: ['20.3', '21.3', '22.3', '23.3', '24.0-rc2']

steps:
- uses: actions/checkout@v2

- uses: gleam-lang/[email protected]
with:
otp-version: ${{ matrix.otp }}
- uses: actions/[email protected]

- name: Run tests
run: rebar3 do eunit, ct, dialyzer
Expand Down
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

# Bookish spork #

Copyright (c) 2018-2020 Alexey Nikitin
Copyright (c) 2018-2021 Alexey Nikitin

__Version:__ 0.3.6
__Version:__ 0.4.0

__Authors:__ Alexey Nikitin ([`[email protected]`](mailto:[email protected])) (_web site:_ [`https://twitter.com/tank_bohr`](https://twitter.com/tank_bohr)).

Expand Down Expand Up @@ -52,7 +52,7 @@ First step: add to your rebar config
{profiles, [
{test, [
{deps, [
{bookish_spork, "0.3.6"}
{bookish_spork, "0.4.0"}
]}
]}
]}.
Expand Down Expand Up @@ -111,13 +111,15 @@ It returns you an opaque structure of the request. You can inspect it with

#### <a name="Bypass_comparision">Bypass comparision</a> ####

An elixir library [bypass](https://github.com/PSPDFKit-labs/bypass) does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test
An elixir library [bypass](https://github.com/PSPDFKit-labs/bypass) does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test. It's a beautiful library with great API, documentation, and very concise source code. If you are an elixir developer, most likely, it will be a good fit for you.

But bookish_spork has some advantages:
But nevertheless bookish_spork has some advantages:

* Bypass depends on `cowboy` and `plug`. Bookish spork has zero dependencies
* Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library
* Bookish spork much simpler (I believe)
* Bypass depends on `cowboy` and `plug`. Bookish spork has zero dependencies.
* Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library.
* <strike>Bookish spork much simpler (I believe)</strike>
(not any more).
* Bookish spork allows you to inspect the request very deeply and accurate. For example take a look at [`bookish_spork_request:raw_headers/1`](http://github.com/tank-bohr/bookish_spork/blob/master/doc/bookish_spork_request.md#raw_headers-1) and [`bookish_spork_request:ssl_info/1`](http://github.com/tank-bohr/bookish_spork/blob/master/doc/bookish_spork_request.md#ssl_info-1) and [`bookish_spork_request:tls_ext/1`](http://github.com/tank-bohr/bookish_spork/blob/master/doc/bookish_spork_request.md#tls_ext-1). It can be useful for HTTP clients testing.


#### <a name="Elli_comparision">Elli comparision</a> ####
Expand Down Expand Up @@ -227,9 +229,9 @@ defmodule ChuckNorrisApiTest do
use ExUnit.Case
doctest ChuckNorrisApi

setup_all do
{:ok, _} = :bookish_spork.start_server
{:ok, %{}}
setup do
{:ok, _} = :bookish_spork.start_server()
on_exit(fn -> :bookish_spork.stop_server() end)
end

test "retrieves a random joke" do
Expand All @@ -238,8 +240,8 @@ defmodule ChuckNorrisApiTest do
}"])
assert ChuckNorrisApi.random == "Chuck norris tried to crank that soulja boy but it wouldn't crank up"

{:ok, request} = :bookish_spork.capture_request
assert request.uri == '/jokes/random'
{:ok, request} = :bookish_spork.capture_request()
assert request.uri === "/jokes/random"
end
end

Expand Down
28 changes: 15 additions & 13 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

# Bookish spork #

Copyright (c) 2018-2020 Alexey Nikitin
Copyright (c) 2018-2021 Alexey Nikitin

__Version:__ 0.3.6
__Version:__ 0.4.0

__Authors:__ Alexey Nikitin ([`[email protected]`](mailto:[email protected])) (_web site:_ [`https://twitter.com/tank_bohr`](https://twitter.com/tank_bohr)).

Expand Down Expand Up @@ -52,7 +52,7 @@ First step: add to your rebar config
{profiles, [
{test, [
{deps, [
{bookish_spork, "0.3.6"}
{bookish_spork, "0.4.0"}
]}
]}
]}.
Expand Down Expand Up @@ -111,13 +111,15 @@ It returns you an opaque structure of the request. You can inspect it with

#### <a name="Bypass_comparision">Bypass comparision</a> ####

An elixir library [bypass](https://github.com/PSPDFKit-labs/bypass) does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test
An elixir library [bypass](https://github.com/PSPDFKit-labs/bypass) does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test. It's a beautiful library with great API, documentation, and very concise source code. If you are an elixir developer, most likely, it will be a good fit for you.

But bookish_spork has some advantages:
But nevertheless bookish_spork has some advantages:

* Bypass depends on `cowboy` and `plug`. Bookish spork has zero dependencies
* Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library
* Bookish spork much simpler (I believe)
* Bypass depends on `cowboy` and `plug`. Bookish spork has zero dependencies.
* Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library.
* <strike>Bookish spork much simpler (I believe)</strike>
(not any more).
* Bookish spork allows you to inspect the request very deeply and accurate. For example take a look at [`bookish_spork_request:raw_headers/1`](bookish_spork_request.md#raw_headers-1) and [`bookish_spork_request:ssl_info/1`](bookish_spork_request.md#ssl_info-1) and [`bookish_spork_request:tls_ext/1`](bookish_spork_request.md#tls_ext-1). It can be useful for HTTP clients testing.


#### <a name="Elli_comparision">Elli comparision</a> ####
Expand Down Expand Up @@ -227,9 +229,9 @@ defmodule ChuckNorrisApiTest do
use ExUnit.Case
doctest ChuckNorrisApi

setup_all do
{:ok, _} = :bookish_spork.start_server
{:ok, %{}}
setup do
{:ok, _} = :bookish_spork.start_server()
on_exit(fn -> :bookish_spork.stop_server() end)
end

test "retrieves a random joke" do
Expand All @@ -238,8 +240,8 @@ defmodule ChuckNorrisApiTest do
}"])
assert ChuckNorrisApi.random == "Chuck norris tried to crank that soulja boy but it wouldn't crank up"

{:ok, request} = :bookish_spork.capture_request
assert request.uri == '/jokes/random'
{:ok, request} = :bookish_spork.capture_request()
assert request.uri === "/jokes/random"
end
end

Expand Down
21 changes: 16 additions & 5 deletions doc/bookish_spork_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ __abstract datatype__: `t()`
## Function Index ##


<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#body-1">body/1</a></td><td>request body.</td></tr><tr><td valign="top"><a href="#content_length-1">content_length/1</a></td><td>Content-Length header value as intger.</td></tr><tr><td valign="top"><a href="#from_transport-1">from_transport/1</a></td><td></td></tr><tr><td valign="top"><a href="#header-2">header/2</a></td><td>Returns a particular header from request.</td></tr><tr><td valign="top"><a href="#headers-1">headers/1</a></td><td>http headers map.</td></tr><tr><td valign="top"><a href="#is_keepalive-1">is_keepalive/1</a></td><td>tells you if the request is keepalive or not <a href="https://tools.ietf.org.md/rfc6223" target="_top"><tt>https://tools.ietf.org/html/rfc6223</tt></a></td></tr><tr><td valign="top"><a href="#method-1">method/1</a></td><td>http verb: 'GET', 'POST','PUT', 'DELETE', 'OPTIONS', ...</td></tr><tr><td valign="top"><a href="#transport-1">transport/1</a></td><td></td></tr><tr><td valign="top"><a href="#uri-1">uri/1</a></td><td>path with query string.</td></tr><tr><td valign="top"><a href="#version-1">version/1</a></td><td>http protocol version tuple.</td></tr></table>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#body-1">body/1</a></td><td>request body.</td></tr><tr><td valign="top"><a href="#content_length-1">content_length/1</a></td><td>Content-Length header value as intger.</td></tr><tr><td valign="top"><a href="#from_transport-1">from_transport/1</a></td><td></td></tr><tr><td valign="top"><a href="#header-2">header/2</a></td><td>Returns a particular header from request.</td></tr><tr><td valign="top"><a href="#headers-1">headers/1</a></td><td>HTTP headers map.</td></tr><tr><td valign="top"><a href="#is_keepalive-1">is_keepalive/1</a></td><td>tells you if the request is keepalive or not <a href="https://tools.ietf.org.md/rfc6223" target="_top"><tt>https://tools.ietf.org/html/rfc6223</tt></a></td></tr><tr><td valign="top"><a href="#method-1">method/1</a></td><td>http verb in lower case: get, post, put, delete, options, ...</td></tr><tr><td valign="top"><a href="#raw_headers-1">raw_headers/1</a></td><td>HTTP raw headers.</td></tr><tr><td valign="top"><a href="#transport-1">transport/1</a></td><td></td></tr><tr><td valign="top"><a href="#uri-1">uri/1</a></td><td>path with query string.</td></tr><tr><td valign="top"><a href="#version-1">version/1</a></td><td>http protocol version tuple.</td></tr></table>


<a name="functions"></a>
Expand Down Expand Up @@ -65,11 +65,11 @@ from_transport(Transport::<a href="bookish_spork_transport.md#type-t">bookish_sp
### header/2 ###

<pre><code>
header(Request::<a href="#type-t">t()</a>, HeaderName::string()) -&gt; string() | nil
header(Request::<a href="#type-t">t()</a>, HeaderName::string() | binary()) -&gt; binary() | nil
</code></pre>
<br />

Returns a particular header from request. Header name is lowerced
Returns a particular header from request.

<a name="headers-1"></a>

Expand All @@ -80,7 +80,7 @@ headers(Request::<a href="#type-t">t()</a>) -&gt; map()
</code></pre>
<br />

http headers map. Header names are normalized and lowercased
HTTP headers map. Header names are normalized and lowercased

<a name="is_keepalive-1"></a>

Expand All @@ -102,7 +102,18 @@ method(Request::<a href="#type-t">t()</a>) -&gt; atom()
</code></pre>
<br />

http verb: 'GET', 'POST','PUT', 'DELETE', 'OPTIONS', ...
http verb in lower case: get, post, put, delete, options, ...

<a name="raw_headers-1"></a>

### raw_headers/1 ###

<pre><code>
raw_headers(Request::<a href="#type-t">t()</a>) -&gt; <a href="proplists.md#type-proplist">proplists:proplist()</a>
</code></pre>
<br />

HTTP raw headers. Headers order and case are preserved

<a name="transport-1"></a>

Expand Down
22 changes: 12 additions & 10 deletions doc/overview.edoc
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,19 @@ It returns you an opaque structure of the request. You can inspect it with

=== Bypass comparision ===

An elixir library <a target="_blank" href="https://github.com/PSPDFKit-labs/bypass">bypass</a> does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test
An elixir library <a target="_blank" href="https://github.com/PSPDFKit-labs/bypass">bypass</a> does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test. It's a beautiful library with great API, documentation, and very concise source code. If you are an elixir developer, most likely, it will be a good fit for you.

But bookish_spork has some advantages:
But nevertheless bookish_spork has some advantages:

<ul>

<li>Bypass depends on `cowboy' and `plug'. Bookish spork has zero dependencies</li>
<li>Bypass depends on `cowboy' and `plug'. Bookish spork has zero dependencies.</li>

<li>Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library</li>
<li>Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library.</li>

<li>Bookish spork much simpler (I believe)</li>
<li><strike>Bookish spork much simpler (I believe)</strike> (not any more).</li>

<li>Bookish spork allows you to inspect the request very deeply and accurate. For example take a look at {@link bookish_spork_request:raw_headers/1} and {@link bookish_spork_request:ssl_info/1} and {@link bookish_spork_request:tls_ext/1}. It can be useful for HTTP clients testing.</li>

</ul>

Expand Down Expand Up @@ -221,9 +223,9 @@ defmodule ChuckNorrisApiTest do
use ExUnit.Case
doctest ChuckNorrisApi

setup_all do
{:ok, _} = :bookish_spork.start_server
{:ok, %{}}
setup do
{:ok, _} = :bookish_spork.start_server()
on_exit(fn -> :bookish_spork.stop_server() end)
end

test "retrieves a random joke" do
Expand All @@ -232,8 +234,8 @@ defmodule ChuckNorrisApiTest do
}"])
assert ChuckNorrisApi.random == "Chuck norris tried to crank that soulja boy but it wouldn't crank up"

{:ok, request} = :bookish_spork.capture_request
assert request.uri == '/jokes/random'
{:ok, request} = :bookish_spork.capture_request()
assert request.uri === "/jokes/random"
end
end
</pre>
Expand Down
6 changes: 6 additions & 0 deletions elvis.config
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
{elvis_style, function_naming_convention, #{
ignore => [bookish_spork_request],
regex => "^([a-z][a-z0-9]*_?)*$"
}},
{elvis_style, state_record_and_type, #{
ignore => [
bookish_spork_acceptor,
bookish_spork_blocking_queue
]
}}
],
ruleset => erl_files
Expand Down
4 changes: 2 additions & 2 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{profiles, [
{test, [
{deps, [
{gun, "1.3.1"}
{gun, "1.3.3"}
]},

{plugins, [
Expand All @@ -33,7 +33,7 @@
]},
{elvis, [
{plugins, [
{rebar3_lint, "0.1.11"}
{rebar3_lint, "0.4.0"}
]}
]}
]}.
Expand Down
8 changes: 7 additions & 1 deletion src/bookish_spork_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ receive_request(#state{transport = Transport, request = RequestIn} = State) ->
{ok, {http_request, Method, {abs_path, Uri}, Version}} ->
RequestOut = bookish_spork_request:request_line(RequestIn, Method, Uri, Version),
?FUNCTION_NAME(State#state{request = RequestOut});
{ok, {http_header, _, Header, _, Value}} ->
{ok, {http_header, _, NormalizedHeader, PreserveCaseHeader, Value}} ->
Header = choose_header(NormalizedHeader, PreserveCaseHeader),
RequestOut = bookish_spork_request:add_header(RequestIn, Header, Value),
?FUNCTION_NAME(State#state{request = RequestOut});
{ok, http_eoh} ->
Expand Down Expand Up @@ -136,6 +137,11 @@ complete_connection(State = #state{transport = Transport, request = Request}) ->
{halt, normal}
end.

choose_header(NormalizedHeader, undefined) ->
NormalizedHeader;
choose_header(_NormalizedHeader, PreserveCaseHeader) ->
PreserveCaseHeader.

reduce_while(State, []) ->
{noreply, State};
reduce_while(State, [Fun|Rest]) ->
Expand Down
Loading

0 comments on commit f885ff5

Please sign in to comment.