Skip to content

Commit

Permalink
Merge pull request #74 from puzza007/curlopt-interface
Browse files Browse the repository at this point in the history
Support CURLOPT_INTERFACE
  • Loading branch information
puzza007 committed Mar 6, 2018
2 parents 2291a73 + 8c092e1 commit b16b897
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 25 deletions.
43 changes: 22 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,23 @@ katipo:Method(Pool :: atom(), URL :: binary(), ReqOptions :: map()).

#### Request options

| Option | Type | Default | Notes |
|:--------------------|:------------------------------- |:----------------- |:----------------- |
| `headers` | `[{binary(), iodata()}]` | `[]` | |
| `cookiejar` | opaque (returned in response) | `[]` | |
| `body` | `iodata()` | `<<>>` | |
| `connecttimeout_ms` | `pos_integer()` | 30000 | |
| `followlocation` | `boolean()` | `false` | |
| `ssl_verifyhost` | `boolean()` | `true` | |
| `ssl_verifypeer` | `boolean()` | `true` | |
| `capath` | `binary()` | `undefined` | |
| `cacert` | `binary()` | `undefined` | |
| `timeout_ms` | `pos_integer()` | 30000 | |
| `maxredirs` | `non_neg_integer()` | 9 | |
| `proxy` | `binary()` | `undefined` | |
| `return_metrics` | `boolean()` | `false` | |
| `tcp_fastopen` | `boolean()` | `false` | curl >= 7.49.0 |
| Option | Type | Default | Notes |
|:--------------------|:------------------------------|:------------|:--------------------------------------------------------------------------------|
| `headers` | `[{binary(), iodata()}]` | `[]` | |
| `cookiejar` | opaque (returned in response) | `[]` | |
| `body` | `iodata()` | `<<>>` | |
| `connecttimeout_ms` | `pos_integer()` | 30000 | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html) |
| `followlocation` | `boolean()` | `false` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html) |
| `ssl_verifyhost` | `boolean()` | `true` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html) |
| `ssl_verifypeer` | `boolean()` | `true` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html) |
| `capath` | `binary()` | `undefined` | |
| `cacert` | `binary()` | `undefined` | |
| `timeout_ms` | `pos_integer()` | 30000 | |
| `maxredirs` | `non_neg_integer()` | 9 | |
| `proxy` | `binary()` | `undefined` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html) |
| `return_metrics` | `boolean()` | `false` | |
| `tcp_fastopen` | `boolean()` | `false` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_TCP_FASTOPEN.html) curl >= 7.49.0 |
| `interface` | `binary()` | `undefined` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_INTERFACE.html) |

#### Responses

Expand All @@ -133,11 +134,11 @@ katipo:Method(Pool :: atom(), URL :: binary(), ReqOptions :: map()).

#### Pool Options

| Option | Type | Default | Note |
|:------------------------|:---------------------|:----------------- |----------------------------------------|
| `pipelining` | `boolean()` | `false` | HTTP pipelining |
| `max_pipeline_length` | `non_neg_integer()` | 100 | |
| `max_total_connections` | `non_neg_integer()` | 0 (no limit) | |
| Option | Type | Default | Note |
|:------------------------|:--------------------|:-------------|:---------------------------------------------------------------------------|
| `pipelining` | `boolean()` | `false` | HTTP pipelining |
| `max_pipeline_length` | `non_neg_integer()` | 100 | |
| `max_total_connections` | `non_neg_integer()` | 0 (no limit) | [docs](https://curl.haxx.se/libcurl/c/CURLMOPT_MAX_TOTAL_CONNECTIONS.html) |

#### Metrics

Expand Down
18 changes: 18 additions & 0 deletions c_src/katipo.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#define K_CURLOPT_PROXY 15
#define K_CURLOPT_CACERT 16
#define K_CURLOPT_TCP_FASTOPEN 17
#define K_CURLOPT_INTERFACE 18

#define K_CURLAUTH_BASIC 100
#define K_CURLAUTH_DIGEST 101
Expand Down Expand Up @@ -100,6 +101,7 @@ typedef struct _EasyOpts {
char *curlopt_password;
char *curlopt_proxy;
long curlopt_tcp_fastopen;
char *curlopt_interface;
} EasyOpts;

static const char *curl_error_code(CURLcode error) {
Expand Down Expand Up @@ -779,6 +781,10 @@ static void new_conn(long method, char *url, struct curl_slist *req_headers,
curl_easy_setopt(conn->easy, CURLOPT_PROXY,
eopts.curlopt_proxy);
}
if (eopts.curlopt_interface != NULL) {
curl_easy_setopt(conn->easy, CURLOPT_INTERFACE,
eopts.curlopt_interface);
}
#if LIBCURL_VERSION_NUM >= 0x073100 /* Available since 7.49.0 */
curl_easy_setopt(conn->easy, CURLOPT_TCP_FASTOPEN, eopts.curlopt_tcp_fastopen);
#endif
Expand All @@ -801,6 +807,12 @@ static void new_conn(long method, char *url, struct curl_slist *req_headers,
if (eopts.curlopt_password != NULL) {
free(eopts.curlopt_password);
}
if (eopts.curlopt_proxy != NULL) {
free(eopts.curlopt_proxy);
}
if (eopts.curlopt_interface != NULL) {
free(eopts.curlopt_interface);
}

set_method(method, conn);
rc = curl_multi_add_handle(global->multi, conn->easy);
Expand Down Expand Up @@ -948,6 +960,7 @@ static void erl_input(struct bufferevent *ev, void *arg) {
eopts.curlopt_password = NULL;
eopts.curlopt_proxy = NULL;
eopts.curlopt_tcp_fastopen = 0;
eopts.curlopt_interface = NULL;

if (ei_decode_list_header(buf, &index, &num_eopts)) {
errx(2, "Couldn't decode eopts length");
Expand Down Expand Up @@ -1041,6 +1054,11 @@ static void erl_input(struct bufferevent *ev, void *arg) {
case K_CURLOPT_TCP_FASTOPEN:
eopts.curlopt_tcp_fastopen = eopt_long;
break;
case K_CURLOPT_INTERFACE:
if (erl_type == ERL_BINARY_EXT) {
eopts.curlopt_interface = eopt_binary;
}
break;
default:
errx(2, "Unknown eopt value %ld", eopt);
}
Expand Down
2 changes: 1 addition & 1 deletion src/katipo.app.src
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{application, 'katipo',
[{description, "HTTP client based on libcurl"},
{vsn, "0.6.0"},
{vsn, "0.6.1"},
{registered, []},
{mod, {'katipo_app', []}},
{applications,
Expand Down
12 changes: 9 additions & 3 deletions src/katipo.erl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
-define(proxy, 15).
-define(cacert, 16).
-define(tcp_fastopen, 17).
-define(interface, 18).

-define(DEFAULT_REQ_TIMEOUT, 30000).
-define(FOLLOWLOCATION_TRUE, 1).
Expand Down Expand Up @@ -254,7 +255,8 @@
password = undefined :: undefined | binary(),
proxy = undefined :: undefined | binary(),
return_metrics = false :: boolean(),
tcp_fastopen = ?TCP_FASTOPEN_FALSE :: ?TCP_FASTOPEN_FALSE | ?TCP_FASTOPEN_TRUE
tcp_fastopen = ?TCP_FASTOPEN_FALSE :: ?TCP_FASTOPEN_FALSE | ?TCP_FASTOPEN_TRUE,
interface = undefined :: undefined | binary()
}).

-spec get(katipo_pool:name(), url()) -> response().
Expand Down Expand Up @@ -363,7 +365,8 @@ handle_call(#req{method = Method,
username = Username,
password = Password,
proxy = Proxy,
tcp_fastopen = TCPFastOpen},
tcp_fastopen = TCPFastOpen,
interface = Interface},
From,
State=#state{port=Port, reqs=Reqs}) ->
{Self, Ref} = From,
Expand All @@ -379,7 +382,8 @@ handle_call(#req{method = Method,
{?username, Username},
{?password, Password},
{?proxy, Proxy},
{?tcp_fastopen, TCPFastOpen}],
{?tcp_fastopen, TCPFastOpen},
{?interface, Interface}],
Command = {Self, Ref, Method, Url, Headers, CookieJar, Body, Opts},
true = port_command(Port, term_to_binary(Command)),
Tref = erlang:start_timer(Timeout, self(), {req_timeout, From}),
Expand Down Expand Up @@ -545,6 +549,8 @@ opt(tcp_fastopen, true, {Req, Errors}) ->
{Req#req{tcp_fastopen=?TCP_FASTOPEN_TRUE}, Errors};
opt(tcp_fastopen, false, {Req, Errors}) ->
{Req#req{tcp_fastopen=?TCP_FASTOPEN_FALSE}, Errors};
opt(interface, Interface, {Req, Errors}) when is_binary(Interface) ->
{Req#req{interface=Interface}, Errors};
opt(K, V, {Req, Errors}) ->
{Req, [{K, V} | Errors]}.

Expand Down
18 changes: 18 additions & 0 deletions test/katipo_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ groups() ->
followlocation_false,
tcp_fastopen_true,
tcp_fastopen_false,
interface,
interface_unknown,
timeout_ms,
maxredirs,
basic_unauthorised,
Expand Down Expand Up @@ -377,6 +379,22 @@ tcp_fastopen_false(_) ->
{ok, #{}} =
katipo:get(?POOL, <<"http://httpbin.org/get">>, #{tcp_fastopen => false}).

interface(_) ->
Interface = case os:type() of
{unix, darwin} ->
<<"en0">>;
{unix, _} ->
<<"eth0">>;
_ ->
erlang:error({unknown_operating_system, fixme})
end,
{ok, #{}} =
katipo:get(?POOL, <<"http://httpbin.org/get">>, #{interface => Interface}).

interface_unknown(_) ->
{error, #{code := interface_failed}} =
katipo:get(?POOL, <<"http://httpbin.org/get">>, #{interface => <<"cannot_be_an_interface">>}).

maxredirs(_) ->
Opts = #{followlocation => true, maxredirs => 2},
{error, #{code := too_many_redirects, message := <<"Maximum (2) redirects followed">>}} =
Expand Down

0 comments on commit b16b897

Please sign in to comment.