1{ hostPkgs, lib, ... }:
2
3# Tests basics such as TLS, creating a mime-type & serving Unicode characters.
4
5let
6 domain = {
7 HTTP = "h2o.local";
8 TLS = "acme.test";
9 };
10
11 port = {
12 HTTP = 8080;
13 TLS = 8443;
14 };
15
16 sawatdi_chao_lok = "สวัสดีชาวโลก";
17
18 hello_world_txt = hostPkgs.writeTextFile {
19 name = "/hello_world.txt";
20 text = sawatdi_chao_lok;
21 };
22
23 hello_world_rst = hostPkgs.writeTextFile {
24 name = "/hello_world.rst";
25 text = # rst
26 ''
27 ====================
28 Thaiger Sprint 2025‼
29 ====================
30
31 ${sawatdi_chao_lok}
32 '';
33 };
34in
35{
36 name = "h2o-basic";
37
38 meta = {
39 maintainers = with lib.maintainers; [ toastal ];
40 };
41
42 nodes = {
43 server =
44 { pkgs, ... }:
45 {
46 environment.systemPackages = [
47 pkgs.curlHTTP3
48 ];
49
50 services.h2o = {
51 enable = true;
52 defaultHTTPListenPort = port.HTTP;
53 defaultTLSListenPort = port.TLS;
54 hosts = {
55 "${domain.HTTP}" = {
56 settings = {
57 paths = {
58 "/hello_world.txt" = {
59 "file.file" = "${hello_world_txt}";
60 };
61 };
62 };
63 };
64 "${domain.TLS}" = {
65 tls = {
66 policy = "force";
67 quic = {
68 retry = "ON";
69 };
70 identity = [
71 {
72 key-file = ../../common/acme/server/acme.test.key.pem;
73 certificate-file = ../../common/acme/server/acme.test.cert.pem;
74 }
75 ];
76 extraSettings = {
77 minimum-version = "TLSv1.3";
78 # when using common ACME certs, disable talking to CA
79 ocsp-update-interval = 0;
80 };
81 };
82 settings = {
83 paths = {
84 "/hello_world.rst" = {
85 "file.file" = "${hello_world_rst}";
86 };
87 };
88 };
89 };
90 };
91 settings = {
92 compress = "ON";
93 compress-minimum-size = 32;
94 "file.mime.addtypes" = {
95 "text/x-rst" = {
96 extensions = [ ".rst" ];
97 is_compressible = "YES";
98 };
99 };
100 ssl-offload = "kernel";
101 };
102 };
103
104 security.pki.certificates = [
105 (builtins.readFile ../../common/acme/server/ca.cert.pem)
106 ];
107
108 networking = {
109 firewall = {
110 allowedTCPPorts = with port; [
111 HTTP
112 TLS
113 ];
114 allowedUDPPorts = with port; [
115 TLS
116 ];
117 };
118 extraHosts = ''
119 127.0.0.1 ${domain.HTTP}
120 127.0.0.1 ${domain.TLS}
121 '';
122 };
123 };
124 };
125 testScript =
126 let
127 portStrHTTP = builtins.toString port.HTTP;
128 portStrTLS = builtins.toString port.TLS;
129 in
130 # python
131 ''
132 server.wait_for_unit("h2o.service")
133 server.wait_for_open_port(${portStrHTTP})
134 server.wait_for_open_port(${portStrTLS})
135
136 assert "${sawatdi_chao_lok}" in server.succeed("curl --fail-with-body 'http://${domain.HTTP}:${portStrHTTP}/hello_world.txt'")
137
138 tls_hello_world_head = server.succeed("curl -v --head --compressed --http2 --tlsv1.3 --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'").lower()
139 assert "http/2 200" in tls_hello_world_head
140 assert "server: h2o" in tls_hello_world_head
141 assert "content-type: text/x-rst" in tls_hello_world_head
142
143 assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http2 --tlsv1.3 --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
144
145 quic_hello_world_head = server.succeed("curl -v --head --compressed --http3-only --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'").lower()
146 assert "http/3 200" in quic_hello_world_head
147 assert "server: h2o" in quic_hello_world_head
148 assert "content-type: text/x-rst" in quic_hello_world_head
149
150 assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http3-only --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
151
152 assert "redirected" in server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'").lower()
153
154 server.fail("curl --location --max-redirs 0 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'")
155
156 assert "${sawatdi_chao_lok}" in server.succeed("curl -v --location --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'")
157 '';
158}