diff --git a/.gitignore b/.gitignore index 60de56f..f30562d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -doc/README.md +doc/ erl_crash.dump fprofx.* rebar3.crashdump diff --git a/README.md b/README.md index 8c5e2cd..911a857 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,15 @@ High-Performance Erlang HTTP 1.1 Client ![Build Status](https://github.com/lpgauth/buoy/workflows/Erlang%20CI/badge.svg) -## Disclaimer: +## Disclaimer This HTTP client has been designed for HTTP 1.1 with keep-alive. For performance reasons, it only implements a subset of RFC2616. -### Unsupported Features: +## Unsupported Features - Doesn't accept an arbitrary number of new lines in headers - Doesn't accept random capitalization of content-length header - Doesn't protect against malicious servers -## API -Function Index - ## Examples ```erlang @@ -56,7 +53,7 @@ ok {<<"Content-Length">>,<<"1270">>}]} ``` -### Pool Options +## Pool Options diff --git a/doc/buoy.md b/doc/buoy.md deleted file mode 100644 index bea2ff4..0000000 --- a/doc/buoy.md +++ /dev/null @@ -1,352 +0,0 @@ - - -# Module buoy # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### body() ### - - -

-body() = undefined | iodata()
-
- - - - -### buoy_opts() ### - - -

-buoy_opts() = #{headers => headers(), body => body(), pid => pid(), timeout => non_neg_integer()}
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### error() ### - - -

-error() = {error, term()}
-
- - - - -### headers() ### - - -

-headers() = [{iodata(), iodata()}]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### method() ### - - -

-method() = get | post | put | {custom, binary()}
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
async_custom/3
async_get/2
async_post/2
async_put/2
async_request/3
custom/3
get/2
post/2
put/2
receive_response/1
request/3
- - - - -## Function Details ## - - - -### async_custom/3 ### - -

-async_custom(Verb::binary(), Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, shackle:request_id()} | error()
-
-
- - - -### async_get/2 ### - -

-async_get(Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, shackle:request_id()} | error()
-
-
- - - -### async_post/2 ### - -

-async_post(Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, shackle:request_id()} | error()
-
-
- - - -### async_put/2 ### - -

-async_put(Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, shackle:request_id()} | error()
-
-
- - - -### async_request/3 ### - -

-async_request(Method::method(), Buoy_url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, shackle:request_id()} | error()
-
-
- - - -### custom/3 ### - -

-custom(Verb::binary(), Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, buoy_resp()} | error()
-
-
- - - -### get/2 ### - -

-get(Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, buoy_resp()} | error()
-
-
- - - -### post/2 ### - -

-post(Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, buoy_resp()} | error()
-
-
- - - -### put/2 ### - -

-put(Url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, buoy_resp()} | error()
-
-
- - - -### receive_response/1 ### - -

-receive_response(RequestId::request_id()) -> {ok, term()} | error()
-
-
- - - -### request/3 ### - -

-request(Method::method(), Buoy_url::buoy_url(), BuoyOpts::buoy_opts()) -> {ok, buoy_resp()} | error()
-
-
- diff --git a/doc/buoy_app.md b/doc/buoy_app.md deleted file mode 100644 index f4b1216..0000000 --- a/doc/buoy_app.md +++ /dev/null @@ -1,241 +0,0 @@ - - -# Module buoy_app # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - -__Behaviours:__ [`application`](application.md). - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
start/0
start/2
stop/0
stop/1
- - - - -## Function Details ## - - - -### start/0 ### - -

-start() -> {ok, [atom()]}
-
-
- - - -### start/2 ### - -

-start(StartType::application:start_type(), StartArgs::term()) -> {ok, pid()}
-
-
- - - -### stop/0 ### - -

-stop() -> ok | {error, {not_started, buoy}}
-
-
- - - -### stop/1 ### - -

-stop(State::term()) -> ok
-
-
- diff --git a/doc/buoy_client.md b/doc/buoy_client.md deleted file mode 100644 index c941b9c..0000000 --- a/doc/buoy_client.md +++ /dev/null @@ -1,258 +0,0 @@ - - -# Module buoy_client # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### state() ### - - -

-state() = #state{bin_patterns = tuple(), buffer = binary(), requests_in = non_neg_integer(), requests_out = non_neg_integer(), response = undefined | buoy_resp()}
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
handle_data/2
handle_request/2
init/1
setup/2
terminate/1
- - - - -## Function Details ## - - - -### handle_data/2 ### - -

-handle_data(Data::binary(), State::state()) -> {ok, [{pos_integer(), term()}], state()} | {error, atom(), state()}
-
-
- - - -### handle_request/2 ### - -

-handle_request(X1::term(), State::state()) -> {ok, non_neg_integer(), iodata(), state()}
-
-
- - - -### init/1 ### - -

-init(Opts::undefined) -> {ok, state()}
-
-
- - - -### setup/2 ### - -

-setup(Socket::inet:socket(), State::state()) -> {ok, state()}
-
-
- - - -### terminate/1 ### - -

-terminate(State::state()) -> ok
-
-
- diff --git a/doc/buoy_pool.md b/doc/buoy_pool.md deleted file mode 100644 index b8cb550..0000000 --- a/doc/buoy_pool.md +++ /dev/null @@ -1,268 +0,0 @@ - - -# Module buoy_pool # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### option() ### - - -

-option() = {backlog_size, pos_integer()} | {pool_size, pos_integer()} | {pool_strategy, random | round_robin} | {reconnect, boolean()} | {reconnect_time_max, pos_integer() | infinity} | {reconnect_time_min, pos_integer()}
-
- - - - -### options() ### - - -

-options() = [option()]
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
init/0
lookup/3
start/1
start/2
stop/1
- - - - -## Function Details ## - - - -### init/0 ### - -

-init() -> ok
-
-
- - - -### lookup/3 ### - -

-lookup(Protocol::protocol_http(), Hostname::hostname(), Port::inet:port_number()) -> {ok, atom()} | {error, pool_not_started}
-
-
- - - -### start/1 ### - -

-start(Url::buoy_url()) -> ok | {error, pool_already_started | shackle_not_started}
-
-
- - - -### start/2 ### - -

-start(Buoy_url::buoy_url(), Options::options()) -> ok | {error, pool_already_started | shackle_not_started}
-
-
- - - -### stop/1 ### - -

-stop(Buoy_url::buoy_url()) -> ok | {error, shackle_not_started | pool_not_started}
-
-
- diff --git a/doc/buoy_protocol.md b/doc/buoy_protocol.md deleted file mode 100644 index f05fa9a..0000000 --- a/doc/buoy_protocol.md +++ /dev/null @@ -1,298 +0,0 @@ - - -# Module buoy_protocol # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### bin_patterns() ### - - -

-bin_patterns() = #bin_patterns{rn = binary:cp(), rnrn = binary:cp()}
-
- - - - -### body() ### - - -

-body() = undefined | iodata()
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### error() ### - - -

-error() = {error, term()}
-
- - - - -### headers() ### - - -

-headers() = [{iodata(), iodata()}]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### method() ### - - -

-method() = get | post | put | {custom, binary()}
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
bin_patterns/0
headers/1
request/5
response/1
response/3
- - - - -## Function Details ## - - - -### bin_patterns/0 ### - -

-bin_patterns() -> bin_patterns()
-
-
- - - -### headers/1 ### - -

-headers(Buoy_resp::buoy_resp()) -> {ok, headers()} | {error, invalid_headers}
-
-
- - - -### request/5 ### - -

-request(Method::method(), Path::path(), Headers::headers(), Host::host(), Body::body()) -> iolist()
-
-
- - - -### response/1 ### - -

-response(Data::binary()) -> {ok, buoy_resp(), binary()} | error()
-
-
- - - -### response/3 ### - -

-response(Data::binary(), Buoy_resp::undefined | buoy_resp(), BinPatterns::bin_patterns()) -> {ok, buoy_resp(), binary()} | error()
-
-
- diff --git a/doc/buoy_sup.md b/doc/buoy_sup.md deleted file mode 100644 index 96b894c..0000000 --- a/doc/buoy_sup.md +++ /dev/null @@ -1,223 +0,0 @@ - - -# Module buoy_sup # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - -__Behaviours:__ [`supervisor`](supervisor.md). - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
init/1
start_link/0
- - - - -## Function Details ## - - - -### init/1 ### - -

-init(X1::[]) -> {ok, {{one_for_one, 5, 10}, []}}
-
-
- - - -### start_link/0 ### - -

-start_link() -> {ok, pid()}
-
-
- diff --git a/doc/buoy_utils.md b/doc/buoy_utils.md deleted file mode 100644 index d08c315..0000000 --- a/doc/buoy_utils.md +++ /dev/null @@ -1,212 +0,0 @@ - - -# Module buoy_utils # -* [Data Types](#types) -* [Function Index](#index) -* [Function Details](#functions) - - - -## Data Types ## - - - - -### backlog_size() ### - - -

-backlog_size() = pos_integer() | infinity
-
- - - - -### buoy_resp() ### - - -

-buoy_resp() = #buoy_resp{state = body | done, body = undefined | binary(), content_length = undefined | non_neg_integer() | chunked, headers = undefined | [binary()], reason = undefined | binary(), status_code = undefined | 100..505}
-
- - - - -### buoy_url() ### - - -

-buoy_url() = #buoy_url{host = host(), hostname = hostname(), path = path(), port = inet:port_number(), protocol = protocol_http()}
-
- - - - -### client_option() ### - - -

-client_option() = {init_options, init_options()} | {ip, inet:ip_address() | inet:hostname()} | {port, inet:port_number()} | {protocol, protocol()} | {reconnect, boolean()} | {reconnect_time_max, time() | infinity} | {reconnect_time_min, time()} | {socket_options, [gen_tcp:connect_option() | gen_udp:option()]}
-
- - - - -### client_options() ### - - -

-client_options() = [client_option()]
-
- - - - -### host() ### - - -

-host() = binary()
-
- - - - -### hostname() ### - - -

-hostname() = binary()
-
- - - - -### init_options() ### - - -

-init_options() = term()
-
- - - - -### path() ### - - -

-path() = binary()
-
- - - - -### pool_option() ### - - -

-pool_option() = {backlog_size, backlog_size()} | {pool_size, pool_size()} | {pool_strategy, pool_strategy()}
-
- - - - -### pool_options() ### - - -

-pool_options() = [pool_option()]
-
- - - - -### pool_size() ### - - -

-pool_size() = pos_integer()
-
- - - - -### pool_strategy() ### - - -

-pool_strategy() = random | round_robin
-
- - - - -### protocol() ### - - -

-protocol() = shackle_ssl | shackle_tcp | shackle_udp
-
- - - - -### protocol_http() ### - - -

-protocol_http() = http | https
-
- - - - -### request_id() ### - - -

-request_id() = {server_name(), reference()}
-
- - - - -### server_name() ### - - -

-server_name() = atom()
-
- - - - -### time() ### - - -

-time() = pos_integer()
-
- - - -## Function Index ## - - -
parse_url/1
- - - - -## Function Details ## - - - -### parse_url/1 ### - -

-parse_url(X1::binary()) -> buoy_url() | {error, invalid_url}
-
-
- diff --git a/doc/edoc-info b/doc/edoc-info deleted file mode 100644 index baff42f..0000000 --- a/doc/edoc-info +++ /dev/null @@ -1,4 +0,0 @@ -%% encoding: UTF-8 -{application,buoy}. -{modules,[buoy,buoy_app,buoy_client,buoy_pool,buoy_protocol,buoy_sup, - buoy_utils]}. diff --git a/include/buoy.hrl b/include/buoy.hrl index 8d2b041..e87e523 100644 --- a/include/buoy.hrl +++ b/include/buoy.hrl @@ -9,38 +9,16 @@ }). -record(buoy_url, { - host :: host(), - hostname :: hostname(), - path :: path(), + host :: buoy:host(), + hostname :: buoy:hostname(), + path :: buoy:path(), port :: inet:port_number(), - protocol :: protocol_http() + protocol :: buoy_pool:protocol() }). -%% types --type body() :: undefined | iodata(). --type buoy_opts() :: #{headers => headers(), - body => body(), - pid => pid(), - timeout => non_neg_integer()}. --type buoy_resp() :: #buoy_resp {}. --type buoy_url() :: #buoy_url {}. --type error() :: {error, term()}. --type headers() :: [{iodata(), iodata()}]. --type host() :: binary(). --type hostname() :: binary(). --type method() :: get | head | post | put | {custom, binary()}. --type option() :: {backlog_size, pos_integer()} | - {pool_size, pos_integer()} | - {pool_strategy, random | round_robin} | - {reconnect, boolean()} | - {reconnect_time_max, pos_integer() | infinity} | - {reconnect_time_min, pos_integer()} | - {socket_options, [gen_tcp:connect_option() | ssl:tls_client_option()]}. --type options() :: [option()]. --type path() :: binary(). --type protocol_http() :: http | https. - --export_type([ - buoy_resp/0, - buoy_url/0 -]). +-record(buoy_req, { + method :: buoy:method(), + url :: buoy:url(), + headers :: buoy:headers(), + body :: buoy:body() +}). diff --git a/include/buoy_internal.hrl b/include/buoy_internal.hrl index a45da3f..e8a0f4b 100644 --- a/include/buoy_internal.hrl +++ b/include/buoy_internal.hrl @@ -1,6 +1,3 @@ --include("buoy.hrl"). --include_lib("shackle/include/shackle.hrl"). - %% macros -define(APP, buoy). -define(CLIENT, buoy_client). diff --git a/rebar.config b/rebar.config index a70b2eb..c17bae2 100644 --- a/rebar.config +++ b/rebar.config @@ -2,20 +2,23 @@ {foil, ".*", {git, "https://github.com/lpgauth/foil.git", {tag, "0.1.2"}}}, {shackle, ".*", - {git, "https://github.com/lpgauth/shackle.git", {tag, "0.6.19"}}} + {git, "https://github.com/rkallos/shackle.git", {ref, "3da046743a9ba83ee0e54dbdd2e158b937244eeb"}}} ]}. +{plugins, [rebar3_hex, rebar3_ex_doc]}. + {dialyzer, [{plt_extra_apps, [public_key]}]}. +{hex, [ + {doc, #{provider => ex_doc}} +]}. -{edoc_opts, [ - {app_default, "http://www.erlang.org/doc/man"}, - {doclet, edown_doclet}, - {image, ""}, - {includes, ["include"]}, - {preprocess, true}, - {stylesheet, ""}, - {title, "anchor"} +{ex_doc, [ + {api_reference, false}, + {extras, ["README.md"]}, + {main, "readme"}, + {prefix_ref_vsn_with_v, false}, + {source_url, "https://github.com/lpgauth/buoy"} ]}. {erl_opts, [ @@ -36,12 +39,6 @@ warn_unused_vars ]} ]}, - {edoc, [ - {deps, [ - {edown, - {git, "https://github.com/uwiger/edown.git", {tag, "0.7"}}} - ]} - ]}, {test, [ {deps, [ {cowboy, diff --git a/rebar.lock b/rebar.lock index d09ed63..c9ebd50 100644 --- a/rebar.lock +++ b/rebar.lock @@ -9,12 +9,15 @@ 1}, {<<"metal">>,{pkg,<<"metal">>,<<"0.1.1">>},1}, {<<"shackle">>, - {git,"https://github.com/lpgauth/shackle.git", - {ref,"a4f7d82d10115cf0d676582b638a56260be685d5"}}, - 0}]}. + {git,"https://github.com/rkallos/shackle.git", + {ref,"3da046743a9ba83ee0e54dbdd2e158b937244eeb"}}, + 0}, + {<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.2.1">>},1}]}. [ {pkg_hash,[ - {<<"metal">>, <<"5D3D1322DA7BCD34B94FED5486F577973685298883954F7A3E517EF5EF6953F5">>}]}, + {<<"metal">>, <<"5D3D1322DA7BCD34B94FED5486F577973685298883954F7A3E517EF5EF6953F5">>}, + {<<"telemetry">>, <<"68FDFE8D8F05A8428483A97D7AAB2F268AAFF24B49E0F599FAA091F1D4E7F61C">>}]}, {pkg_hash_ext,[ - {<<"metal">>, <<"88B82B634998A1A768DEDCD372C2F7E657B19445325C0AF5CCBAC62C77210F1D">>}]} + {<<"metal">>, <<"88B82B634998A1A768DEDCD372C2F7E657B19445325C0AF5CCBAC62C77210F1D">>}, + {<<"telemetry">>, <<"DAD9CE9D8EFFC621708F99EAC538EF1CBE05D6A874DD741DE2E689C47FEAFED5">>}]} ]. diff --git a/src/buoy.erl b/src/buoy.erl index 1c1d842..aa31395 100644 --- a/src/buoy.erl +++ b/src/buoy.erl @@ -1,4 +1,5 @@ -module(buoy). +-include("buoy.hrl"). -include("buoy_internal.hrl"). -compile(inline). @@ -20,53 +21,86 @@ request/3 ]). +%% types +-type body() :: undefined | iodata(). +-type error() :: {error, term()}. +-type headers() :: [{iodata(), iodata()}]. +-type host() :: binary(). +-type hostname() :: binary(). +-type method() :: get | head | post | put | {custom, binary()}. +-type opts() :: #{headers => headers(), + body => body(), + pid => pid(), + timeout => non_neg_integer()}. +-type path() :: binary(). +-type req() :: #buoy_req {}. +-type resp() :: #buoy_resp {}. +-type url() :: #buoy_url {}. + +-export_type([ + body/0, + error/0, + headers/0, + host/0, + hostname/0, + method/0, + opts/0, + path/0, + req/0, + resp/0, + url/0 +]). + %% public --spec async_custom(binary(), buoy_url(), buoy_opts()) -> +-spec async_custom(binary(), url(), opts()) -> {ok, shackle:request_id()} | error(). async_custom(Verb, Url, BuoyOpts) -> async_request({custom, Verb}, Url, BuoyOpts). --spec async_get(buoy_url(), buoy_opts()) -> +-spec async_get(url(), opts()) -> {ok, shackle:request_id()} | error(). async_get(Url, BuoyOpts) -> async_request(get, Url, BuoyOpts). --spec async_head(buoy_url(), buoy_opts()) -> +-spec async_head(url(), opts()) -> {ok, shackle:request_id()} | error(). async_head(Url, BuoyOpts) -> async_request(head, Url, BuoyOpts). --spec async_post(buoy_url(), buoy_opts()) -> +-spec async_post(url(), opts()) -> {ok, shackle:request_id()} | error(). async_post(Url, BuoyOpts) -> async_request(post, Url, BuoyOpts). --spec async_put(buoy_url(), buoy_opts()) -> +-spec async_put(url(), opts()) -> {ok, shackle:request_id()} | error(). async_put(Url, BuoyOpts) -> async_request(put, Url, BuoyOpts). --spec async_request(method(), buoy_url(), buoy_opts()) -> +-spec async_request(method(), url(), opts()) -> {ok, shackle:request_id()} | error(). async_request(Method, #buoy_url { protocol = Protocol, - host = Host, hostname = Hostname, - port = Port, - path = Path - }, BuoyOpts) -> + port = Port + } = Url, BuoyOpts) -> case buoy_pool:lookup(Protocol, Hostname, Port) of {ok, PoolName} -> Headers = buoy_opts(headers, BuoyOpts), Body = buoy_opts(body, BuoyOpts), - Request = {request, Method, Path, Headers, Host, Body}, + Request = #buoy_req{ + method = Method, + url = Url, + headers = Headers, + body = Body + }, Pid = buoy_opts(pid, BuoyOpts), Timeout = buoy_opts(timeout, BuoyOpts), shackle:cast(PoolName, Request, Pid, Timeout); @@ -74,58 +108,61 @@ async_request(Method, #buoy_url { E end. --spec custom(binary(), buoy_url(), buoy_opts()) -> - {ok, buoy_resp()} | error(). +-spec custom(binary(), url(), opts()) -> + {ok, resp()} | error(). custom(Verb, Url, BuoyOpts) -> request({custom, Verb}, Url, BuoyOpts). --spec get(buoy_url(), buoy_opts()) -> - {ok, buoy_resp()} | error(). +-spec get(url(), opts()) -> + {ok, resp()} | error(). get(Url, BuoyOpts) -> request(get, Url, BuoyOpts). --spec head(buoy_url(), buoy_opts()) -> - {ok, buoy_resp()} | error(). +-spec head(url(), opts()) -> + {ok, resp()} | error(). head(Url, BuoyOpts) -> request(head, Url, BuoyOpts). --spec post(buoy_url(), buoy_opts()) -> - {ok, buoy_resp()} | error(). +-spec post(url(), opts()) -> + {ok, resp()} | error(). post(Url, BuoyOpts) -> request(post, Url, BuoyOpts). --spec put(buoy_url(), buoy_opts()) -> - {ok, buoy_resp()} | error(). +-spec put(url(), opts()) -> + {ok, resp()} | error(). put(Url, BuoyOpts) -> request(put, Url, BuoyOpts). --spec receive_response(request_id()) -> +-spec receive_response(shackle:request_id()) -> {ok, term()} | error(). receive_response(RequestId) -> shackle:receive_response(RequestId). --spec request(method(), buoy_url(), buoy_opts()) -> - {ok, buoy_resp()} | error(). +-spec request(method(), url(), opts()) -> + {ok, resp()} | error(). request(Method, #buoy_url { protocol = Protocol, - host = Host, hostname = Hostname, - port = Port, - path = Path - }, BuoyOpts) -> + port = Port + } = Url, BuoyOpts) -> case buoy_pool:lookup(Protocol, Hostname, Port) of {ok, PoolName} -> Headers = buoy_opts(headers, BuoyOpts), Body = buoy_opts(body, BuoyOpts), - Request = {request, Method, Path, Headers, Host, Body}, + Request = #buoy_req{ + method = Method, + url = Url, + headers = Headers, + body = Body + }, Timeout = buoy_opts(timeout, BuoyOpts), shackle:call(PoolName, Request, Timeout); {error, _} = E -> diff --git a/src/buoy_client.erl b/src/buoy_client.erl index e77bacf..c044405 100644 --- a/src/buoy_client.erl +++ b/src/buoy_client.erl @@ -1,5 +1,5 @@ -module(buoy_client). --include("buoy_internal.hrl"). +-include("buoy.hrl"). -compile(inline). -compile({inline_size, 512}). @@ -18,7 +18,7 @@ buffer = <<>> :: binary(), queue :: queue:queue(), request_id = 0 :: non_neg_integer(), - response :: undefined | buoy_resp() + response :: undefined | buoy:resp() }). -type state() :: #state {}. @@ -42,15 +42,20 @@ setup(_Socket, State) -> -spec handle_request(term(), state()) -> {ok, non_neg_integer(), iodata(), state()}. -handle_request({request, Method, Path, Headers, Host, Body}, #state { +handle_request(#buoy_req{ + method = Method, + url = #buoy_url{host = Host, path = Path}, + headers = Headers, body = Body + } = Request, + #state { queue = Queue, request_id = RequestId } = State) -> - Request = buoy_protocol:request(Method, Path, Headers, Host, Body), + RequestData = buoy_protocol:request(Method, Path, Headers, Host, Body), - {ok, RequestId, Request, State#state { - queue = queue:in({RequestId, Method}, Queue), + {ok, RequestId, RequestData, State#state { + queue = queue:in({RequestId, Request}, Queue), request_id = RequestId + 1 }}. @@ -87,7 +92,7 @@ terminate(_State) -> responses(<<>>, Queue, Response, _BinPatterns, Responses) -> {ok, Queue, Response, Responses, <<>>}; responses(Data, Queue, Response, BinPatterns, Responses) -> - {value, {_, Method}} = queue:peek(Queue), + {value, {_, #buoy_req{method = Method}}} = queue:peek(Queue), case buoy_protocol:response(Data, Method, Response, BinPatterns) of {ok, #buoy_resp {state = done} = Response2, Rest} -> {{value, {RequestId, _}}, Queue2} = queue:out(Queue), diff --git a/src/buoy_pool.erl b/src/buoy_pool.erl index 709862c..da70b70 100644 --- a/src/buoy_pool.erl +++ b/src/buoy_pool.erl @@ -1,4 +1,5 @@ -module(buoy_pool). +-include("buoy.hrl"). -include("buoy_internal.hrl"). -export([ @@ -10,6 +11,22 @@ terminate/0 ]). +%% types +-type option() :: {backlog_size, pos_integer()} | + {pool_size, pos_integer()} | + {pool_strategy, random | round_robin} | + {reconnect, boolean()} | + {reconnect_time_max, pos_integer() | infinity} | + {reconnect_time_min, pos_integer()} | + {socket_options, [gen_tcp:connect_option() | ssl:tls_client_option()]}. +-type options() :: [option()]. +-type protocol() :: http | https. + +-export_type([ + options/0, + protocol/0 +]). + %% public -spec init() -> ok. @@ -18,7 +35,7 @@ init() -> foil:new(?MODULE), foil:load(?MODULE). --spec lookup(protocol_http(), hostname(), inet:port_number()) -> +-spec lookup(protocol(), buoy:hostname(), inet:port_number()) -> {ok, atom()} | {error, pool_not_started | buoy_not_started}. lookup(Protocol, Hostname, Port) -> @@ -31,13 +48,13 @@ lookup(Protocol, Hostname, Port) -> {error, buoy_not_started} end. --spec start(buoy_url()) -> +-spec start(buoy:url()) -> ok | {error, pool_already_started | buoy_not_started}. start(Url) -> start(Url, ?DEFAULT_POOL_OPTIONS). --spec start(buoy_url(), options()) -> +-spec start(buoy:url(), options()) -> ok | {error, pool_already_started | buoy_not_started}. start(#buoy_url { @@ -61,7 +78,7 @@ start(#buoy_url { {error, buoy_not_started} end. --spec stop(buoy_url()) -> +-spec stop(buoy:url()) -> ok | {error, pool_not_started | buoy_not_started}. stop(#buoy_url { diff --git a/src/buoy_protocol.erl b/src/buoy_protocol.erl index a2806b3..2354bfc 100644 --- a/src/buoy_protocol.erl +++ b/src/buoy_protocol.erl @@ -1,5 +1,5 @@ -module(buoy_protocol). --include("buoy_internal.hrl"). +-include("buoy.hrl"). -compile(inline). -compile({inline_size, 512}). @@ -29,13 +29,13 @@ bin_patterns() -> rnrn = binary:compile_pattern(<<"\r\n\r\n">>) }. --spec headers(buoy_resp()) -> - {ok, headers()} | {error, invalid_headers}. +-spec headers(buoy:resp()) -> + {ok, buoy:headers()} | {error, invalid_headers}. headers(#buoy_resp {headers = Headers}) -> parse_headers(Headers, []). --spec request(method(), path(), headers(), host(), body()) -> +-spec request(buoy:method(), buoy:path(), buoy:headers(), buoy:host(), buoy:body()) -> iolist(). request(Method, Path, Headers, Host, undefined) -> @@ -58,13 +58,13 @@ request(Method, Path, Headers, Host, Body) -> Body]. -spec response(binary()) -> - {ok, buoy_resp(), binary()} | error(). + {ok, buoy:resp(), binary()} | buoy:error(). response(Data) -> response(Data, get, undefined, bin_patterns()). --spec response(binary(), method(), undefined | buoy_resp(), bin_patterns()) -> - {ok, buoy_resp(), binary()} | error(). +-spec response(binary(), buoy:method(), undefined | buoy:resp(), bin_patterns()) -> + {ok, buoy:resp(), binary()} | buoy:error(). response(Data, Method, undefined, BinPatterns) -> case parse_status_line(Data, BinPatterns) of diff --git a/src/buoy_utils.erl b/src/buoy_utils.erl index 0249694..25d6006 100644 --- a/src/buoy_utils.erl +++ b/src/buoy_utils.erl @@ -1,5 +1,5 @@ -module(buoy_utils). --include("buoy_internal.hrl"). +-include("buoy.hrl"). -compile(inline). -compile({inline_size, 512}). @@ -10,7 +10,7 @@ %% public -spec parse_url(binary()) -> - buoy_url() | {error, invalid_url}. + buoy:url() | {error, invalid_url}. parse_url(<<"http://", Rest/binary>>) -> parse_url(http, Rest);