From a157b4948a57854ddfcea7b2c5b1e992d8336633 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Tue, 17 Sep 2019 17:41:46 +1200 Subject: [PATCH] WIP --- c_src/Makefile | 4 +- c_src/katipo.c | 6 + test/katipo_SUITE.erl | 308 ++++++++++++++++++++++++------------------ 3 files changed, 187 insertions(+), 131 deletions(-) diff --git a/c_src/Makefile b/c_src/Makefile index 9996f4e..9bea048 100644 --- a/c_src/Makefile +++ b/c_src/Makefile @@ -28,10 +28,10 @@ else ifeq ($(UNAME_SYS), Linux) 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)) diff --git a/c_src/katipo.c b/c_src/katipo.c index ccc9fbb..694f16b 100644 --- a/c_src/katipo.c +++ b/c_src/katipo.c @@ -531,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; @@ -550,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); @@ -657,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; @@ -670,6 +673,7 @@ static size_t header_cb(void *ptr, size_t size, size_t nmemb, void *data) { ConnInfo *conn = (ConnInfo *)data; char *header; + 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)) { @@ -848,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); } @@ -1112,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); diff --git a/test/katipo_SUITE.erl b/test/katipo_SUITE.erl index 3445e1e..1c7953a 100644 --- a/test/katipo_SUITE.erl +++ b/test/katipo_SUITE.erl @@ -14,7 +14,9 @@ init_per_suite(Config) -> application:ensure_all_started(katipo), application:ensure_all_started(meck), {ok, _} = katipo_pool:start(?POOL, ?POOL_SIZE), - Config. + DataDir = ?config(data_dir, Config), + CACert = filename:join(DataDir, "ca-bundle.crt"), + [{cacert_file, list_to_binary(CACert)} | Config]. end_per_suite(_Config) -> ok = application:stop(katipo). @@ -32,13 +34,15 @@ init_per_group(session, Config) -> init_per_group(pool, Config) -> application:ensure_all_started(meck), Config; -init_per_group(https, Config) -> - DataDir = ?config(data_dir, Config), - CACert = filename:join(DataDir, "ca-bundle.crt"), - [{cacert_file, list_to_binary(CACert)} | Config]; init_per_group(proxy, Config) -> application:ensure_all_started(http_proxy), Config; +init_per_group(http1, Config) -> + [{httpbin_base, <<"https://httpbin.org">>}, {http_version, curl_http_version_1_1}] ++ Config; +init_per_group(http2, Config) -> + [{httpbin_base, <<"https://nghttp2.org/httpbin">>}, {http_version, curl_http_version_2_prior_knowledge}] ++ Config; +init_per_group(http3, Config) -> + [{httpbin_base, <<"https://cloudflare-quic.com/b">>}, {http_version, curl_http_version_3}] ++ Config; init_per_group(_, Config) -> Config. @@ -81,8 +85,6 @@ groups() -> post_arity_2, post_qs, post_req, - url_missing, - bad_method, put_data, put_arity_2, put_qs, @@ -99,7 +101,6 @@ groups() -> statuses, cookies, cookies_delete, - cookies_bad_cookie_jar, bytes, stream_bytes, utf8, @@ -107,18 +108,23 @@ groups() -> connecttimeout_ms, followlocation_true, followlocation_false, - tcp_fastopen_true, - tcp_fastopen_false, - interface, - interface_unknown, - unix_socket_path, - unix_socket_path_cant_connect, timeout_ms, maxredirs, basic_unauthorised, basic_authorised, digest_unauthorised, digest_authorised, + proxy_couldnt_connect]}, + {curl, [parallel], + [url_missing, + bad_method, + cookies_bad_cookie_jar, + tcp_fastopen_true, + tcp_fastopen_false, + interface, + interface_unknown, + unix_socket_path, + unix_socket_path_cant_connect, lock_data_ssl_session_true, lock_data_ssl_session_false, doh_url, @@ -150,15 +156,20 @@ groups() -> {metrics, [], [metrics_true, metrics_false]}, + {http1, [parallel], + [{group, http}, + {group, https}]}, {http2, [parallel], - [http2_get]}, + [{group, http}, + {group, https}]}, {http3, [parallel], - [http3_get]}]. + [{group, http}, + {group, https}]}]. all() -> - [{group, http}, + [{group, http1}, + {group, curl}, {group, pool}, - {group, https}, {group, proxy}, {group, session}, {group, port}, @@ -166,63 +177,76 @@ all() -> {group, http2}, {group, http3}]. -get(_) -> +get(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"https://httpbin.org/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>), + katipo:get(?POOL, httpbin_url(Config, <<"/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), [{<<"a">>, <<"!@#$%^&*()_+">>}] = proplists:get_value(<<"args">>, Json). -get_http(_) -> +get_http(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"http://httpbin.org/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>), + katipo:get(?POOL, httpbin_url(Config, <<"/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), [{<<"a">>, <<"!@#$%^&*()_+">>}] = proplists:get_value(<<"args">>, Json). -get_req(_) -> +get_req(Config) -> + HTTPVersion = ?config(http_version, Config), + Url = httpbin_url(Config, <<"/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>), {ok, #{status := 200, body := Body}} = - katipo:req(?POOL, #{url => <<"https://httpbin.org/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>}), + katipo:req(?POOL, #{url => Url, http_version => HTTPVersion}), Json = jsx:decode(Body), [{<<"a">>, <<"!@#$%^&*()_+">>}] = proplists:get_value(<<"args">>, Json). -head(_) -> +head(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200}} = - katipo:head(?POOL, <<"https://httpbin.org/get">>). + katipo:head(?POOL, httpbin_url(Config, <<"/get">>), #{http_version => HTTPVersion}). -post_data(_) -> +post_data(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:post(?POOL, <<"https://httpbin.org/post">>, + katipo:post(?POOL, httpbin_url(Config, <<"/post">>), #{headers => [{<<"Content-Type">>, <<"application/json">>}], - body => <<"!@#$%^&*()">>}), + body => <<"!@#$%^&*()">>, + http_version => HTTPVersion}), Json = jsx:decode(Body), <<"!@#$%^&*()">> = proplists:get_value(<<"data">>, Json). -post_iodata(_) -> +post_iodata(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:post(?POOL, <<"https://httpbin.org/post">>, + katipo:post(?POOL, httpbin_url(Config, <<"/post">>), #{headers => [{<<"Content-Type">>, <<"application/json">>}], - body => [<<"!@#$%">>, <<"^&*()">>]}), + body => [<<"!@#$%">>, <<"^&*()">>], + http_version => HTTPVersion}), Json = jsx:decode(Body), <<"!@#$%^&*()">> = proplists:get_value(<<"data">>, Json). -post_arity_2(_) -> +post_arity_2(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:post(?POOL, <<"https://httpbin.org/post">>), + katipo:post(?POOL, httpbin_url(Config, <<"/post">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), undefined = proplists:get_value(<<>>, Json). -post_qs(_) -> +post_qs(Config) -> + HTTPVersion = ?config(http_version, Config), QsVals = [{<<"foo">>, <<"bar">>}, {<<"baz">>, true}], {ok, #{status := 200, body := Body}} = - katipo:post(?POOL, <<"https://httpbin.org/post">>, #{body => QsVals}), + katipo:post(?POOL, httpbin_url(Config, <<"/post">>), #{body => QsVals, http_version => HTTPVersion}), Json = jsx:decode(Body), [] = [{<<"baz">>,<<>>},{<<"foo">>,<<"bar">>}] -- proplists:get_value(<<"form">>, Json). -post_req(_) -> +post_req(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:req(?POOL, #{url => <<"https://httpbin.org/post">>, - method => post, - headers => [{<<"Content-Type">>, <<"application/json">>}], - body => <<"!@#$%^&*()">>}), + katipo:req(?POOL, #{url => httpbin_url(Config, <<"/post">>), + method => post, + headers => [{<<"Content-Type">>, <<"application/json">>}], + body => <<"!@#$%^&*()">>, + http_version => HTTPVersion}), Json = jsx:decode(Body), <<"!@#$%^&*()">> = proplists:get_value(<<"data">>, Json). @@ -231,167 +255,196 @@ url_missing(_) -> BinaryMessage = iolist_to_binary(io_lib:format("~p", [Message])), {error, #{code := bad_opts, message := BinaryMessage}} = katipo:req(?POOL, #{method => post, - headers => [{<<"Content-Type">>, <<"application/json">>}], - body => <<"!@#$%^&*()">>}). + headers => [{<<"Content-Type">>, <<"application/json">>}], + body => <<"!@#$%^&*()">>}). bad_method(_) -> Message = [{method, toast}], BinaryMessage = iolist_to_binary(io_lib:format("~p", [Message])), {error, #{code := bad_opts, message := BinaryMessage}} = katipo:req(?POOL, #{method => toast, - headers => [{<<"Content-Type">>, <<"application/json">>}], - body => <<"!@#$%^&*()">>}). + headers => [{<<"Content-Type">>, <<"application/json">>}], + body => <<"!@#$%^&*()">>}). -put_data(_) -> +put_data(Config) -> + HTTPVersion = ?config(http_version, Config), Headers = [{<<"Content-Type">>, <<"application/json">>}], {ok, #{status := 200, body := Body}} = - katipo:put(?POOL, <<"https://httpbin.org/put">>, - #{headers => Headers, body => <<"!@#$%^&*()">>}), + katipo:put(?POOL, httpbin_url(Config, <<"/put">>), + #{headers => Headers, body => <<"!@#$%^&*()">>, http_version => HTTPVersion}), Json = jsx:decode(Body), <<"!@#$%^&*()">> = proplists:get_value(<<"data">>, Json). -put_arity_2(_) -> +put_arity_2(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:put(?POOL, <<"https://httpbin.org/put">>), + katipo:put(?POOL, httpbin_url(Config, <<"/put">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), undefined = proplists:get_value(<<>>, Json). -put_qs(_) -> +put_qs(Config) -> + HTTPVersion = ?config(http_version, Config), QsVals = [{<<"foo">>, <<"bar">>}, {<<"baz">>, true}], {ok, #{status := 200, body := Body}} = - katipo:put(?POOL, <<"https://httpbin.org/put">>, #{body => QsVals}), + katipo:put(?POOL, httpbin_url(Config, <<"/put">>), #{body => QsVals, http_version => HTTPVersion}), Json = jsx:decode(Body), [] = [{<<"baz">>,<<>>},{<<"foo">>,<<"bar">>}] -- proplists:get_value(<<"form">>, Json). -patch_data(_) -> +patch_data(Config) -> + HTTPVersion = ?config(http_version, Config), Headers = [{<<"Content-Type">>, <<"application/json">>}], {ok, #{status := 200, body := Body}} = - katipo:patch(?POOL, <<"https://httpbin.org/patch">>, - #{headers => Headers, body => <<"!@#$%^&*()">>}), + katipo:patch(?POOL, httpbin_url(Config, <<"/patch">>), + #{headers => Headers, body => <<"!@#$%^&*()">>, http_version => HTTPVersion}), Json = jsx:decode(Body), <<"!@#$%^&*()">> = proplists:get_value(<<"data">>, Json). -patch_arity_2(_) -> +patch_arity_2(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 200, body := Body}} = - katipo:patch(?POOL, <<"https://httpbin.org/patch">>), + katipo:patch(?POOL, httpbin_url(Config, <<"/patch">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), <<>> = proplists:get_value(<<"data">>, Json). -patch_qs(_) -> +patch_qs(Config) -> + HTTPVersion = ?config(http_version, Config), QsVals = [{<<"foo">>, <<"bar">>}, {<<"baz">>, true}], {ok, #{status := 200, body := Body}} = - katipo:patch(?POOL, <<"https://httpbin.org/patch">>, #{body => QsVals}), + katipo:patch(?POOL, httpbin_url(Config, <<"/patch">>), #{body => QsVals, http_version => HTTPVersion}), Json = jsx:decode(Body), [] = [{<<"baz">>,<<>>},{<<"foo">>,<<"bar">>}] -- proplists:get_value(<<"form">>, Json). -options(_) -> - {ok, #{status := 200, headers := Headers}} = katipo:options(?POOL, <<"https://httpbin.org">>), +options(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, headers := Headers}} = katipo:options(?POOL, httpbin_url(Config, <<"/get">>), #{http_version => HTTPVersion}), + Lowercase = lists:map(fun({K, V}) -> {string:lowercase(K), V} end, Headers), + %% Different httpbin servers have different header capitalisations <<"GET, POST, PUT, DELETE, PATCH, OPTIONS">> = - proplists:get_value(<<"Access-Control-Allow-Methods">>, Headers). + proplists:get_value(<<"access-control-allow-methods">>, Lowercase). -delete(_) -> - {ok, #{status := 200}} = katipo:delete(?POOL, <<"https://httpbin.org/delete">>). +delete(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200}} = katipo:delete(?POOL, httpbin_url(Config, <<"/delete">>), #{http_version => HTTPVersion}). -headers(_) -> +headers(Config) -> + Url = httpbin_url(Config, <<"/gzip">>), + Parsed = uri_string:parse(Url), + Host = maps:get(host, Parsed), + HTTPVersion = ?config(http_version, Config), Headers = [{<<"header1">>, <<"!@#$%^&*()">>}], {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"https://httpbin.org/gzip">>, #{headers => Headers}), + katipo:get(?POOL, Url, #{headers => Headers, http_version => HTTPVersion}), Json = jsx:decode(Body), Expected = [{<<"Accept">>,<<"*/*">>}, {<<"Accept-Encoding">>,<<"gzip,deflate">>}, {<<"Header1">>,<<"!@#$%^&*()">>}, - {<<"Host">>,<<"httpbin.org">>}], + {<<"Host">>,Host}], [] = Expected -- proplists:get_value(<<"headers">>, Json). -header_remove(_) -> +header_remove(Config) -> + Url = httpbin_url(Config, <<"/get">>), + Parsed = uri_string:parse(Url), + Host = maps:get(host, Parsed), + HTTPVersion = ?config(http_version, Config), Headers = [{<<"Accept-Encoding">>, <<>>}], {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"https://httpbin.org/get">>, #{headers => Headers}), + katipo:get(?POOL, Url, #{headers => Headers, http_version => HTTPVersion}), Json = jsx:decode(Body), Expected = [{<<"Accept">>,<<"*/*">>}, - {<<"Host">>,<<"httpbin.org">>}], + {<<"Host">>,Host}], [] = Expected -- proplists:get_value(<<"headers">>, Json). -gzip(_) -> - {ok, #{status := 200, body := Body}} = katipo:get(?POOL, <<"https://httpbin.org/gzip">>), +gzip(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, body := Body}} = katipo:get(?POOL, httpbin_url(Config, <<"/gzip">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), true = proplists:get_value(<<"gzipped">>, Json). -deflate(_) -> - {ok, #{status := 200, body := Body}} = katipo:get(?POOL, <<"https://httpbin.org/deflate">>), +deflate(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, body := Body}} = katipo:get(?POOL, httpbin_url(Config, <<"/deflate">>), #{http_version => HTTPVersion}), Json = jsx:decode(Body), true = proplists:get_value(<<"deflated">>, Json). -bytes(_) -> - {ok, #{status := 200, body := Body}} = katipo:get(?POOL, <<"https://httpbin.org/bytes/1024?seed=9999">>), +bytes(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, body := Body}} = katipo:get(?POOL, httpbin_url(Config, <<"/bytes/1024?seed=9999">>), #{http_version => HTTPVersion}), 1024 = byte_size(Body), <<168,123,193,120,18,120,65,73,67,119,198,61,39,1,24,169>> = crypto:hash(md5, Body). -stream_bytes(_) -> - {ok, #{status := 200, body := Body}} = katipo:get(?POOL, <<"https://httpbin.org/bytes/1024?seed=9999&chunk_size=8">>), +stream_bytes(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, body := Body}} = katipo:get(?POOL, httpbin_url(Config, <<"/bytes/1024?seed=9999&chunk_size=8">>), #{http_version => HTTPVersion}), 1024 = byte_size(Body), <<168,123,193,120,18,120,65,73,67,119,198,61,39,1,24,169>> = crypto:hash(md5, Body). -utf8(_) -> - {ok, #{status := 200, body := Body}} = katipo:get(?POOL, <<"https://httpbin.org/encoding/utf8">>), +utf8(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, body := Body}} = katipo:get(?POOL, httpbin_url(Config, <<"/encoding/utf8">>), #{http_version => HTTPVersion}), case xmerl_ucs:from_utf8(Body) of [_|_] -> ok end. -stream(_) -> - {ok, #{status := 200, body := Body}} = katipo:get(?POOL, <<"https://httpbin.org/stream/20">>), +stream(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200, body := Body}} = katipo:get(?POOL, httpbin_url(Config, <<"/stream/20">>), #{http_version => HTTPVersion}), 20 = length(binary:split(Body, <<"\n">>, [global, trim])). -statuses(_) -> +statuses(Config) -> + HTTPVersion = ?config(http_version, Config), MFAs = [begin B = integer_to_binary(S), - Url = <<"https://httpbin.org/status/",B/binary>>, - {katipo, get, [?POOL, Url]} + Url = httpbin_url(Config, <<"/status/",B/binary>>), + {katipo, get, [?POOL, Url, #{http_version => HTTPVersion}]} end || S <- http_status_codes()], Results = rpc:parallel_eval(MFAs), Results2 = [S || {ok, #{status := S}} <- Results], Results2 = http_status_codes(). -cookies(_) -> - Url = <<"https://httpbin.org/cookies/set?cname=cvalue">>, - Opts = #{followlocation => true}, +cookies(Config) -> + HTTPVersion = ?config(http_version, Config), + Url = httpbin_url(Config, <<"/cookies/set?cname=cvalue">>), + Opts = #{followlocation => true, http_version => HTTPVersion}, {ok, #{status := 200, body := Body}} = katipo:get(?POOL, Url, Opts), Json = jsx:decode(Body), [{<<"cname">>, <<"cvalue">>}] = proplists:get_value(<<"cookies">>, Json). -cookies_delete(_) -> - GetUrl = <<"https://httpbin.org/cookies/set?cname=cvalue">>, - Opts = #{followlocation => true}, +cookies_delete(Config) -> + HTTPVersion = ?config(http_version, Config), + GetUrl = httpbin_url(Config, <<"/cookies/set?cname=cvalue">>), + Opts = #{followlocation => true, http_version => HTTPVersion}, {ok, #{status := 200, cookiejar := CookieJar}} = katipo:get(?POOL, GetUrl, Opts), - DeleteUrl = <<"https://httpbin.org/cookies/delete?cname">>, + DeleteUrl = httpbin_url(Config, <<"/cookies/delete?cname">>), {ok, #{status := 200, body := Body}} = katipo:get(?POOL, DeleteUrl, #{cookiejar => CookieJar, followlocation => true}), Json = jsx:decode(Body), [{}] = proplists:get_value(<<"cookies">>, Json). cookies_bad_cookie_jar(_) -> - Url = <<"https://httpbin.org/cookies/delete?cname">>, + Url = <<"http://httpbin.org/cookies/delete?cname">>, CookieJar = ["has to be a binary"], Message = <<"[{cookiejar,[\"has to be a binary\"]}]">>, {error, #{code := bad_opts, message := Message}} = katipo:get(?POOL, Url, #{cookiejar => CookieJar}). %% TODO -redirect_to(_) -> - {ok, #{status := 302}} = katipo:get(?POOL, <<"https://httpbin.org/redirect-to?url=https://google.com">>). +redirect_to(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 302}} = katipo:get(?POOL, httpbin_url(Config, <<"/redirect-to?url=https://google.com">>), #{http_version => HTTPVersion}). connecttimeout_ms(_) -> {error, #{code := operation_timedout}} = katipo:get(?POOL, <<"http://google.com">>, #{connecttimeout_ms => 1}). -followlocation_true(_) -> - {ok, #{status := 200, headers := Headers}} = - katipo:get(?POOL, <<"https://httpbin.org/redirect/6">>, #{followlocation => true}), - 1 = length(proplists:get_all_values(<<"Server">>, Headers)). +followlocation_true(Config) -> + HTTPVersion = ?config(http_version, Config), + {ok, #{status := 200}} = + katipo:get(?POOL, httpbin_url(Config, <<"/redirect/6">>), #{followlocation => true, http_version => HTTPVersion}). -followlocation_false(_) -> +followlocation_false(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 302}} = - katipo:get(?POOL, <<"https://httpbin.org/redirect/6">>, #{followlocation => false}). + katipo:get(?POOL, httpbin_url(Config, <<"/redirect/6">>), #{followlocation => false, http_version => HTTPVersion}). tcp_fastopen_true(_) -> case katipo:get(?POOL, <<"https://httpbin.org/get">>, #{tcp_fastopen => true}) of @@ -450,35 +503,40 @@ unix_socket_path_cant_connect(_) -> ok end. -maxredirs(_) -> - Opts = #{followlocation => true, maxredirs => 2}, +maxredirs(Config) -> + HTTPVersion = ?config(http_version, Config), + Opts = #{followlocation => true, maxredirs => 2, http_version => HTTPVersion}, {error, #{code := too_many_redirects, message := <<"Maximum (2) redirects followed">>}} = - katipo:get(?POOL, <<"https://httpbin.org/redirect/6">>, Opts). + katipo:get(?POOL, httpbin_url(Config, <<"/redirect/6">>), Opts). -basic_unauthorised(_) -> +basic_unauthorised(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 401}} = - katipo:get(?POOL, <<"https://httpbin.org/basic-auth/johndoe/p455w0rd">>). + katipo:get(?POOL, httpbin_url(Config, <<"/basic-auth/johndoe/p455w0rd">>), #{http_version => HTTPVersion}). -basic_authorised(_) -> +basic_authorised(Config) -> + HTTPVersion = ?config(http_version, Config), Username = <<"johndoe">>, Password = <<"p455w0rd">>, {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"https://httpbin.org/basic-auth/johndoe/p455w0rd">>, - #{http_auth => basic, username => Username, password => Password}), + katipo:get(?POOL, httpbin_url(Config, <<"/basic-auth/johndoe/p455w0rd">>), + #{http_auth => basic, username => Username, password => Password, http_version => HTTPVersion}), Json = jsx:decode(Body), true = proplists:get_value(<<"authenticated">>, Json), Username = proplists:get_value(<<"user">>, Json). -digest_unauthorised(_) -> +digest_unauthorised(Config) -> + HTTPVersion = ?config(http_version, Config), {ok, #{status := 401}} = - katipo:get(?POOL, <<"https://httpbin.org/digest-auth/auth/johndoe/p455w0rd">>). + katipo:get(?POOL, httpbin_url(Config, <<"/digest-auth/auth/johndoe/p455w0rd">>), #{http_version => HTTPVersion}). -digest_authorised(_) -> +digest_authorised(Config) -> + HTTPVersion = ?config(http_version, Config), Username = <<"johndoe">>, Password = <<"p455w0rd">>, {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"https://httpbin.org/digest-auth/auth/johndoe/p455w0rd">>, - #{http_auth => digest, username => Username, password => Password}), + katipo:get(?POOL, httpbin_url(Config, <<"/digest-auth/auth/johndoe/p455w0rd">>), + #{http_auth => digest, username => Username, password => Password, http_version => HTTPVersion}), Json = jsx:decode(Body), true = proplists:get_value(<<"authenticated">>, Json), Username = proplists:get_value(<<"user">>, Json). @@ -520,9 +578,10 @@ proxy_couldnt_connect(_) -> {error, #{code := couldnt_connect}} = katipo:get(?POOL, Url, #{proxy => <<"http://localhost:3128">>}). -timeout_ms(_) -> +timeout_ms(Config) -> + HTTPVersion = ?config(http_version, Config), {error, #{code := operation_timedout}} = - katipo:get(?POOL, <<"https://httpbin.org/delay/1">>, #{timeout_ms => 500}). + katipo:get(?POOL, httpbin_url(Config, <<"/delay/1">>), #{timeout_ms => 500, http_version => HTTPVersion}). couldnt_resolve_host(_) -> {error, #{code := couldnt_resolve_host, @@ -790,19 +849,6 @@ metrics_false(_) -> katipo:head(?POOL, <<"https://httpbin.org/get">>, #{return_metrics => false}), false = maps:is_key(metrics, Res). -http2_get(_) -> - {ok, #{status := 200, body := Body}} = - katipo:get(?POOL, <<"https://nghttp2.org/httpbin/get?a=%21%40%23%24%25%5E%26%2A%28%29_%2B">>, - #{http_version => curl_http_version_2_prior_knowledge, verbose => true}), - Json = jsx:decode(Body), - [{<<"a">>, <<"!@#$%^&*()_+">>}] = proplists:get_value(<<"args">>, Json). - -http3_get(_) -> - {ok, #{status := 404, headers := Headers}} = - katipo:get(?POOL, <<"https://quic.tech:8443">>, - #{http_version => curl_http_version_3, verbose => true}), - <<"quiche">> = proplists:get_value(<<"server">>, Headers). - repeat_until_true(Fun) -> try case Fun() of @@ -816,3 +862,7 @@ repeat_until_true(Fun) -> timer:sleep(100), repeat_until_true(Fun) end. + +httpbin_url(Config, Path) -> + Base = ?config(httpbin_base, Config), + <>.