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 @@...@@ -1,5 +1,7 @@
1//! TODO: send connection: keep-alive and LRU cache a configurable number of1//! TODO: send connection: keep-alive and LRU cache a configurable number of
2//! open connections to skip DNS and TLS handshake for subsequent requests.2//! open connections to skip DNS and TLS handshake for subsequent requests.
3//!
4//! This API is *not* thread safe.
35
4const std = @import("../std.zig");6const std = @import("../std.zig");
5const mem = std.mem;7const mem = std.mem;
...@@ -15,6 +17,9 @@ const testing = std.testing;...@@ -15,6 +17,9 @@ const testing = std.testing;
15/// managed buffer is not provided.17/// managed buffer is not provided.
16allocator: Allocator,18allocator: Allocator,
17ca_bundle: std.crypto.Certificate.Bundle = .{},19ca_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
19pub const Connection = struct {24pub const Connection = struct {
20 stream: net.Stream,25 stream: net.Stream,
...@@ -594,6 +599,7 @@ pub const Request = struct {...@@ -594,6 +599,7 @@ pub const Request = struct {
594 CertificateTimeInvalid,599 CertificateTimeInvalid,
595 CertificateHasUnrecognizedObjectId,600 CertificateHasUnrecognizedObjectId,
596 CertificateHasInvalidBitString,601 CertificateHasInvalidBitString,
602 CertificateAuthorityBundleTooBig,
597603
598 // TODO: convert to higher level errors604 // TODO: convert to higher level errors
599 InvalidFormat,605 InvalidFormat,
...@@ -648,6 +654,10 @@ pub const Request = struct {...@@ -648,6 +654,10 @@ pub const Request = struct {
648 NetworkSubsystemFailed,654 NetworkSubsystemFailed,
649 NotDir,655 NotDir,
650 ReadOnlyFileSystem,656 ReadOnlyFileSystem,
657 Unseekable,
658 MissingEndCertificateMarker,
659 InvalidPadding,
660 EndOfStream,
651 };661 };
652662
653 pub fn read(req: *Request, buffer: []u8) ReadError!usize {663 pub fn read(req: *Request, buffer: []u8) ReadError!usize {
...@@ -837,10 +847,6 @@ pub fn deinit(client: *Client) void {...@@ -837,10 +847,6 @@ pub fn deinit(client: *Client) void {
837 client.* = undefined;847 client.* = undefined;
838}848}
839849
840pub fn rescanRootCertificates(client: *Client) !void {
841 return client.ca_bundle.rescan(client.allocator);
842}
843
844pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) !Connection {850pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) !Connection {
845 var conn: Connection = .{851 var conn: Connection = .{
846 .stream = try net.tcpConnectToHost(client.allocator, host, port),852 .stream = try net.tcpConnectToHost(client.allocator, host, port),
...@@ -876,6 +882,11 @@ pub fn request(client: *Client, uri: Uri, headers: Request.Headers, options: Req...@@ -876,6 +882,11 @@ pub fn request(client: *Client, uri: Uri, headers: Request.Headers, options: Req
876882
877 const host = uri.host orelse return error.UriMissingHost;883 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
879 var req: Request = .{890 var req: Request = .{
880 .client = client,891 .client = client,
881 .headers = headers,892 .headers = headers,
src/main.zig-1
...@@ -4098,7 +4098,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4098,7 +4098,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4098 if (!build_options.omit_pkg_fetching_code) {4098 if (!build_options.omit_pkg_fetching_code) {
4099 var http_client: std.http.Client = .{ .allocator = gpa };4099 var http_client: std.http.Client = .{ .allocator = gpa };
4100 defer http_client.deinit();4100 defer http_client.deinit();
4101 try http_client.rescanRootCertificates();
41024101
4103 // Here we provide an import to the build runner that allows using reflection to find4102 // Here we provide an import to the build runner that allows using reflection to find
4104 // all of the dependencies. Without this, there would be no way to use `@import` to4103 // all of the dependencies. Without this, there would be no way to use `@import` to