feature. See also
. The project being documented here (as the example) is the Zig library itself.
Fetch.unpackResource
fn unpackResource(
f: *Fetch,
resource: *Resource,
uri_path: []const u8,
tmp_directory: Directory,
) RunError!UnpackResult
File
Code
fn unpackResource(
f: *Fetch,
resource: *Resource,
uri_path: []const u8,
tmp_directory: Directory,
) RunError!UnpackResult {
const eb = &f.error_bundle;
const file_type = switch (resource.*) {
.file => FileType.fromPath(uri_path) orelse
return f.fail(f.location_tok, try eb.printString("unknown file type: '{s}'", .{uri_path})),
.http_request => |*http_request| ft: {
const head = &http_request.response.head;
const content_type = head.content_type orelse
return f.fail(f.location_tok, try eb.addString("missing 'Content-Type' header"));
const mime_type_end = std.mem.indexOf(u8, content_type, ";") orelse content_type.len;
const mime_type = content_type[0..mime_type_end];
if (ascii.eqlIgnoreCase(mime_type, "application/x-tar"))
break :ft .tar;
if (ascii.eqlIgnoreCase(mime_type, "application/gzip") or
ascii.eqlIgnoreCase(mime_type, "application/x-gzip") or
ascii.eqlIgnoreCase(mime_type, "application/tar+gzip") or
ascii.eqlIgnoreCase(mime_type, "application/x-tar-gz") or
ascii.eqlIgnoreCase(mime_type, "application/x-gtar-compressed"))
{
break :ft .@"tar.gz";
}
if (ascii.eqlIgnoreCase(mime_type, "application/x-xz"))
break :ft .@"tar.xz";
if (ascii.eqlIgnoreCase(mime_type, "application/zstd"))
break :ft .@"tar.zst";
if (ascii.eqlIgnoreCase(mime_type, "application/zip") or
ascii.eqlIgnoreCase(mime_type, "application/x-zip-compressed") or
ascii.eqlIgnoreCase(mime_type, "application/java-archive"))
{
break :ft .zip;
}
if (!ascii.eqlIgnoreCase(mime_type, "application/octet-stream") and
!ascii.eqlIgnoreCase(mime_type, "application/x-compressed"))
{
return f.fail(f.location_tok, try eb.printString(
"unrecognized 'Content-Type' header: '{s}'",
.{content_type},
));
}
if (head.content_disposition) |cd_header| {
break :ft FileType.fromContentDisposition(cd_header) orelse {
return f.fail(f.location_tok, try eb.printString(
"unsupported Content-Disposition header value: '{s}' for Content-Type=application/octet-stream",
.{cd_header},
));
};
}
break :ft FileType.fromPath(uri_path) orelse {
return f.fail(f.location_tok, try eb.printString("unknown file type: '{s}'", .{uri_path}));
};
},
.git => .git_pack,
.dir => |dir| {
f.recursiveDirectoryCopy(dir, tmp_directory.handle) catch |err| {
return f.fail(f.location_tok, try eb.printString("unable to copy directory '{s}': {t}", .{
uri_path, err,
}));
};
return .{};
},
};
switch (file_type) {
.tar => {
return unpackTarball(f, tmp_directory.handle, resource.reader());
},
.@"tar.gz" => {
var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
var decompress: std.compress.flate.Decompress = .init(resource.reader(), .gzip, &flate_buffer);
return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
},
.@"tar.xz" => {
const gpa = f.arena.child_allocator;
var decompress = std.compress.xz.Decompress.init(resource.reader(), gpa, &.{}) catch |err|
return f.fail(f.location_tok, try eb.printString("unable to decompress tarball: {t}", .{err}));
defer decompress.deinit();
return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
},
.@"tar.zst" => {
const window_len = std.compress.zstd.default_window_len;
const window_buffer = try f.arena.allocator().alloc(u8, window_len + std.compress.zstd.block_size_max);
var decompress: std.compress.zstd.Decompress = .init(resource.reader(), window_buffer, .{
.verify_checksum = false,
.window_len = window_len,
});
return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
},
.git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {
error.FetchFailed, error.OutOfMemory => |e| return e,
else => |e| return f.fail(f.location_tok, try eb.printString("unable to unpack git files: {t}", .{e})),
},
.zip => return unzip(f, tmp_directory.handle, resource.reader()) catch |err| switch (err) {
error.ReadFailed => return f.fail(f.location_tok, try eb.printString(
"failed reading resource: {t}",
.{err},
)),
else => |e| return e,
},
}
}