| ... | @@ -526,9 +526,7 @@ fn fetchAndUnpack( | ... | @@ -526,9 +526,7 @@ fn fetchAndUnpack( |
| 526 | // whose content-disposition header is: 'attachment; filename="<project>-<sha>.tar.gz"' | 526 | // whose content-disposition header is: 'attachment; filename="<project>-<sha>.tar.gz"' |
| 527 | const content_disposition = req.response.headers.getFirstValue("Content-Disposition") orelse | 527 | const content_disposition = req.response.headers.getFirstValue("Content-Disposition") orelse |
| 528 | return report.fail(dep.url_tok, "Missing 'Content-Disposition' header for Content-Type=application/octet-stream", .{}); | 528 | return report.fail(dep.url_tok, "Missing 'Content-Disposition' header for Content-Type=application/octet-stream", .{}); |
| 529 | if (mem.startsWith(u8, content_disposition, "attachment;") and | 529 | if (isTarAttachment(content_disposition)) { |
| 530 | mem.endsWith(u8, content_disposition, ".tar.gz\"")) | | |
| 531 | { | | |
| 532 | try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.gzip); | 530 | try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.gzip); |
| 533 | } else return report.fail(dep.url_tok, "Unsupported 'Content-Disposition' header value: '{s}' for Content-Type=application/octet-stream", .{content_disposition}); | 531 | } else return report.fail(dep.url_tok, "Unsupported 'Content-Disposition' header value: '{s}' for Content-Type=application/octet-stream", .{content_disposition}); |
| 534 | } else { | 532 | } else { |
| ... | @@ -766,3 +764,37 @@ fn renameTmpIntoCache( | ... | @@ -766,3 +764,37 @@ fn renameTmpIntoCache( |
| 766 | break; | 764 | break; |
| 767 | } | 765 | } |
| 768 | } | 766 | } |
| | 767 | |
| | 768 | fn isTarAttachment(content_disposition: []const u8) bool { |
| | 769 | const disposition_type_end = ascii.indexOfIgnoreCase(content_disposition, "attachment;") orelse return false; |
| | 770 | |
| | 771 | var value_start = ascii.indexOfIgnoreCasePos(content_disposition, disposition_type_end + 1, "filename") orelse return false; |
| | 772 | value_start += "filename".len; |
| | 773 | if (content_disposition[value_start] == '*') { |
| | 774 | value_start += 1; |
| | 775 | } |
| | 776 | if (content_disposition[value_start] != '=') return false; |
| | 777 | value_start += 1; |
| | 778 | |
| | 779 | var value_end = mem.indexOfPos(u8, content_disposition, value_start, ";") orelse content_disposition.len; |
| | 780 | if (content_disposition[value_end - 1] == '\"') { |
| | 781 | value_end -= 1; |
| | 782 | } |
| | 783 | return ascii.endsWithIgnoreCase(content_disposition[value_start..value_end], ".tar.gz"); |
| | 784 | } |
| | 785 | |
| | 786 | test "isTarAttachment" { |
| | 787 | try std.testing.expect(isTarAttachment("attaChment; FILENAME=\"stuff.tar.gz\"; size=42")); |
| | 788 | try std.testing.expect(isTarAttachment("attachment; filename*=\"stuff.tar.gz\"")); |
| | 789 | try std.testing.expect(isTarAttachment("ATTACHMENT; filename=\"stuff.tar.gz\"")); |
| | 790 | try std.testing.expect(isTarAttachment("attachment; FileName=\"stuff.tar.gz\"")); |
| | 791 | try std.testing.expect(isTarAttachment("attachment; FileName*=UTF-8\'\'xyz%2Fstuff.tar.gz")); |
| | 792 | |
| | 793 | try std.testing.expect(!isTarAttachment("attachment FileName=\"stuff.tar.gz\"")); |
| | 794 | try std.testing.expect(!isTarAttachment("attachment; FileName=\"stuff.tar\"")); |
| | 795 | try std.testing.expect(!isTarAttachment("attachment; FileName\"stuff.gz\"")); |
| | 796 | try std.testing.expect(!isTarAttachment("attachment; size=42")); |
| | 797 | try std.testing.expect(!isTarAttachment("inline; size=42")); |
| | 798 | try std.testing.expect(!isTarAttachment("FileName=\"stuff.tar.gz\"; attachment;")); |
| | 799 | try std.testing.expect(!isTarAttachment("FileName=\"stuff.tar.gz\";")); |
| | 800 | } |