From 227c33e2db4af37606bccc056815da609bdab064 Mon Sep 17 00:00:00 2001 From: jiacai2050 Date: Sun, 21 Jan 2024 19:56:42 +0800 Subject: [PATCH] use build_info to determine if use system ca bundle --- Makefile | 6 ++-- build.zig | 24 +++++++++---- examples/advanced.zig | 3 -- src/c.zig | 80 ------------------------------------------- src/easy.zig | 9 ++--- src/errors.zig | 2 +- src/root.zig | 11 +++--- src/util.zig | 80 ++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 112 insertions(+), 103 deletions(-) delete mode 100644 src/c.zig diff --git a/Makefile b/Makefile index 99b8927..67cfa42 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,11 @@ clean: rm -rf zig-cache zig-out run: - zig build run-basic -freference-trace - zig build run-advanced -freference-trace + zig build run-basic -freference-trace -Dlink_vendor + zig build run-advanced -freference-trace -Dlink_vendor test: - zig build test + zig build test -Dlink_vendor docs: zig build-lib -femit-docs src/root.zig diff --git a/build.zig b/build.zig index 5956a94..b2d3cba 100644 --- a/build.zig +++ b/build.zig @@ -11,13 +11,18 @@ pub fn build(b: *Build) void { const optimize = b.standardOptimizeOption(.{}); const link_vendor = b.option(bool, "link_vendor", "Whether link with vendored libcurl"); - const libcurl = buildLibcurl(b, target, optimize); + const build_info = b.addOptions(); + build_info.addOption(bool, "link_vendor", link_vendor orelse false); const module = b.addModule(MODULE_NAME, .{ .root_source_file = .{ .path = "src/root.zig" }, }); + module.addOptions("build_info", build_info); + + var libcurl: ?*Step.Compile = null; if (link_vendor) |link| { if (link) { - module.linkLibrary(libcurl); + libcurl = buildLibcurl(b, target, optimize); + module.linkLibrary(libcurl.?); } } @@ -30,8 +35,11 @@ pub fn build(b: *Build) void { .optimize = optimize, }); - main_tests.linkLibrary(libcurl); - main_tests.linkLibC(); + if (libcurl) |lib| { + main_tests.linkLibrary(lib); + } else { + main_tests.linkSystemLibrary("curl"); + } const run_main_tests = b.addRunArtifact(main_tests); const test_step = b.step("test", "Run library tests"); @@ -53,7 +61,7 @@ fn addExample( b: *Build, comptime name: []const u8, curl_module: *Module, - libcurl: *Step.Compile, + libcurl: ?*Step.Compile, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, ) !void { @@ -66,7 +74,11 @@ fn addExample( b.installArtifact(exe); exe.root_module.addImport(MODULE_NAME, curl_module); - exe.linkLibrary(libcurl); + if (libcurl) |lib| { + exe.linkLibrary(lib); + } else { + exe.linkSystemLibrary("curl"); + } exe.linkLibC(); const run_step = b.step( diff --git a/examples/advanced.zig b/examples/advanced.zig index c958e74..b4f97f2 100644 --- a/examples/advanced.zig +++ b/examples/advanced.zig @@ -70,9 +70,6 @@ fn put_with_custom_header(allocator: Allocator, easy: Easy) !void { }, ); - if (!curl.has_parse_header_support()) { - return; - } // Get response header `date`. const date_header = try resp.get_header("date"); if (date_header) |h| { diff --git a/src/c.zig b/src/c.zig deleted file mode 100644 index 22b55e6..0000000 --- a/src/c.zig +++ /dev/null @@ -1,80 +0,0 @@ -const std = @import("std"); -pub const c = @cImport({ - @cInclude("curl/curl.h"); -}); - -pub fn print_libcurl_version() void { - const v = c.curl_version_info(c.CURLVERSION_NOW); - std.debug.print( - \\Libcurl build info - \\Host: {s} - \\Version: {s} - \\SSL version: {s} - \\Libz version: {s} - \\Protocols: - , .{ - v.*.host, - v.*.version, - v.*.ssl_version, - v.*.libz_version, - }); - var i: usize = 0; - while (v.*.protocols[i] != null) { - std.debug.print(" {s}", .{ - v.*.protocols[i], - }); - i += 1; - } else { - std.debug.print("\n", .{}); - } - - // feature_names is introduced in 7.87.0 - if (@hasField(c.struct_curl_version_info_data, "feature_names")) { - std.debug.print("Features:", .{}); - i = 0; - while (v.*.feature_names[i] != null) { - std.debug.print(" {s}", .{ - v.*.feature_names[i], - }); - i += 1; - } else { - std.debug.print("\n", .{}); - } - } -} - -pub fn has_parse_header_support() bool { - // `curl_header` is officially supported since 7.84.0. - // https://curl.se/libcurl/c/curl_easy_header.html - return c.CURL_AT_LEAST_VERSION(7, 84, 0); -} - -comptime { - // `curl_easy_reset` is only available since 7.12.0 - if (!c.CURL_AT_LEAST_VERSION(7, 12, 0)) { - @compileError("Libcurl version must at least 7.12.0"); - } -} - -pub fn url_encode(string: [:0]const u8) ?[]const u8 { - const r = c.curl_easy_escape(null, string.ptr, @intCast(string.len)); - return std.mem.sliceTo(r.?, 0); -} - -test "url encode" { - inline for (.{ - .{ - "https://github.com/", - "https%3A%2F%2Fgithub.com%2F", - }, - .{ - "https://httpbin.org/anything/你好", - "https%3A%2F%2Fhttpbin.org%2Fanything%2F%E4%BD%A0%E5%A5%BD", - }, - }) |case| { - const input = case.@"0"; - const expected = case.@"1"; - const actual = url_encode(input); - try std.testing.expectEqualStrings(expected, actual.?); - } -} diff --git a/src/easy.zig b/src/easy.zig index eea5a76..cad7497 100644 --- a/src/easy.zig +++ b/src/easy.zig @@ -1,14 +1,14 @@ -const c = @import("c.zig").c; const std = @import("std"); const errors = @import("errors.zig"); const util = @import("util.zig"); +const c = util.c; const mem = std.mem; const fmt = std.fmt; const Allocator = mem.Allocator; const checkCode = errors.checkCode; -const has_parse_header_support = @import("c.zig").has_parse_header_support; +const has_parse_header_support = @import("util.zig").has_parse_header_support; const Self = @This(); @@ -137,8 +137,9 @@ pub const MultiPart = struct { /// Init options for Easy handle pub const EasyOptions = struct { /// Use zig's std.crypto.Certificate.Bundle for TLS instead of libcurl's default. - /// Note that the builtin libcurl is compiled with mbedtls and does not include a CA bundle. - use_std_crypto_ca_bundle: bool = true, + // Note that the builtin libcurl is compiled with mbedtls and does not include a CA bundle, + // so this defaults to true when link_vendor is enabled. + use_std_crypto_ca_bundle: bool = @import("build_info").link_vendor, /// The maximum time in milliseconds that the entire transfer operation to take. default_timeout_ms: usize = 30_000, }; diff --git a/src/errors.zig b/src/errors.zig index 80bd928..ba48d0b 100644 --- a/src/errors.zig +++ b/src/errors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("c.zig").c; const assert = @import("std").debug.assert; +const c = @import("util.zig").c; pub const HeaderError = error{ BadIndex, diff --git a/src/root.zig b/src/root.zig index 3fb6ee3..b23cbe8 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,10 +1,11 @@ const std = @import("std"); -const c = @import("c.zig").c; +const util = @import("util.zig"); const checkCode = @import("errors.zig").checkCode; pub const Easy = @import("easy.zig"); -pub usingnamespace Easy; -pub usingnamespace @import("c.zig"); +pub const print_libcurl_version = util.print_libcurl_version; +pub const url_encode = util.url_encode; +pub const libcurl = util.c; /// This function sets up the program environment that libcurl needs. /// Since this function is not thread safe before libcurl 7.84.0, this function @@ -12,12 +13,12 @@ pub usingnamespace @import("c.zig"); /// A common place is in the beginning of the program. More see: /// https://curl.se/libcurl/c/curl_global_init.html pub fn global_init() !void { - try checkCode(c.curl_global_init(c.CURL_GLOBAL_ALL)); + try checkCode(libcurl.curl_global_init(libcurl.CURL_GLOBAL_ALL)); } /// This function releases resources acquired by curl_global_init. pub fn global_deinit() void { - c.curl_global_cleanup(); + libcurl.curl_global_cleanup(); } test { diff --git a/src/util.zig b/src/util.zig index 0939427..880066e 100644 --- a/src/util.zig +++ b/src/util.zig @@ -1,5 +1,7 @@ const std = @import("std"); -const c = @import("c.zig").c; +pub const c = @cImport({ + @cInclude("curl/curl.h"); +}); const Allocator = std.mem.Allocator; const Encoder = std.base64.standard.Encoder; @@ -9,3 +11,79 @@ pub fn encode_base64(allocator: Allocator, input: []const u8) ![]const u8 { return Encoder.encode(dest, input); } + +pub fn print_libcurl_version() void { + const v = c.curl_version_info(c.CURLVERSION_NOW); + std.debug.print( + \\Libcurl build info + \\Host: {s} + \\Version: {s} + \\SSL version: {s} + \\Libz version: {s} + \\Protocols: + , .{ + v.*.host, + v.*.version, + v.*.ssl_version, + v.*.libz_version, + }); + var i: usize = 0; + while (v.*.protocols[i] != null) { + std.debug.print(" {s}", .{ + v.*.protocols[i], + }); + i += 1; + } else { + std.debug.print("\n", .{}); + } + + // feature_names is introduced in 7.87.0 + if (@hasField(c.struct_curl_version_info_data, "feature_names")) { + std.debug.print("Features:", .{}); + i = 0; + while (v.*.feature_names[i] != null) { + std.debug.print(" {s}", .{ + v.*.feature_names[i], + }); + i += 1; + } else { + std.debug.print("\n", .{}); + } + } +} + +pub fn has_parse_header_support() bool { + // `curl_header` is officially supported since 7.84.0. + // https://curl.se/libcurl/c/curl_easy_header.html + return c.CURL_AT_LEAST_VERSION(7, 84, 0); +} + +comptime { + // `curl_easy_reset` is only available since 7.12.0 + if (!c.CURL_AT_LEAST_VERSION(7, 12, 0)) { + @compileError("Libcurl version must at least 7.12.0"); + } +} + +pub fn url_encode(string: [:0]const u8) ?[]const u8 { + const r = c.curl_easy_escape(null, string.ptr, @intCast(string.len)); + return std.mem.sliceTo(r.?, 0); +} + +test "url encode" { + inline for (.{ + .{ + "https://github.com/", + "https%3A%2F%2Fgithub.com%2F", + }, + .{ + "https://httpbin.org/anything/你好", + "https%3A%2F%2Fhttpbin.org%2Fanything%2F%E4%BD%A0%E5%A5%BD", + }, + }) |case| { + const input = case.@"0"; + const expected = case.@"1"; + const actual = url_encode(input); + try std.testing.expectEqualStrings(expected, actual.?); + } +}