mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-30 07:31:47 +00:00
Switch to nonblocking socket
Improve test server handshake performance, allowing for a few more fuzz iterations without making tests unbearably slow.
This commit is contained in:
@@ -38,7 +38,7 @@ pub const App = struct {
|
||||
.allocator = allocator,
|
||||
.telemetry = undefined,
|
||||
.app_dir_path = app_dir_path,
|
||||
.http_client = try HttpClient.init(allocator, 5, null),
|
||||
.http_client = try HttpClient.init(allocator, 5),
|
||||
};
|
||||
app.telemetry = Telemetry.init(app, run_mode);
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ pub const Client = struct {
|
||||
root_ca: tls.config.CertBundle,
|
||||
|
||||
// we only allow passing in a root_ca for testing
|
||||
pub fn init(allocator: Allocator, max_concurrent: usize, root_ca_: ?tls.config.CertBundle) !Client {
|
||||
var root_ca = root_ca_ orelse try tls.config.CertBundle.fromSystem(allocator);
|
||||
pub fn init(allocator: Allocator, max_concurrent: usize) !Client {
|
||||
var root_ca = try tls.config.CertBundle.fromSystem(allocator);
|
||||
errdefer root_ca.deinit(allocator);
|
||||
|
||||
const state_pool = try StatePool.init(allocator, max_concurrent);
|
||||
@@ -123,6 +123,9 @@ pub const Request = struct {
|
||||
// we'll set it based on `uri` before issuing the request.
|
||||
_has_host_header: bool,
|
||||
|
||||
// Whether or not we should verify that the host matches the certificate CN
|
||||
_tls_verify_host: bool = true,
|
||||
|
||||
pub const Method = enum {
|
||||
GET,
|
||||
PUT,
|
||||
@@ -202,9 +205,12 @@ pub const Request = struct {
|
||||
}
|
||||
|
||||
// TODO timeout
|
||||
const SendSyncOpts = struct {};
|
||||
const SendSyncOpts = struct {
|
||||
tls_verify_host: bool = true,
|
||||
};
|
||||
// Makes an synchronous request
|
||||
pub fn sendSync(self: *Request, _: SendSyncOpts) anyerror!Response {
|
||||
pub fn sendSync(self: *Request, opts: SendSyncOpts) anyerror!Response {
|
||||
self._tls_verify_host = opts.tls_verify_host;
|
||||
try self.prepareInitialSend();
|
||||
return self.doSendSync();
|
||||
}
|
||||
@@ -224,9 +230,12 @@ pub const Request = struct {
|
||||
};
|
||||
}
|
||||
|
||||
const SendAsyncOpts = struct {};
|
||||
const SendAsyncOpts = struct {
|
||||
tls_verify_host: bool = true,
|
||||
};
|
||||
// Makes an asynchronous request
|
||||
pub fn sendAsync(self: *Request, loop: anytype, handler: anytype, _: SendAsyncOpts) !void {
|
||||
pub fn sendAsync(self: *Request, loop: anytype, handler: anytype, opts: SendAsyncOpts) !void {
|
||||
self._tls_verify_host = opts.tls_verify_host;
|
||||
try self.prepareInitialSend();
|
||||
return self.doSendAsync(loop, handler);
|
||||
}
|
||||
@@ -236,8 +245,7 @@ pub const Request = struct {
|
||||
}
|
||||
|
||||
fn doSendAsync(self: *Request, loop: anytype, handler: anytype) !void {
|
||||
// TODO: change this to nonblocking (false) when we have promise resolution
|
||||
const socket, const address = try self.createSocket(true);
|
||||
const socket, const address = try self.createSocket(false);
|
||||
const AsyncHandlerT = AsyncHandler(@TypeOf(handler), @TypeOf(loop));
|
||||
const async_handler = try self.arena.create(AsyncHandlerT);
|
||||
|
||||
@@ -256,6 +264,7 @@ pub const Request = struct {
|
||||
.tls_client = try tls.asyn.Client(AsyncHandlerT.TLSHandler).init(self.arena, .{ .handler = async_handler }, .{
|
||||
.host = self.host(),
|
||||
.root_ca = self._client.root_ca,
|
||||
.insecure_skip_verify = self._tls_verify_host == false,
|
||||
// .key_log_callback = tls.config.key_log.callback
|
||||
}),
|
||||
};
|
||||
@@ -367,6 +376,7 @@ pub const Request = struct {
|
||||
if (@hasDecl(posix.TCP, "NODELAY")) {
|
||||
try posix.setsockopt(socket, posix.IPPROTO.TCP, posix.TCP.NODELAY, &std.mem.toBytes(@as(c_int, 1)));
|
||||
}
|
||||
|
||||
self._socket = socket;
|
||||
return .{ socket, address };
|
||||
}
|
||||
@@ -544,7 +554,6 @@ fn AsyncHandler(comptime H: type, comptime L: type) type {
|
||||
const n = n_ catch |err| {
|
||||
return self.handleError("Read error", err);
|
||||
};
|
||||
|
||||
if (n == 0) {
|
||||
return self.handleError("Connection closed", error.ConnectionResetByPeer);
|
||||
}
|
||||
@@ -662,12 +671,12 @@ fn AsyncHandler(comptime H: type, comptime L: type) type {
|
||||
|
||||
switch (self.protocol) {
|
||||
.tls_client => |*tls_client| {
|
||||
handler.receive();
|
||||
try tls_client.onConnect();
|
||||
// when TLS is active, from a network point of view
|
||||
// it's no longer a strict REQ->RES. We pretty much
|
||||
// have to constantly receive data (e.g. to process
|
||||
// the handshake)
|
||||
handler.receive();
|
||||
},
|
||||
.plain => {
|
||||
// queue everything up
|
||||
@@ -847,6 +856,7 @@ const SyncHandler = struct {
|
||||
.tls = try tls.client(std.net.Stream{ .handle = socket }, .{
|
||||
.host = request.host(),
|
||||
.root_ca = request._client.root_ca,
|
||||
.insecure_skip_verify = request._tls_verify_host == false,
|
||||
// .key_log_callback = tls.config.key_log.callback,
|
||||
}),
|
||||
};
|
||||
@@ -1704,13 +1714,12 @@ test "HttpClient: sync no body" {
|
||||
}
|
||||
|
||||
test "HttpClient: sync tls no body" {
|
||||
// https://github.com/ianic/tls.zig/issues/10
|
||||
for (0..1) |_| {
|
||||
for (0..5) |_| {
|
||||
var client = try testClient();
|
||||
defer client.deinit();
|
||||
|
||||
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/simple");
|
||||
var res = try req.sendSync(.{});
|
||||
var res = try req.sendSync(.{ .tls_verify_host = false });
|
||||
|
||||
try testing.expectEqual(null, try res.next());
|
||||
try testing.expectEqual(200, res.header.status);
|
||||
@@ -1741,14 +1750,13 @@ test "HttpClient: sync tls with body" {
|
||||
defer arr.deinit(testing.allocator);
|
||||
try arr.ensureTotalCapacity(testing.allocator, 20);
|
||||
|
||||
// https://github.com/ianic/tls.zig/issues/10
|
||||
for (0..1) |_| {
|
||||
for (0..5) |_| {
|
||||
defer arr.clearRetainingCapacity();
|
||||
var client = try testClient();
|
||||
defer client.deinit();
|
||||
|
||||
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/body");
|
||||
var res = try req.sendSync(.{});
|
||||
var res = try req.sendSync(.{ .tls_verify_host = false });
|
||||
|
||||
while (try res.next()) |data| {
|
||||
arr.appendSliceAssumeCapacity(data);
|
||||
@@ -1766,14 +1774,13 @@ test "HttpClient: sync redirect from TLS to Plaintext" {
|
||||
defer arr.deinit(testing.allocator);
|
||||
try arr.ensureTotalCapacity(testing.allocator, 20);
|
||||
|
||||
// https://github.com/ianic/tls.zig/issues/10
|
||||
for (0..1) |_| {
|
||||
for (0..5) |_| {
|
||||
defer arr.clearRetainingCapacity();
|
||||
var client = try testClient();
|
||||
defer client.deinit();
|
||||
|
||||
var req = try client.request(.GET, "https://127.0.0.1:9581/http_client/redirect/insecure");
|
||||
var res = try req.sendSync(.{});
|
||||
var res = try req.sendSync(.{ .tls_verify_host = false });
|
||||
|
||||
while (try res.next()) |data| {
|
||||
arr.appendSliceAssumeCapacity(data);
|
||||
@@ -1793,14 +1800,13 @@ test "HttpClient: sync redirect plaintext to TLS" {
|
||||
defer arr.deinit(testing.allocator);
|
||||
try arr.ensureTotalCapacity(testing.allocator, 20);
|
||||
|
||||
// https://github.com/ianic/tls.zig/issues/10
|
||||
for (0..1) |_| {
|
||||
for (0..5) |_| {
|
||||
defer arr.clearRetainingCapacity();
|
||||
var client = try testClient();
|
||||
defer client.deinit();
|
||||
|
||||
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/redirect/secure");
|
||||
var res = try req.sendSync(.{});
|
||||
var res = try req.sendSync(.{ .tls_verify_host = false });
|
||||
|
||||
while (try res.next()) |data| {
|
||||
arr.appendSliceAssumeCapacity(data);
|
||||
@@ -1818,7 +1824,7 @@ test "HttpClient: sync GET redirect" {
|
||||
defer client.deinit();
|
||||
|
||||
var req = try client.request(.GET, "http://127.0.0.1:9582/http_client/redirect");
|
||||
var res = try req.sendSync(.{});
|
||||
var res = try req.sendSync(.{ .tls_verify_host = false });
|
||||
|
||||
try testing.expectEqual("over 9000!", try res.next());
|
||||
try testing.expectEqual(201, res.header.status);
|
||||
@@ -1866,9 +1872,6 @@ test "HttpClient: async no body" {
|
||||
var handler = try CaptureHandler.init();
|
||||
defer handler.deinit();
|
||||
|
||||
var loop = try jsruntime.Loop.init(testing.allocator);
|
||||
defer loop.deinit();
|
||||
|
||||
var req = try client.request(.GET, "HTTP://127.0.0.1:9582/http_client/simple");
|
||||
try req.sendAsync(&handler.loop, &handler, .{});
|
||||
try handler.waitUntilDone();
|
||||
@@ -1886,11 +1889,8 @@ test "HttpClient: async no body" {
|
||||
// var handler = try CaptureHandler.init();
|
||||
// defer handler.deinit();
|
||||
|
||||
// var loop = try jsruntime.Loop.init(testing.allocator);
|
||||
// defer loop.deinit();
|
||||
|
||||
// var req = try client.request(.GET, "HTTPs://127.0.0.1:9581/http_client/simple");
|
||||
// try req.sendAsync(&handler.loop, &handler, .{});
|
||||
// try req.sendAsync(&handler.loop, &handler, .{ .tls_verify_host = false });
|
||||
// try handler.waitUntilDone();
|
||||
|
||||
// const res = handler.response;
|
||||
@@ -1929,9 +1929,6 @@ test "HttpClient: async redirect" {
|
||||
var handler = try CaptureHandler.init();
|
||||
defer handler.deinit();
|
||||
|
||||
var loop = try jsruntime.Loop.init(testing.allocator);
|
||||
defer loop.deinit();
|
||||
|
||||
var req = try client.request(.GET, "HTTP://127.0.0.1:9582/http_client/redirect");
|
||||
try req.sendAsync(&handler.loop, &handler, .{});
|
||||
|
||||
@@ -2094,7 +2091,5 @@ fn testReader(state: *State, res: *TestResponse, data: []const u8) !void {
|
||||
}
|
||||
|
||||
fn testClient() !Client {
|
||||
const test_dir = try std.fs.cwd().openDir("tests", .{});
|
||||
const root_ca = try tls.config.CertBundle.fromFile(testing.allocator, test_dir, "test_cert.pem");
|
||||
return try Client.init(testing.allocator, 1, root_ca);
|
||||
return try Client.init(testing.allocator, 1);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ fn testExecFn(
|
||||
std.debug.print("documentHTMLClose error: {s}\n", .{@errorName(err)});
|
||||
};
|
||||
|
||||
var http_client = try @import("http/client.zig").Client.init(alloc, 5, null );
|
||||
var http_client = try @import("http/client.zig").Client.init(alloc, 5);
|
||||
defer http_client.deinit();
|
||||
|
||||
try js_env.setUserContext(.{
|
||||
|
||||
@@ -52,13 +52,13 @@ test "tests:beforeAll" {
|
||||
|
||||
{
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 9582);
|
||||
const thread = try std.Thread.spawn(.{}, serveHTTP, .{ address });
|
||||
const thread = try std.Thread.spawn(.{}, serveHTTP, .{address});
|
||||
thread.detach();
|
||||
}
|
||||
|
||||
{
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 9581);
|
||||
const thread = try std.Thread.spawn(.{}, serveHTTPS, .{ address });
|
||||
const thread = try std.Thread.spawn(.{}, serveHTTPS, .{address});
|
||||
thread.detach();
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ test "tests:beforeAll" {
|
||||
const thread = try std.Thread.spawn(.{}, serveCDP, .{address});
|
||||
thread.detach();
|
||||
}
|
||||
|
||||
// need to wait for the servers to be listening, else tests will fail because
|
||||
// they aren't able to connect.
|
||||
wg.wait();
|
||||
@@ -144,11 +145,6 @@ fn serveHTTP(address: std.net.Address) !void {
|
||||
// isn't a jerk.
|
||||
fn serveHTTPS(address: std.net.Address) !void {
|
||||
const allocator = gpa.allocator();
|
||||
const test_dir = try std.fs.cwd().openDir("tests", .{});
|
||||
|
||||
// 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"
|
||||
var auth = try tls.config.CertKeyPair.load(allocator, test_dir, "test_cert.pem", "test_key.pem");
|
||||
defer auth.deinit(allocator);
|
||||
|
||||
var listener = try address.listen(.{ .reuse_address = true });
|
||||
defer listener.deinit();
|
||||
@@ -174,7 +170,7 @@ fn serveHTTPS(address: std.net.Address) !void {
|
||||
};
|
||||
defer stream.close();
|
||||
|
||||
var conn = try tls.server(stream, .{ .auth = &auth });
|
||||
var conn = try tls.server(stream, .{ .auth = null });
|
||||
defer conn.close() catch {};
|
||||
|
||||
var pos: usize = 0;
|
||||
@@ -208,7 +204,7 @@ fn serveHTTPS(address: std.net.Address) !void {
|
||||
const to_send = rand.intRangeAtMost(usize, 1, unsent.len);
|
||||
const sent = try conn.write(unsent[0..to_send]);
|
||||
unsent = unsent[sent..];
|
||||
// std.time.sleep(std.time.ns_per_us * 5);
|
||||
std.time.sleep(std.time.ns_per_us * 5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ const Loop = jsruntime.Loop;
|
||||
const Env = jsruntime.Env;
|
||||
const Window = @import("../html/window.zig").Window;
|
||||
const storage = @import("../storage/storage.zig");
|
||||
const Client = @import("asyncio").Client;
|
||||
const HttpClient = @import("../http/client.zig").Client;
|
||||
|
||||
const Types = @import("../main_wpt.zig").Types;
|
||||
const UserContext = @import("../main_wpt.zig").UserContext;
|
||||
@@ -55,13 +55,13 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
|
||||
var loop = try Loop.init(alloc);
|
||||
defer loop.deinit();
|
||||
|
||||
var cli = Client{ .allocator = alloc };
|
||||
defer cli.deinit();
|
||||
var http_client = try HttpClient.init(alloc, 2);
|
||||
defer http_client.deinit();
|
||||
|
||||
var js_env: Env = undefined;
|
||||
Env.init(&js_env, alloc, &loop, UserContext{
|
||||
.document = html_doc,
|
||||
.httpClient = &cli,
|
||||
.http_client = &http_client,
|
||||
});
|
||||
defer js_env.deinit();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user