const std = @import("std"); const Allocator = std.mem.Allocator; pub fn httpGet(allocator: Allocator, url: []const u8) ![]u8 { var client: std.http.Client = .{ .allocator = allocator }; defer client.deinit(); var aw: std.Io.Writer.Allocating = .init(allocator); defer aw.deinit(); const result = client.fetch(.{ .location = .{ .url = url }, .response_writer = &aw.writer, }) catch return error.HttpRequestFailed; if (result.status != .ok) return error.HttpRequestFailed; return aw.toOwnedSlice() catch return error.OutOfMemory; } pub fn httpPostJson(allocator: Allocator, url: []const u8, body: []const u8) ![]u8 { var client: std.http.Client = .{ .allocator = allocator }; defer client.deinit(); var aw: std.Io.Writer.Allocating = .init(allocator); defer aw.deinit(); const result = client.fetch(.{ .location = .{ .url = url }, .method = .POST, .payload = body, .headers = .{ .content_type = .{ .override = "application/json" } }, .response_writer = &aw.writer, }) catch return error.HttpRequestFailed; if (result.status != .ok) return error.HttpRequestFailed; return aw.toOwnedSlice() catch return error.OutOfMemory; } pub fn httpPostMultipart( allocator: Allocator, url: []const u8, file_field: []const u8, file_path: []const u8, file_name: []const u8, fields: []const [2][]const u8, ) ![]u8 { const boundary = "----ZigMultipartBoundary9876543210"; // Build multipart body var body_writer: std.Io.Writer.Allocating = .init(allocator); defer body_writer.deinit(); // Add form fields for (fields) |field| { body_writer.writer.print("--{s}\r\nContent-Disposition: form-data; name=\"{s}\"\r\n\r\n{s}\r\n", .{ boundary, field[0], field[1] }) catch return error.OutOfMemory; } // Add file field header body_writer.writer.print("--{s}\r\nContent-Disposition: form-data; name=\"{s}\"; filename=\"{s}\"\r\nContent-Type: application/octet-stream\r\n\r\n", .{ boundary, file_field, file_name }) catch return error.OutOfMemory; // Read and append file content const file = std.fs.openFileAbsolute(file_path, .{}) catch return error.HttpRequestFailed; defer file.close(); const file_content = file.readToEndAlloc(allocator, 100 * 1024 * 1024) catch return error.HttpRequestFailed; defer allocator.free(file_content); body_writer.writer.writeAll(file_content) catch return error.OutOfMemory; body_writer.writer.print("\r\n--{s}--\r\n", .{boundary}) catch return error.OutOfMemory; const body = body_writer.written(); // Send request var client: std.http.Client = .{ .allocator = allocator }; defer client.deinit(); var response_aw: std.Io.Writer.Allocating = .init(allocator); defer response_aw.deinit(); const content_type = std.fmt.allocPrint(allocator, "multipart/form-data; boundary={s}", .{boundary}) catch return error.OutOfMemory; defer allocator.free(content_type); const result = client.fetch(.{ .location = .{ .url = url }, .method = .POST, .payload = body, .headers = .{ .content_type = .{ .override = content_type } }, .response_writer = &response_aw.writer, }) catch return error.HttpRequestFailed; if (result.status != .ok) return error.HttpRequestFailed; return response_aw.toOwnedSlice() catch return error.OutOfMemory; } pub fn downloadToFile(allocator: Allocator, url: []const u8, dest_path: []const u8) !void { const data = try httpGet(allocator, url); defer allocator.free(data); const file = std.fs.createFileAbsolute(dest_path, .{}) catch return error.HttpRequestFailed; defer file.close(); file.writeAll(data) catch return error.HttpRequestFailed; }