Skip to content

Commit 530185e

Browse files
committed
Add test coverage to see how HTTP versions are handled.
To see how HTTP client versions get translated into underlying requests to the API backend before we start tinkering with more Enovy settings that could impact this.
1 parent 3f94ca3 commit 530185e

File tree

10 files changed

+205
-0
lines changed

10 files changed

+205
-0
lines changed

Taskfile.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,15 @@ tasks:
318318
generates:
319319
- ./build/work/stamp/test-deps/bundle
320320

321+
test-deps:caddy:
322+
cmds:
323+
- ./tasks/test-deps/caddy
324+
sources:
325+
- ./tasks/test-deps/caddy
326+
- ./tasks/helpers.sh
327+
generates:
328+
- ./build/work/stamp/test-deps/caddy
329+
321330
test-deps:glauth:
322331
cmds:
323332
- ./tasks/test-deps/glauth
@@ -363,6 +372,7 @@ tasks:
363372
test-deps:
364373
cmds:
365374
- task: test-deps:bundle
375+
- task: test-deps:caddy
366376
- task: test-deps:glauth
367377
- task: test-deps:luarocks
368378
- task: test-deps:mailpit

config/schema.cue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,11 @@ import "path"
925925
port: uint16 | *13104
926926
}
927927

928+
caddy: {
929+
http_port: uint16 | *13105
930+
https_port: uint16 | *13106
931+
}
932+
928933
umask: string | *"0027"
929934

930935
geoip: {

src/api-umbrella/cli/write_config_files.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ local function activate_services()
261261
active_services["dev-env-example-website-hugo"] = 1
262262
end
263263
if config["app_env"] == "test" then
264+
active_services["test-env-caddy"] = 1
264265
active_services["test-env-glauth"] = 1
265266
active_services["test-env-mailpit"] = 1
266267
active_services["test-env-nginx"] = 1

tasks/outdated.thor

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ require "uri"
1111

1212
class Outdated < Thor
1313
REPOS = {
14+
"caddy" => {
15+
:git => "https://github.com/caddyserver/caddy.git",
16+
:github_release => "caddyserver/caddy",
17+
},
1418
"cue" => {
1519
:git => "https://github.com/cue-lang/cue.git",
1620
:github_release => "cue-lang/cue",

tasks/test-deps/caddy

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
set -e -u -x
4+
source ./tasks/helpers.sh
5+
6+
caddy_version="2.10.2"
7+
caddy_hash="747df7ee74de188485157a383633a1a963fd9233b71fbb4a69ddcbcc589ce4e2cc82dacf5dbbe136cb51d17e14c59daeb5d9bc92487610b0f3b93680b2646546"
8+
if [ "$TARGETARCH" == "arm64" ]; then
9+
caddy_hash="6ce061a690312ab38367df3c5d5f89a2e4a263e7300d300d87356211bb81e79b15933e6d6203e03fbf26f15cc0311f264805f336147dbdd24938d84b57a4421c"
10+
fi
11+
12+
task_working_dir
13+
download "https://github.com/caddyserver/caddy/releases/download/v${caddy_version}/caddy_${caddy_version}_linux_${TARGETARCH}.tar.gz" "sha512" "$caddy_hash"
14+
extract_download "caddy_${caddy_version}_linux_${TARGETARCH}.tar.gz"
15+
16+
install -D -m 755 "caddy" "$TEST_INSTALL_PREFIX/bin/caddy"
17+
18+
stamp
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
HOME=<%- config["tmp_dir"] %>/caddy
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env bash
2+
set -e -u
3+
exec ../rc.log "$@"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env bash
2+
set -e -u
3+
4+
# Redirect stderr to stdout
5+
exec 2>&1
6+
7+
umask "<%- config['umask'] %>"
8+
9+
if [ "${1}" = "start" ]; then
10+
echo "starting ${2}..."
11+
api_umbrella_user="<%- config['user'] %>"
12+
13+
PATH="<%- config['_test_env_install_dir'] %>/sbin:<%- config['_test_env_install_dir'] %>/bin:$PATH"
14+
run_args=("-e" "rc.env")
15+
if [ -n "$api_umbrella_user" ]; then
16+
run_args+=("-u" "$api_umbrella_user")
17+
fi
18+
19+
exec runtool ${run_args[@]+"${run_args[@]}"} caddy run \
20+
--config "<%- config['etc_dir'] %>/test-env/Caddyfile"
21+
fi
22+
23+
exit 0
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
http://localhost:<%- config["caddy"]["http_port"] %> {
2+
tls internal
3+
log
4+
metrics /metrics
5+
respond <<JSON
6+
{
7+
"http.request.proto": "{http.request.proto}"
8+
}
9+
JSON
10+
}
11+
12+
https://localhost:<%- config["caddy"]["https_port"] %> {
13+
tls internal
14+
log
15+
metrics /metrics
16+
respond <<JSON
17+
{
18+
"http.request.proto": "{http.request.proto}"
19+
}
20+
JSON
21+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
require_relative "../test_helper"
2+
3+
# Tests to see how different HTTP client version request get translated into
4+
# HTTP requests for the API backend proxied requests.
5+
#
6+
# Currently, these all get translated to HTTP 1.1 requests (since nginx doesn't
7+
# currently support 2.0 upstream requests:
8+
# https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version),
9+
# but if this changes in the behavior, we can update these tests (this is
10+
# mostly just about documenting current behavior).
11+
#
12+
# This uses Caddy as an API backend server, since it supports HTTP versions
13+
# 1-3. The current version of curl inside our image doesn't yet support HTTP
14+
# v3, though, so we don't have tests for that yet.
15+
class Test::Proxy::TestBackendHttpVersions < Minitest::Test
16+
include ApiUmbrellaTestHelpers::Setup
17+
18+
parallelize_me!
19+
20+
def setup
21+
super
22+
setup_server
23+
once_per_class_setup do
24+
prepend_api_backends([
25+
{
26+
:frontend_host => "127.0.0.1",
27+
:backend_host => "localhost",
28+
:servers => [{ :host => "127.0.0.1", :port => $config["caddy"]["http_port"] }],
29+
:url_matches => [{ :frontend_prefix => "/#{unique_test_class_id}/http/", :backend_prefix => "/" }],
30+
},
31+
{
32+
:frontend_host => "127.0.0.1",
33+
:backend_host => "localhost",
34+
:backend_protocol => "https",
35+
:servers => [{ :host => "127.0.0.1", :port => $config["caddy"]["https_port"] }],
36+
:url_matches => [{ :frontend_prefix => "/#{unique_test_class_id}/https/", :backend_prefix => "/" }],
37+
},
38+
])
39+
end
40+
end
41+
42+
def test_httpv1_0_client
43+
# Make to HTTP server port, since current version of curl doesn't seem to
44+
# work with HTTP 1.0 without `--no-alpn` option, which Typhoeus doesn't
45+
# currently support.
46+
http_opts = http_options.merge(ssl_verifypeer: false, http_version: :httpv1_0)
47+
response = Typhoeus.get("http://localhost:#{$config["caddy"]["http_port"]}/", http_opts)
48+
assert_response_code(200, response)
49+
assert_match("HTTP/1.0 200 OK", response.response_headers)
50+
data = MultiJson.load(response.body)
51+
assert_equal("HTTP/1.0", data.fetch("http.request.proto"))
52+
53+
response = Typhoeus.get("http://127.0.0.1:9080/#{unique_test_class_id}/http/", http_opts)
54+
assert_response_code(200, response)
55+
assert_match("HTTP/1.1 200 OK", response.response_headers)
56+
data = MultiJson.load(response.body)
57+
assert_equal("HTTP/1.1", data.fetch("http.request.proto"))
58+
end
59+
60+
def test_httpv1_1_client
61+
http_opts = http_options.merge(ssl_verifypeer: false, http_version: :httpv1_1)
62+
response = Typhoeus.get("https://localhost:#{$config["caddy"]["https_port"]}/", http_opts)
63+
assert_response_code(200, response)
64+
assert_match("HTTP/1.1 200 OK", response.response_headers)
65+
data = MultiJson.load(response.body)
66+
assert_equal("HTTP/1.1", data.fetch("http.request.proto"))
67+
68+
response = Typhoeus.get("http://127.0.0.1:9080/#{unique_test_class_id}/https/", http_opts)
69+
assert_response_code(200, response)
70+
assert_match("HTTP/1.1 200 OK", response.response_headers)
71+
data = MultiJson.load(response.body)
72+
assert_equal("HTTP/1.1", data.fetch("http.request.proto"))
73+
end
74+
75+
def test_httpv2_0_client
76+
http_opts = http_options.merge(ssl_verifypeer: false, http_version: :httpv2_0)
77+
response = Typhoeus.get("https://localhost:#{$config["caddy"]["https_port"]}/", http_opts)
78+
assert_response_code(200, response)
79+
assert_match("HTTP/2 200", response.response_headers)
80+
data = MultiJson.load(response.body)
81+
assert_equal("HTTP/2.0", data.fetch("http.request.proto"))
82+
83+
response = Typhoeus.get("http://127.0.0.1:9080/#{unique_test_class_id}/https/", http_opts)
84+
assert_response_code(200, response)
85+
assert_match("HTTP/1.1 200", response.response_headers)
86+
data = MultiJson.load(response.body)
87+
assert_equal("HTTP/1.1", data.fetch("http.request.proto"))
88+
end
89+
90+
def test_httpv2_tls_client
91+
http_opts = http_options.merge(ssl_verifypeer: false, http_version: :httpv2_tls)
92+
response = Typhoeus.get("https://localhost:#{$config["caddy"]["https_port"]}/", http_opts)
93+
assert_response_code(200, response)
94+
assert_match("HTTP/2 200", response.response_headers)
95+
data = MultiJson.load(response.body)
96+
assert_equal("HTTP/2.0", data.fetch("http.request.proto"))
97+
98+
response = Typhoeus.get("http://127.0.0.1:9080/#{unique_test_class_id}/https/", http_opts)
99+
assert_response_code(200, response)
100+
assert_match("HTTP/1.1 200", response.response_headers)
101+
data = MultiJson.load(response.body)
102+
assert_equal("HTTP/1.1", data.fetch("http.request.proto"))
103+
end
104+
105+
def test_httpv2_prior_knowledge_client
106+
http_opts = http_options.merge(ssl_verifypeer: false, http_version: :httpv2_prior_knowledge)
107+
response = Typhoeus.get("https://localhost:#{$config["caddy"]["https_port"]}/", http_opts)
108+
assert_response_code(200, response)
109+
assert_match("HTTP/2 200", response.response_headers)
110+
data = MultiJson.load(response.body)
111+
assert_equal("HTTP/2.0", data.fetch("http.request.proto"))
112+
113+
response = Typhoeus.get("http://127.0.0.1:9080/#{unique_test_class_id}/https/", http_opts)
114+
assert_response_code(200, response)
115+
assert_match("HTTP/1.1 200", response.response_headers)
116+
data = MultiJson.load(response.body)
117+
assert_equal("HTTP/1.1", data.fetch("http.request.proto"))
118+
end
119+
end

0 commit comments

Comments
 (0)