Skip to content

Commit 2a0d1b0

Browse files
committed
Switch to nonblocking socket
Improve test server handshake performance, allowing for a few more fuzz iterations without making tests unbearably slow.
1 parent 22aa126 commit 2a0d1b0

File tree

7 files changed

+42
-132
lines changed

7 files changed

+42
-132
lines changed

src/app.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub const App = struct {
3838
.allocator = allocator,
3939
.telemetry = undefined,
4040
.app_dir_path = app_dir_path,
41-
.http_client = try HttpClient.init(allocator, 5, null),
41+
.http_client = try HttpClient.init(allocator, 5),
4242
};
4343
app.telemetry = Telemetry.init(app, run_mode);
4444

src/http/client.zig

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ pub const Client = struct {
4848
root_ca: tls.config.CertBundle,
4949

5050
// 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);
51+
pub fn init(allocator: Allocator, max_concurrent: usize) !Client {
52+
var root_ca = try tls.config.CertBundle.fromSystem(allocator);
5353
errdefer root_ca.deinit(allocator);
5454

5555
const state_pool = try StatePool.init(allocator, max_concurrent);
@@ -123,6 +123,9 @@ pub const Request = struct {
123123
// we'll set it based on `uri` before issuing the request.
124124
_has_host_header: bool,
125125

126+
// Whether or not we should verify that the host matches the certificate CN
127+
_tls_verify_host: bool = true,
128+
126129
pub const Method = enum {
127130
GET,
128131
PUT,
@@ -202,9 +205,12 @@ pub const Request = struct {
202205
}
203206

204207
// TODO timeout
205-
const SendSyncOpts = struct {};
208+
const SendSyncOpts = struct {
209+
tls_verify_host: bool = true,
210+
};
206211
// Makes an synchronous request
207-
pub fn sendSync(self: *Request, _: SendSyncOpts) anyerror!Response {
212+
pub fn sendSync(self: *Request, opts: SendSyncOpts) anyerror!Response {
213+
self._tls_verify_host = opts.tls_verify_host;
208214
try self.prepareInitialSend();
209215
return self.doSendSync();
210216
}
@@ -224,9 +230,12 @@ pub const Request = struct {
224230
};
225231
}
226232

227-
const SendAsyncOpts = struct {};
233+
const SendAsyncOpts = struct {
234+
tls_verify_host: bool = true,
235+
};
228236
// Makes an asynchronous request
229-
pub fn sendAsync(self: *Request, loop: anytype, handler: anytype, _: SendAsyncOpts) !void {
237+
pub fn sendAsync(self: *Request, loop: anytype, handler: anytype, opts: SendAsyncOpts) !void {
238+
self._tls_verify_host = opts.tls_verify_host;
230239
try self.prepareInitialSend();
231240
return self.doSendAsync(loop, handler);
232241
}
@@ -236,8 +245,7 @@ pub const Request = struct {
236245
}
237246

238247
fn doSendAsync(self: *Request, loop: anytype, handler: anytype) !void {
239-
// TODO: change this to nonblocking (false) when we have promise resolution
240-
const socket, const address = try self.createSocket(true);
248+
const socket, const address = try self.createSocket(false);
241249
const AsyncHandlerT = AsyncHandler(@TypeOf(handler), @TypeOf(loop));
242250
const async_handler = try self.arena.create(AsyncHandlerT);
243251

@@ -256,6 +264,7 @@ pub const Request = struct {
256264
.tls_client = try tls.asyn.Client(AsyncHandlerT.TLSHandler).init(self.arena, .{ .handler = async_handler }, .{
257265
.host = self.host(),
258266
.root_ca = self._client.root_ca,
267+
.insecure_skip_verify = self._tls_verify_host == false,
259268
// .key_log_callback = tls.config.key_log.callback
260269
}),
261270
};
@@ -367,6 +376,7 @@ pub const Request = struct {
367376
if (@hasDecl(posix.TCP, "NODELAY")) {
368377
try posix.setsockopt(socket, posix.IPPROTO.TCP, posix.TCP.NODELAY, &std.mem.toBytes(@as(c_int, 1)));
369378
}
379+
370380
self._socket = socket;
371381
return .{ socket, address };
372382
}
@@ -544,7 +554,6 @@ fn AsyncHandler(comptime H: type, comptime L: type) type {
544554
const n = n_ catch |err| {
545555
return self.handleError("Read error", err);
546556
};
547-
548557
if (n == 0) {
549558
return self.handleError("Connection closed", error.ConnectionResetByPeer);
550559
}
@@ -662,12 +671,12 @@ fn AsyncHandler(comptime H: type, comptime L: type) type {
662671

663672
switch (self.protocol) {
664673
.tls_client => |*tls_client| {
674+
handler.receive();
665675
try tls_client.onConnect();
666676
// when TLS is active, from a network point of view
667677
// it's no longer a strict REQ->RES. We pretty much
668678
// have to constantly receive data (e.g. to process
669679
// the handshake)
670-
handler.receive();
671680
},
672681
.plain => {
673682
// queue everything up
@@ -847,6 +856,7 @@ const SyncHandler = struct {
847856
.tls = try tls.client(std.net.Stream{ .handle = socket }, .{
848857
.host = request.host(),
849858
.root_ca = request._client.root_ca,
859+
.insecure_skip_verify = request._tls_verify_host == false,
850860
// .key_log_callback = tls.config.key_log.callback,
851861
}),
852862
};
@@ -1704,13 +1714,12 @@ test "HttpClient: sync no body" {
17041714
}
17051715

17061716
test "HttpClient: sync tls no body" {
1707-
// https://github.com/ianic/tls.zig/issues/10
1708-
for (0..1) |_| {
1717+
for (0..5) |_| {
17091718
var client = try testClient();
17101719
defer client.deinit();
17111720

17121721
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/simple");
1713-
var res = try req.sendSync(.{});
1722+
var res = try req.sendSync(.{ .tls_verify_host = false });
17141723

17151724
try testing.expectEqual(null, try res.next());
17161725
try testing.expectEqual(200, res.header.status);
@@ -1741,14 +1750,13 @@ test "HttpClient: sync tls with body" {
17411750
defer arr.deinit(testing.allocator);
17421751
try arr.ensureTotalCapacity(testing.allocator, 20);
17431752

1744-
// https://github.com/ianic/tls.zig/issues/10
1745-
for (0..1) |_| {
1753+
for (0..5) |_| {
17461754
defer arr.clearRetainingCapacity();
17471755
var client = try testClient();
17481756
defer client.deinit();
17491757

17501758
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/body");
1751-
var res = try req.sendSync(.{});
1759+
var res = try req.sendSync(.{ .tls_verify_host = false });
17521760

17531761
while (try res.next()) |data| {
17541762
arr.appendSliceAssumeCapacity(data);
@@ -1766,14 +1774,13 @@ test "HttpClient: sync redirect from TLS to Plaintext" {
17661774
defer arr.deinit(testing.allocator);
17671775
try arr.ensureTotalCapacity(testing.allocator, 20);
17681776

1769-
// https://github.com/ianic/tls.zig/issues/10
1770-
for (0..1) |_| {
1777+
for (0..5) |_| {
17711778
defer arr.clearRetainingCapacity();
17721779
var client = try testClient();
17731780
defer client.deinit();
17741781

17751782
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/redirect/insecure");
1776-
var res = try req.sendSync(.{});
1783+
var res = try req.sendSync(.{ .tls_verify_host = false });
17771784

17781785
while (try res.next()) |data| {
17791786
arr.appendSliceAssumeCapacity(data);
@@ -1793,14 +1800,13 @@ test "HttpClient: sync redirect plaintext to TLS" {
17931800
defer arr.deinit(testing.allocator);
17941801
try arr.ensureTotalCapacity(testing.allocator, 20);
17951802

1796-
// https://github.com/ianic/tls.zig/issues/10
1797-
for (0..1) |_| {
1803+
for (0..5) |_| {
17981804
defer arr.clearRetainingCapacity();
17991805
var client = try testClient();
18001806
defer client.deinit();
18011807

18021808
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/redirect/secure");
1803-
var res = try req.sendSync(.{});
1809+
var res = try req.sendSync(.{ .tls_verify_host = false });
18041810

18051811
while (try res.next()) |data| {
18061812
arr.appendSliceAssumeCapacity(data);
@@ -1818,7 +1824,7 @@ test "HttpClient: sync GET redirect" {
18181824
defer client.deinit();
18191825

18201826
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/redirect");
1821-
var res = try req.sendSync(.{});
1827+
var res = try req.sendSync(.{ .tls_verify_host = false });
18221828

18231829
try testing.expectEqual("over 9000!", try res.next());
18241830
try testing.expectEqual(201, res.header.status);
@@ -1866,9 +1872,6 @@ test "HttpClient: async no body" {
18661872
var handler = try CaptureHandler.init();
18671873
defer handler.deinit();
18681874

1869-
var loop = try jsruntime.Loop.init(testing.allocator);
1870-
defer loop.deinit();
1871-
18721875
var req = try client.request(.GET, "HTTP://127.0.0.1:9582/http_client/simple");
18731876
try req.sendAsync(&handler.loop, &handler, .{});
18741877
try handler.waitUntilDone();
@@ -1886,11 +1889,8 @@ test "HttpClient: async no body" {
18861889
// var handler = try CaptureHandler.init();
18871890
// defer handler.deinit();
18881891

1889-
// var loop = try jsruntime.Loop.init(testing.allocator);
1890-
// defer loop.deinit();
1891-
18921892
// var req = try client.request(.GET, "HTTPs://127.0.0.1:9581/http_client/simple");
1893-
// try req.sendAsync(&handler.loop, &handler, .{});
1893+
// try req.sendAsync(&handler.loop, &handler, .{ .tls_verify_host = false });
18941894
// try handler.waitUntilDone();
18951895

18961896
// const res = handler.response;
@@ -1929,9 +1929,6 @@ test "HttpClient: async redirect" {
19291929
var handler = try CaptureHandler.init();
19301930
defer handler.deinit();
19311931

1932-
var loop = try jsruntime.Loop.init(testing.allocator);
1933-
defer loop.deinit();
1934-
19351932
var req = try client.request(.GET, "HTTP://127.0.0.1:9582/http_client/redirect");
19361933
try req.sendAsync(&handler.loop, &handler, .{});
19371934

@@ -2094,7 +2091,5 @@ fn testReader(state: *State, res: *TestResponse, data: []const u8) !void {
20942091
}
20952092

20962093
fn testClient() !Client {
2097-
const test_dir = try std.fs.cwd().openDir("tests", .{});
2098-
const root_ca = try tls.config.CertBundle.fromFile(testing.allocator, test_dir, "test_cert.pem");
2099-
return try Client.init(testing.allocator, 1, root_ca);
2094+
return try Client.init(testing.allocator, 1);
21002095
}

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

9494
try js_env.setUserContext(.{

src/main_unit_tests.zig

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ test "tests:beforeAll" {
5252

5353
{
5454
const address = try std.net.Address.parseIp("127.0.0.1", 9582);
55-
const thread = try std.Thread.spawn(.{}, serveHTTP, .{ address });
55+
const thread = try std.Thread.spawn(.{}, serveHTTP, .{address});
5656
thread.detach();
5757
}
5858

5959
{
6060
const address = try std.net.Address.parseIp("127.0.0.1", 9581);
61-
const thread = try std.Thread.spawn(.{}, serveHTTPS, .{ address });
61+
const thread = try std.Thread.spawn(.{}, serveHTTPS, .{address});
6262
thread.detach();
6363
}
6464

@@ -67,6 +67,7 @@ test "tests:beforeAll" {
6767
const thread = try std.Thread.spawn(.{}, serveCDP, .{address});
6868
thread.detach();
6969
}
70+
7071
// need to wait for the servers to be listening, else tests will fail because
7172
// they aren't able to connect.
7273
wg.wait();
@@ -144,11 +145,6 @@ fn serveHTTP(address: std.net.Address) !void {
144145
// isn't a jerk.
145146
fn serveHTTPS(address: std.net.Address) !void {
146147
const allocator = gpa.allocator();
147-
const test_dir = try std.fs.cwd().openDir("tests", .{});
148-
149-
// openssl req -x509 -newkey rsa:4096 -keyout tests/test_key.pem -out tests/test_cert.pem -sha256 -days 3650 -nodes -subj "/CN=127.0.0.1"
150-
var auth = try tls.config.CertKeyPair.load(allocator, test_dir, "test_cert.pem", "test_key.pem");
151-
defer auth.deinit(allocator);
152148

153149
var listener = try address.listen(.{ .reuse_address = true });
154150
defer listener.deinit();
@@ -174,7 +170,7 @@ fn serveHTTPS(address: std.net.Address) !void {
174170
};
175171
defer stream.close();
176172

177-
var conn = try tls.server(stream, .{ .auth = &auth });
173+
var conn = try tls.server(stream, .{ .auth = null });
178174
defer conn.close() catch {};
179175

180176
var pos: usize = 0;
@@ -208,7 +204,7 @@ fn serveHTTPS(address: std.net.Address) !void {
208204
const to_send = rand.intRangeAtMost(usize, 1, unsent.len);
209205
const sent = try conn.write(unsent[0..to_send]);
210206
unsent = unsent[sent..];
211-
// std.time.sleep(std.time.ns_per_us * 5);
207+
std.time.sleep(std.time.ns_per_us * 5);
212208
}
213209
break;
214210
}

src/wpt/run.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const Loop = jsruntime.Loop;
2828
const Env = jsruntime.Env;
2929
const Window = @import("../html/window.zig").Window;
3030
const storage = @import("../storage/storage.zig");
31-
const Client = @import("asyncio").Client;
31+
const HttpClient = @import("../http/client.zig").Client;
3232

3333
const Types = @import("../main_wpt.zig").Types;
3434
const UserContext = @import("../main_wpt.zig").UserContext;
@@ -55,13 +55,13 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
5555
var loop = try Loop.init(alloc);
5656
defer loop.deinit();
5757

58-
var cli = Client{ .allocator = alloc };
59-
defer cli.deinit();
58+
var http_client = try HttpClient.init(alloc, 2);
59+
defer http_client.deinit();
6060

6161
var js_env: Env = undefined;
6262
Env.init(&js_env, alloc, &loop, UserContext{
6363
.document = html_doc,
64-
.httpClient = &cli,
64+
.http_client = &http_client,
6565
});
6666
defer js_env.deinit();
6767

tests/test_cert.pem

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)