Commit 34865d6938

DraagrenKirneh <h_n91@hotmail.com>
2023-05-25 07:30:58
Improve Content-Disposition filename detection (#15844)
1 parent 5744cee
Changed files (1)
src/Package.zig
@@ -526,9 +526,7 @@ fn fetchAndUnpack(
             // whose content-disposition header is: 'attachment; filename="<project>-<sha>.tar.gz"'
             const content_disposition = req.response.headers.getFirstValue("Content-Disposition") orelse
                 return report.fail(dep.url_tok, "Missing 'Content-Disposition' header for Content-Type=application/octet-stream", .{});
-            if (mem.startsWith(u8, content_disposition, "attachment;") and
-                mem.endsWith(u8, content_disposition, ".tar.gz\""))
-            {
+            if (isTarAttachment(content_disposition)) {
                 try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.gzip);
             } else return report.fail(dep.url_tok, "Unsupported 'Content-Disposition' header value: '{s}' for Content-Type=application/octet-stream", .{content_disposition});
         } else {
@@ -766,3 +764,37 @@ fn renameTmpIntoCache(
         break;
     }
 }
+
+fn isTarAttachment(content_disposition: []const u8) bool {
+    const disposition_type_end = ascii.indexOfIgnoreCase(content_disposition, "attachment;") orelse return false;
+
+    var value_start = ascii.indexOfIgnoreCasePos(content_disposition, disposition_type_end + 1, "filename") orelse return false;
+    value_start += "filename".len;
+    if (content_disposition[value_start] == '*') {
+        value_start += 1;
+    }
+    if (content_disposition[value_start] != '=') return false;
+    value_start += 1;
+
+    var value_end = mem.indexOfPos(u8, content_disposition, value_start, ";") orelse content_disposition.len;
+    if (content_disposition[value_end - 1] == '\"') {
+        value_end -= 1;
+    }
+    return ascii.endsWithIgnoreCase(content_disposition[value_start..value_end], ".tar.gz");
+}
+
+test "isTarAttachment" {
+    try std.testing.expect(isTarAttachment("attaChment; FILENAME=\"stuff.tar.gz\"; size=42"));
+    try std.testing.expect(isTarAttachment("attachment; filename*=\"stuff.tar.gz\""));
+    try std.testing.expect(isTarAttachment("ATTACHMENT; filename=\"stuff.tar.gz\""));
+    try std.testing.expect(isTarAttachment("attachment; FileName=\"stuff.tar.gz\""));
+    try std.testing.expect(isTarAttachment("attachment; FileName*=UTF-8\'\'xyz%2Fstuff.tar.gz"));
+
+    try std.testing.expect(!isTarAttachment("attachment FileName=\"stuff.tar.gz\""));
+    try std.testing.expect(!isTarAttachment("attachment; FileName=\"stuff.tar\""));
+    try std.testing.expect(!isTarAttachment("attachment; FileName\"stuff.gz\""));
+    try std.testing.expect(!isTarAttachment("attachment; size=42"));
+    try std.testing.expect(!isTarAttachment("inline; size=42"));
+    try std.testing.expect(!isTarAttachment("FileName=\"stuff.tar.gz\"; attachment;"));
+    try std.testing.expect(!isTarAttachment("FileName=\"stuff.tar.gz\";"));
+}