Skip to content

Commit feb2046

Browse files
committed
add TLS integration test for sync client
1 parent 2f362f2 commit feb2046

File tree

10 files changed

+502
-141
lines changed

10 files changed

+502
-141
lines changed

build.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ pub fn build(b: *std.Build) !void {
133133

134134
// compile
135135
const unit_tests = b.addTest(.{
136-
.root_source_file = b.path("src/unit_tests.zig"),
137-
.test_runner = .{ .path = b.path("src/unit_tests.zig"), .mode = .simple },
136+
.root_source_file = b.path("src/main_unit_tests.zig"),
137+
.test_runner = .{ .path = b.path("src/test_runner.zig"), .mode = .simple },
138138
.target = target,
139139
.optimize = mode,
140140
});

build.zig.zon

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
.version = "0.0.0",
55
.fingerprint = 0xda130f3af836cea0,
66
.dependencies = .{
7-
.tls = .{ .url = "https://github.com/ianic/tls.zig/archive/96b923fcdaa6371617154857cef7b8337778cbe2.tar.gz", .hash = "122031f94565d7420a155b6eaec65aaa02acc80e75e6f0947899be2106bc3055b1ec" },
7+
.tls = .{
8+
.url = "https://github.com/ianic/tls.zig/archive/21aeaa9dd90f89fb86b0cd597f201a2680236f06.tar.gz",
9+
.hash = "1220e584a5962cfba7c2f8d13151754bf76338c9916fedfd9b7a754501b9d9276c61",
10+
},
811
},
912
}

src/browser/browser.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub const Browser = struct {
7474
.allocator = allocator,
7575
.http_client = &app.http_client,
7676
.session_pool = SessionPool.init(allocator),
77-
.http_client = try http.Client.init(allocator, 5),
77+
.http_client = try http.Client.init(allocator, 5, null),
7878
.page_arena = std.heap.ArenaAllocator.init(allocator),
7979
};
8080
}

src/http/client.zig

Lines changed: 156 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
2+
//
3+
// Francis Bouvier <[email protected]>
4+
// Pierre Tachoire <[email protected]>
5+
//
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU Affero General Public License as
8+
// published by the Free Software Foundation, either version 3 of the
9+
// License, or (at your option) any later version.
10+
//
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU Affero General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU Affero General Public License
17+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
118
const std = @import("std");
219
const builtin = @import("builtin");
320

@@ -30,8 +47,9 @@ pub const Client = struct {
3047
state_pool: StatePool,
3148
root_ca: tls.config.CertBundle,
3249

33-
pub fn init(allocator: Allocator, max_concurrent: usize) !Client {
34-
var root_ca = try tls.config.CertBundle.fromSystem(allocator);
50+
// we only allow passing in a root_ca for testing
51+
pub fn init(allocator: Allocator, max_concurrent: usize, root_ca_: ?tls.config.CertBundle) !Client {
52+
var root_ca = root_ca_ orelse try tls.config.CertBundle.fromSystem(allocator);
3553
errdefer root_ca.deinit(allocator);
3654

3755
const state_pool = try StatePool.init(allocator, max_concurrent);
@@ -1420,8 +1438,7 @@ pub const Response = struct {
14201438
fn processData(self: *Response) !?[]u8 {
14211439
const data = self._data orelse return null;
14221440
const result = try self._reader.process(data);
1423-
self._done = result
1424-
.done;
1441+
self._done = result.done;
14251442
self._data = result.unprocessed; // for the next call
14261443
return result.data;
14271444
}
@@ -1631,21 +1648,21 @@ test "HttpClient Reader: fuzz" {
16311648
}
16321649

16331650
test "HttpClient: invalid url" {
1634-
var client = try Client.init(testing.allocator, 1);
1651+
var client = try testClient();
16351652
defer client.deinit();
16361653
try testing.expectError(error.UriMissingHost, client.request(.GET, "http:///"));
16371654
}
16381655

16391656
test "HttpClient: sync connect error" {
1640-
var client = try Client.init(testing.allocator, 2);
1657+
var client = try testClient();
16411658
defer client.deinit();
16421659

16431660
var req = try client.request(.GET, "HTTP://127.0.0.1:9920");
16441661
try testing.expectError(error.ConnectionRefused, req.sendSync(.{}));
16451662
}
16461663

16471664
test "HttpClient: sync no body" {
1648-
var client = try Client.init(testing.allocator, 2);
1665+
var client = try testClient();
16491666
defer client.deinit();
16501667

16511668
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/simple");
@@ -1658,8 +1675,24 @@ test "HttpClient: sync no body" {
16581675
try testing.expectEqual("0", res.header.get("content-length"));
16591676
}
16601677

1678+
test "HttpClient: sync tls no body" {
1679+
// https://github.com/ianic/tls.zig/issues/10
1680+
for (0..1) |_| {
1681+
var client = try testClient();
1682+
defer client.deinit();
1683+
1684+
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/simple");
1685+
var res = try req.sendSync(.{});
1686+
1687+
try testing.expectEqual(null, try res.next());
1688+
try testing.expectEqual(200, res.header.status);
1689+
try testing.expectEqual(1, res.header.count());
1690+
try testing.expectEqual("0", res.header.get("content-length"));
1691+
}
1692+
}
1693+
16611694
test "HttpClient: sync with body" {
1662-
var client = try Client.init(testing.allocator, 2);
1695+
var client = try testClient();
16631696
defer client.deinit();
16641697

16651698
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/echo");
@@ -1674,8 +1707,84 @@ test "HttpClient: sync with body" {
16741707
try testing.expectEqual("Close", res.header.get("_connection"));
16751708
}
16761709

1710+
test "HttpClient: sync tls with body" {
1711+
var arr: std.ArrayListUnmanaged(u8) = .{};
1712+
defer arr.deinit(testing.allocator);
1713+
try arr.ensureTotalCapacity(testing.allocator, 20);
1714+
1715+
// https://github.com/ianic/tls.zig/issues/10
1716+
for (0..1) |_| {
1717+
defer arr.clearRetainingCapacity();
1718+
var client = try testClient();
1719+
defer client.deinit();
1720+
1721+
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/body");
1722+
var res = try req.sendSync(.{});
1723+
1724+
while (try res.next()) |data| {
1725+
arr.appendSliceAssumeCapacity(data);
1726+
}
1727+
try testing.expectEqual("1234567890abcdefhijk", arr.items);
1728+
try testing.expectEqual(201, res.header.status);
1729+
try testing.expectEqual(2, res.header.count());
1730+
try testing.expectEqual("20", res.header.get("content-length"));
1731+
try testing.expectEqual("HEaDer", res.header.get("another"));
1732+
}
1733+
}
1734+
1735+
test "HttpClient: sync redirect from TLS to Plaintext" {
1736+
var arr: std.ArrayListUnmanaged(u8) = .{};
1737+
defer arr.deinit(testing.allocator);
1738+
try arr.ensureTotalCapacity(testing.allocator, 20);
1739+
1740+
// https://github.com/ianic/tls.zig/issues/10
1741+
for (0..1) |_| {
1742+
defer arr.clearRetainingCapacity();
1743+
var client = try testClient();
1744+
defer client.deinit();
1745+
1746+
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/redirect/insecure");
1747+
var res = try req.sendSync(.{});
1748+
1749+
while (try res.next()) |data| {
1750+
arr.appendSliceAssumeCapacity(data);
1751+
}
1752+
try testing.expectEqual(201, res.header.status);
1753+
try testing.expectEqual(4, res.header.count());
1754+
try testing.expectEqual("close", res.header.get("connection"));
1755+
try testing.expectEqual("10", res.header.get("content-length"));
1756+
try testing.expectEqual("127.0.0.1", res.header.get("_host"));
1757+
try testing.expectEqual("Close", res.header.get("_connection"));
1758+
}
1759+
}
1760+
1761+
test "HttpClient: sync redirect plaintext to TLS" {
1762+
var arr: std.ArrayListUnmanaged(u8) = .{};
1763+
defer arr.deinit(testing.allocator);
1764+
try arr.ensureTotalCapacity(testing.allocator, 20);
1765+
1766+
// https://github.com/ianic/tls.zig/issues/10
1767+
for (0..1) |_| {
1768+
defer arr.clearRetainingCapacity();
1769+
var client = try testClient();
1770+
defer client.deinit();
1771+
1772+
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/redirect/secure");
1773+
var res = try req.sendSync(.{});
1774+
1775+
while (try res.next()) |data| {
1776+
arr.appendSliceAssumeCapacity(data);
1777+
}
1778+
try testing.expectEqual(201, res.header.status);
1779+
try testing.expectEqual("1234567890abcdefhijk", arr.items);
1780+
try testing.expectEqual(2, res.header.count());
1781+
try testing.expectEqual("20", res.header.get("content-length"));
1782+
try testing.expectEqual("HEaDer", res.header.get("another"));
1783+
}
1784+
}
1785+
16771786
test "HttpClient: sync GET redirect" {
1678-
var client = try Client.init(testing.allocator, 2);
1787+
var client = try testClient();
16791788
defer client.deinit();
16801789

16811790
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/redirect");
@@ -1710,7 +1819,7 @@ test "HttpClient: async connect error" {
17101819
};
17111820

17121821
var reset: Thread.ResetEvent = .{};
1713-
var client = try Client.init(testing.allocator, 2);
1822+
var client = try testClient();
17141823
defer client.deinit();
17151824

17161825
var req = try client.request(.GET, "HTTP://127.0.0.1:9920");
@@ -1720,7 +1829,7 @@ test "HttpClient: async connect error" {
17201829
}
17211830

17221831
test "HttpClient: async no body" {
1723-
var client = try Client.init(testing.allocator, 2);
1832+
var client = try testClient();
17241833
defer client.deinit();
17251834

17261835
var handler = try CaptureHandler.init();
@@ -1731,26 +1840,44 @@ test "HttpClient: async no body" {
17311840

17321841
var req = try client.request(.GET, "HTTP://127.0.0.1:9582/http_client/simple");
17331842
try req.sendAsync(&handler.loop, &handler, .{});
1734-
try handler.loop.io.run_for_ns(std.time.ns_per_ms);
1735-
try handler.reset.timedWait(std.time.ns_per_s);
1843+
try handler.waitUntilDone();
17361844

17371845
const res = handler.response;
17381846
try testing.expectEqual("", res.body.items);
17391847
try testing.expectEqual(200, res.status);
17401848
try res.assertHeaders(&.{ "connection", "close", "content-length", "0" });
17411849
}
17421850

1851+
// test "HttpClient: async tls no body" {
1852+
// var client = try testClient();
1853+
// defer client.deinit();
1854+
1855+
// var handler = try CaptureHandler.init();
1856+
// defer handler.deinit();
1857+
1858+
// var loop = try jsruntime.Loop.init(testing.allocator);
1859+
// defer loop.deinit();
1860+
1861+
// var req = try client.request(.GET, "HTTPs://127.0.0.1:9581/http_client/simple");
1862+
// try req.sendAsync(&handler.loop, &handler, .{});
1863+
// try handler.waitUntilDone();
1864+
1865+
// const res = handler.response;
1866+
// try testing.expectEqual("", res.body.items);
1867+
// try testing.expectEqual(200, res.status);
1868+
// try res.assertHeaders(&.{ "connection", "close", "content-length", "0" });
1869+
// }
1870+
17431871
test "HttpClient: async with body" {
1744-
var client = try Client.init(testing.allocator, 2);
1872+
var client = try testClient();
17451873
defer client.deinit();
17461874

17471875
var handler = try CaptureHandler.init();
17481876
defer handler.deinit();
17491877

17501878
var req = try client.request(.GET, "HTTP://127.0.0.1:9582/http_client/echo");
17511879
try req.sendAsync(&handler.loop, &handler, .{});
1752-
try handler.loop.io.run_for_ns(std.time.ns_per_ms);
1753-
try handler.reset.timedWait(std.time.ns_per_s);
1880+
try handler.waitUntilDone();
17541881

17551882
const res = handler.response;
17561883
try testing.expectEqual("over 9000!", res.body.items);
@@ -1764,7 +1891,7 @@ test "HttpClient: async with body" {
17641891
}
17651892

17661893
test "HttpClient: async redirect" {
1767-
var client = try Client.init(testing.allocator, 2);
1894+
var client = try testClient();
17681895
defer client.deinit();
17691896

17701897
var handler = try CaptureHandler.init();
@@ -1781,8 +1908,7 @@ test "HttpClient: async redirect" {
17811908
// start to requeue events (from the redirected request), so we need the
17821909
//loop to process those also.
17831910
try handler.loop.io.run_for_ns(std.time.ns_per_ms);
1784-
try handler.loop.io.run_for_ns(std.time.ns_per_ms);
1785-
try handler.reset.timedWait(std.time.ns_per_s);
1911+
try handler.waitUntilDone();
17861912

17871913
const res = handler.response;
17881914
try testing.expectEqual("over 9000!", res.body.items);
@@ -1885,6 +2011,11 @@ const CaptureHandler = struct {
18852011
self.reset.set();
18862012
}
18872013
}
2014+
2015+
fn waitUntilDone(self: *CaptureHandler) !void {
2016+
try self.loop.io.run_for_ns(std.time.ns_per_ms);
2017+
try self.reset.timedWait(std.time.ns_per_s);
2018+
}
18882019
};
18892020

18902021
fn testReader(state: *State, res: *TestResponse, data: []const u8) !void {
@@ -1928,3 +2059,9 @@ fn testReader(state: *State, res: *TestResponse, data: []const u8) !void {
19282059
}
19292060
return error.NeverDone;
19302061
}
2062+
2063+
fn testClient() !Client {
2064+
const test_dir = try std.fs.cwd().openDir("tests", .{});
2065+
const root_ca = try tls.config.CertBundle.fromFile(testing.allocator, test_dir, "test_cert.pem");
2066+
return try Client.init(testing.allocator, 1, root_ca);
2067+
}

src/main_tests.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn testExecFn(
8888
std.debug.print("documentHTMLClose error: {s}\n", .{@errorName(err)});
8989
};
9090

91-
var http_client = try @import("http/client.zig").Client.init(alloc, 5);
91+
var http_client = try @import("http/client.zig").Client.init(alloc, 5, null);
9292
defer http_client.deinit();
9393

9494
try js_env.setUserContext(.{

0 commit comments

Comments
 (0)