🌊

【Zig】TLS 1.2 対応の HTTPS クライアントをつくる

2024/05/25に公開

Zig 0.12 の std.crypto.tls は TLS 1.2 のみしかサポートしない。TLS 1.2 をサポートする Zig-TLS12 を利用して HTTPS クライアントをつくってみた。Zig-TLS12 は依存パッケージ管理のための build.zig.zon に対応しており、zig build を実行するだけで自動的に依存パッケージはダウンロードされる

build.zig.zon
.{
    .name = "http-client-project",
    .version = "0.0.1",
    .paths = .{
        "hello.zig",
        "build.zig",
        "build.zig.zon"
    },
    .dependencies = .{
        .tls12 = .{
            .url = "https://github.com/melonedo/zig-tls12/archive/refs/tags/0.1.0-for-zig-0.12.tar.gz",
            .hash = "1220bb536438e7f0f6b5bdb86039b7de33116ea52198eff0f1ac9f39ab10e487fbf6",
        },
    },
}
build.zig
const std = @import("std");

pub fn build(b: *std.Build) void {
  const target = b.standardTargetOptions(.{});
  const optimize = b.standardOptimizeOption(.{});

  const exe = b.addExecutable(.{
    .name = "http-client",
    .root_source_file = .{ .path = "client.zig" },
    .target = target,
    .optimize = optimize
   });

  const tls12 = b.dependency("tls12", .{
    .target = target,
    .optimize = optimize
   });

  exe.root_module.addImport("tls12", tls12.module("zig-tls12"));

  b.installArtifact(exe);

  const run_exe = b.addRunArtifact(exe);
  const run_step = b.step("run", "Run the application");
  run_step.dependOn(&run_exe.step);
}
client.zig
const std = @import("std");
const HttpClient = @import("tls12");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    var client = HttpClient{ .allocator = allocator };
    defer client.deinit();
    try client.initDefaultProxies(allocator);

    const url = "https://httpbin.org/get";

    const uri = try std.Uri.parse(url);
    var server_header_buffer: [1024 * 1024]u8 = undefined;
    var req = try HttpClient.open(&client, .GET, uri, .{
        .server_header_buffer = &server_header_buffer,
        .redirect_behavior = @enumFromInt(10),
    });
    defer req.deinit();

    try req.send();
    try req.wait();
    const body = try req.reader().readAllAlloc(allocator, 16 * 1024 * 1024);
    defer allocator.free(body);

    std.debug.print("{s}: {s}\n", .{ url, body });
}

実行結果は次のとおり。リクエスト先の httpbin.org は現時点で TLS 1.3 には対応していない

zig build run
https://httpbin.org/get: {
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "zig/0.12.0 (std.http)", 
    "X-Amzn-Trace-Id": "Root=1-6651e55e-0e911c7d0eecfa53324e8ad2"
  }, 
  "origin": "115.162.203.179", 
  "url": "https://httpbin.org/get"
}

Discussion