Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: HTTP/3 #96

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
sudo: required
dist: xenial
group: edge
Expand All @@ -6,23 +7,43 @@ language: erlang

install:
- ORIG_DIR=$PWD
- export PATH=$PATH:$HOME/.cargo/bin
- git clone --recursive https://github.com/cloudflare/quiche
- cd quiche/deps/boringssl
- mkdir build
- cd build
- cmake -DCMAKE_POSITION_INDEPENDENT_CODE=on ..
- make -j`nproc`
- cd ..
- mkdir .openssl/lib -p
- cp build/crypto/libcrypto.a build/ssl/libssl.a .openssl/lib
- ln -s $PWD/include .openssl
- cd ../..
- QUICHE_BSSL_PATH=$PWD/deps/boringssl cargo build --release --features pkg-config-meta
- cd ..
- wget https://github.com/erlang/rebar3/releases/download/3.10.0/rebar3 && chmod 755 rebar3
- wget https://github.com/curl/curl/releases/download/curl-7_64_1/curl-7.64.1.tar.gz && tar xf curl-7.64.1.tar.gz
- cd curl-7.64.1 && ./configure && make && sudo make install
- git clone https://github.com/curl/curl
- cd curl
- ./buildconf
- ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-ssl=$PWD/../quiche/deps/boringssl/.openssl --with-quiche=$PWD/../quiche/target/release
- make -j`nproc`
- sudo make install
- cd $ORIG_DIR

otp_release:
- 20.3
- 21.3
- 22.0

script:
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
- export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
- ./rebar3 update && ./rebar3 ct && ./rebar3 dialyzer && ./rebar3 coveralls send

before_install:
- sudo ifconfig
- sudo apt-get update -q
- sudo apt-get install -qy build-essential libssl-dev libnghttp2-dev
- sudo apt-get install -qy build-essential libssl-dev libnghttp2-dev curl git cmake
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- sudo apt purge -y curl && sudo apt autoremove -y

cache:
directories:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
katipo
=====

An HTTP/HTTP2 client library for Erlang built around libcurl-multi and libevent.
An HTTP/HTTP2/HTTP3 client library for Erlang built around libcurl-multi and libevent.

### Status

Expand Down Expand Up @@ -122,7 +122,7 @@ katipo:Method(Pool :: atom(), URL :: binary(), ReqOptions :: map()).
| `unix_socket_path` | `binary()` | `undefined` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_UNIX_SOCKET_PATH.html) curl >= 7.40.0 |
| `lock_data_ssl_session` | `boolean()` | `false` | [docs](https://curl.haxx.se/libcurl/c/curl_share_setopt.html) curl >= 7.23.0 |
| `doh_url` | `binary()` | `undefined` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_DOH_URL.html) curl >= 7.62.0 |
| `http_version` | `curl_http_version_none` <br> `curl_http_version_1_0` <br> `curl_http_version_1_1` <br> `curl_http_version_2_0` <br> `curl_http_version_2tls` <br> `curl_http_version_2_prior_knowledge` | `curl_http_version_none` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_HTTP_VERSION.html) curl >= 7.62.0 |
| `http_version` | `curl_http_version_none` <br> `curl_http_version_1_0` <br> `curl_http_version_1_1` <br> `curl_http_version_2_0` <br> `curl_http_version_2tls` <br> `curl_http_version_2_prior_knowledge` <br> `curl_http_version_3` | `curl_http_version_none` | [docs](https://curl.haxx.se/libcurl/c/CURLOPT_HTTP_VERSION.html) curl >= 7.62.0 |

#### Responses

Expand Down
5 changes: 3 additions & 2 deletions c_src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ else ifeq ($(UNAME_SYS), Linux)
CC ?= gcc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -finline-functions -Wall
LDLIBS += -L /usr/local/lib
endif

CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) -I /tmp/curl/include
CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)

LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei -lcurl -lssl -lcrypto -levent
LDLIBS += -L /tmp/curl/lib -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei -lcurl -lssl -lcrypto -levent

c_verbose_0 = @echo " C " $(?F);
c_verbose = $(c_verbose_$(V))
Expand Down
37 changes: 30 additions & 7 deletions c_src/katipo.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ typedef struct _GlobalInfo {
CURLSH *shobject;
int still_running;
size_t to_get;
curl_version_info_data *ver;
} GlobalInfo;

typedef struct _ConnInfo {
Expand Down Expand Up @@ -530,6 +531,7 @@ static void check_multi_info(GlobalInfo *global) {
CURLcode res;

while ((msg = curl_multi_info_read(global->multi, &msgs_left))) {
fprintf(stderr, "ZZZZ curl_multi_info_read\n");
if (msg->msg == CURLMSG_DONE) {
easy = msg->easy_handle;
res = msg->data.result;
Expand All @@ -549,6 +551,7 @@ static void check_multi_info(GlobalInfo *global) {
send_error_to_erlang(res, conn);
}

fprintf(stderr, "ZZZZ curl_multi_remove_handle\n");
curl_multi_remove_handle(global->multi, easy);
free(conn->url);
free(conn->pid);
Expand Down Expand Up @@ -656,6 +659,7 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) {
size_t realsize = size * nmemb;
ConnInfo *conn = (ConnInfo *)data;

fprintf(stderr, "ZZZZ write_cb\n");
conn->memory = (char *)realloc(conn->memory, conn->size + realsize);
memcpy(&(conn->memory[conn->size]), ptr, realsize);
conn->size += realsize;
Expand All @@ -665,19 +669,31 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) {

static size_t header_cb(void *ptr, size_t size, size_t nmemb, void *data) {
size_t realsize = size * nmemb;
size_t adjusted_size = realsize;
ConnInfo *conn = (ConnInfo *)data;
char *header;

// the last two chars of headers are \r\n
fprintf(stderr, "ZZZZ header_cb\n");
// the last two chars of headers are \r\n except for http3...
if (realsize > 2) {
if (conn->resp_headers && is_status_line(ptr)) {
curl_slist_free_all(conn->resp_headers);
conn->resp_headers = NULL;
conn->num_headers = 0;
}
header = (char *)malloc(realsize - 1);
strncpy(header, ptr, realsize - 2);
header[realsize - 2] = '\0';
// TODO: understand better what's going on with http3
// headers. They don't seem to have the trailing \r\n that the
// former HTTP versions do
#if LIBCURL_VERSION_NUM >= 0x074200
long http_version;
curl_easy_getinfo(conn->easy, CURLINFO_HTTP_VERSION, &http_version);
if (http_version == CURL_HTTP_VERSION_3) {
adjusted_size += 1;
}
#endif
header = (char *)malloc(adjusted_size - 1);
strncpy(header, ptr, adjusted_size - 2);
header[adjusted_size - 2] = '\0';
conn->resp_headers = curl_slist_append(conn->resp_headers, header);
free(header);
conn->num_headers++;
Expand Down Expand Up @@ -802,9 +818,11 @@ static void new_conn(long method, char *url, struct curl_slist *req_headers,
eopts.curlopt_interface);
}
#if LIBCURL_VERSION_NUM >= 0x072800 /* Available since 7.40.0 */
if (eopts.curlopt_unix_socket_path != NULL) {
curl_easy_setopt(conn->easy, CURLOPT_UNIX_SOCKET_PATH,
eopts.curlopt_unix_socket_path);
if (global->ver->features & CURL_VERSION_UNIX_SOCKETS) {
if (eopts.curlopt_unix_socket_path != NULL) {
curl_easy_setopt(conn->easy, CURLOPT_UNIX_SOCKET_PATH,
eopts.curlopt_unix_socket_path);
}
}
#endif
#if LIBCURL_VERSION_NUM >= 0x073100 /* Available since 7.49.0 */
Expand Down Expand Up @@ -834,6 +852,7 @@ static void new_conn(long method, char *url, struct curl_slist *req_headers,

set_method(method, conn);
rc = curl_multi_add_handle(global->multi, conn->easy);
fprintf(stderr, "ZZZZ curl_multi_add_handle\n");
mcode_or_die("new_conn: curl_multi_add_handle", rc);
}

Expand Down Expand Up @@ -1098,6 +1117,7 @@ static void erl_input(struct bufferevent *ev, void *arg) {
errx(2, "Couldn't skip empty eopt list");
}

fprintf(stderr, "ZZZZ new_conn\n");
new_conn(method, url, req_headers, req_cookies, post_data,
post_data_size, eopts, pid, ref, arg);

Expand Down Expand Up @@ -1131,6 +1151,7 @@ int main(int argc, char **argv) {
int option_index = 0;
int c;
long pipelining = 0;
curl_version_info_data *ver;

struct option long_options[] = {
{ "pipelining", required_argument, 0, 'p' },
Expand Down Expand Up @@ -1158,6 +1179,8 @@ int main(int argc, char **argv) {
}
global.timer_event = evtimer_new(global.evbase, timer_cb, &global);
global.to_get = 0;
ver = curl_version_info(CURLVERSION_NOW);
global.ver = ver;

curl_multi_setopt(global.multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
curl_multi_setopt(global.multi, CURLMOPT_SOCKETDATA, &global);
Expand Down
5 changes: 4 additions & 1 deletion src/katipo.erl
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@
curl_http_version_1_1 |
curl_http_version_2_0 |
curl_http_version_2tls |
curl_http_version_2_prior_knowledge.
curl_http_version_2_prior_knowledge |
curl_http_version_3.
-type curlmopts() :: [{max_pipeline_length, non_neg_integer()} |
{pipelining, pipelining()} |
{max_total_connections, non_neg_integer()}].
Expand Down Expand Up @@ -652,6 +653,8 @@ opt(http_version, curl_http_version_2tls, {Req, Errors}) ->
{Req#req{http_version=4}, Errors};
opt(http_version, curl_http_version_2_prior_knowledge, {Req, Errors}) ->
{Req#req{http_version=5}, Errors};
opt(http_version, curl_http_version_3, {Req, Errors}) ->
{Req#req{http_version=30}, Errors}; %% See https://github.com/curl/curl/blob/32d64b2e875f0d74cd433dff8bda9f8a98dcd44e/include/curl/curl.h#L1983
opt(verbose, true, {Req, Errors}) ->
{Req#req{verbose=?VERBOSE_TRUE}, Errors};
opt(verbose, false, {Req, Errors}) ->
Expand Down
Loading