authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-16 15:49:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-17 01:44:56-05:00
logd56a65a8c4609a740eee43fd7073c2485c87c2c6
tree9936fd3bcf55f9426d8a43425c6e092a95658022
parente646becd04c37fbaaa654f6419dd9f5e85d9f210

std.http.Client: default to lazy root cert scanning

After this change, the system will be inspected for root certificates only upon the first https request that actually occurs. This makes the compiler no longer do SSL certificate scanning when running `zig build` if no network requests are made.

2 files changed, 15 insertions(+), 5 deletions(-)

lib/std/http/Client.zig+15-4
......@@ -1,5 +1,7 @@
11//! TODO: send connection: keep-alive and LRU cache a configurable number of
22//! open connections to skip DNS and TLS handshake for subsequent requests.
3//!
4//! This API is *not* thread safe.
35
46const std = @import("../std.zig");
57const mem = std.mem;
......@@ -15,6 +17,9 @@ const testing = std.testing;
1517/// managed buffer is not provided.
1618allocator: Allocator,
1719ca_bundle: std.crypto.Certificate.Bundle = .{},
20/// When this is `true`, the next time this client performs an HTTPS request,
21/// it will first rescan the system for root certificates.
22next_https_rescan_certs: bool = true,
1823
1924pub const Connection = struct {
2025 stream: net.Stream,
......@@ -594,6 +599,7 @@ pub const Request = struct {
594599 CertificateTimeInvalid,
595600 CertificateHasUnrecognizedObjectId,
596601 CertificateHasInvalidBitString,
602 CertificateAuthorityBundleTooBig,
597603
598604 // TODO: convert to higher level errors
599605 InvalidFormat,
......@@ -648,6 +654,10 @@ pub const Request = struct {
648654 NetworkSubsystemFailed,
649655 NotDir,
650656 ReadOnlyFileSystem,
657 Unseekable,
658 MissingEndCertificateMarker,
659 InvalidPadding,
660 EndOfStream,
651661 };
652662
653663 pub fn read(req: *Request, buffer: []u8) ReadError!usize {
......@@ -837,10 +847,6 @@ pub fn deinit(client: *Client) void {
837847 client.* = undefined;
838848}
839849
840pub fn rescanRootCertificates(client: *Client) !void {
841 return client.ca_bundle.rescan(client.allocator);
842}
843
844850pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) !Connection {
845851 var conn: Connection = .{
846852 .stream = try net.tcpConnectToHost(client.allocator, host, port),
......@@ -876,6 +882,11 @@ pub fn request(client: *Client, uri: Uri, headers: Request.Headers, options: Req
876882
877883 const host = uri.host orelse return error.UriMissingHost;
878884
885 if (client.next_https_rescan_certs and protocol == .tls) {
886 try client.ca_bundle.rescan(client.allocator);
887 client.next_https_rescan_certs = false;
888 }
889
879890 var req: Request = .{
880891 .client = client,
881892 .headers = headers,
src/main.zig-1
......@@ -4098,7 +4098,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
40984098 if (!build_options.omit_pkg_fetching_code) {
40994099 var http_client: std.http.Client = .{ .allocator = gpa };
41004100 defer http_client.deinit();
4101 try http_client.rescanRootCertificates();
41024101
41034102 // Here we provide an import to the build runner that allows using reflection to find
41044103 // all of the dependencies. Without this, there would be no way to use `@import` to