fix: add modified value for object

This commit is contained in:
2026-08-16 15:40:42 +07:00
parent 478095f2b7
commit 92d4da14ed
4 changed files with 26 additions and 6 deletions
+3 -1
View File
@@ -11,7 +11,7 @@ interface GoogleDriveCreateResponse {
id: string;
}
const DRIVE_FIELDS = "id,name,size,mimeType,md5Checksum";
const DRIVE_FIELDS = "id,name,size,mimeType,md5Checksum,modifiedTime";
const FOLDER_MIME_TYPE = "application/vnd.google-apps.folder";
const LIST_NODE_CAP = 5000;
@@ -227,6 +227,7 @@ export async function streamDownloadFromDrive(accessToken: string, bucket: strin
size: parseInt(file.size || "0", 10),
id: file.id,
md5Checksum: file.md5Checksum,
modifiedTime: file.modifiedTime,
status: downloadRes.status,
contentRange: downloadRes.headers.get("Content-Range") ?? undefined,
contentLength: downloadRes.headers.get("Content-Length") ?? undefined,
@@ -264,6 +265,7 @@ export async function getFileMetadata(accessToken: string, bucket: string, objec
mimeType: file.mimeType || "application/octet-stream",
size: parseInt(file.size || "0", 10),
md5Checksum: file.md5Checksum,
modifiedTime: file.modifiedTime,
};
}
+4 -4
View File
@@ -207,6 +207,7 @@ export async function dispatch(request: Request, env: Env, accessToken: string,
ETag: `"${etag(file)}"`,
});
if (file.contentRange) headers.set("Content-Range", file.contentRange);
if (file.modifiedTime) headers.set("Last-Modified", new Date(file.modifiedTime).toUTCString());
return new Response(file.body, { status: file.status, headers });
} catch (error) {
if (error instanceof Error && error.message === "File not found") return s3Error("NoSuchKey", 404, undefined, resource);
@@ -218,10 +219,9 @@ export async function dispatch(request: Request, env: Env, accessToken: string,
if (!key) return new Response(null, { status: 200 });
try {
const metadata = await getFileMetadata(accessToken, bucket, key, env);
return new Response(null, {
status: 200,
headers: { "Content-Type": metadata.mimeType, "Content-Length": metadata.size.toString(), "Accept-Ranges": "bytes", ETag: `"${etag(metadata)}"` },
});
const headers = new Headers({ "Content-Type": metadata.mimeType, "Content-Length": metadata.size.toString(), "Accept-Ranges": "bytes", ETag: `"${etag(metadata)}"` });
if (metadata.modifiedTime) headers.set("Last-Modified", new Date(metadata.modifiedTime).toUTCString());
return new Response(null, { status: 200, headers });
} catch (error) {
if (error instanceof Error && error.message === "File not found") return s3Error("NoSuchKey", 404, undefined, resource, true);
throw error;
+2
View File
@@ -41,6 +41,7 @@ export interface DriveDownloadResult {
size: number;
id: string;
md5Checksum?: string;
modifiedTime?: string;
status: number;
contentRange?: string;
contentLength?: string;
@@ -51,4 +52,5 @@ export interface DriveFileMetadata {
mimeType: string;
size: number;
md5Checksum?: string;
modifiedTime?: string;
}
+17 -1
View File
@@ -18,8 +18,11 @@ interface StoredFile {
mimeType: string;
data: Uint8Array;
md5Checksum: string;
modifiedTime: string;
}
const FAKE_MODIFIED_TIME = "2026-08-16T08:00:00.000Z";
interface StoredFolder {
id: string;
name: string;
@@ -95,6 +98,7 @@ class FakeDrive {
mimeType,
data: new Uint8Array(),
md5Checksum: "d41d8cd98f00b204e9800998ecf8427e",
modifiedTime: FAKE_MODIFIED_TIME,
};
this.files.set(id, file);
return Response.json({ ...file, size: "0", data: undefined });
@@ -148,7 +152,7 @@ class FakeDrive {
private finalize(session: UploadSession, data: Uint8Array): Response {
const id = session.fileId ?? `file-${this.nextId++}`;
const file: StoredFile = { id, name: session.name, parent: session.parent, mimeType: session.mimeType, data, md5Checksum: fakeMd5(data) };
const file: StoredFile = { id, name: session.name, parent: session.parent, mimeType: session.mimeType, data, md5Checksum: fakeMd5(data), modifiedTime: FAKE_MODIFIED_TIME };
this.files.set(id, file);
this.sessions.delete(session.id);
return Response.json({ ...file, size: String(data.byteLength), data: undefined });
@@ -225,6 +229,18 @@ describe("S3 compatibility", () => {
expect(new TextDecoder().decode([...drive.files.values()].find((file) => file.name === "file.txt")!.data)).toBe("second");
});
it("sets Last-Modified on GET and HEAD from Drive's modifiedTime", async () => {
await worker.fetch(await signed("/test-bucket/dated.txt", { method: "PUT", body: "hi" }), ENV, CTX);
const expected = new Date(FAKE_MODIFIED_TIME).toUTCString();
const get = await worker.fetch(await signed("/test-bucket/dated.txt", { method: "GET" }), ENV, CTX);
expect(get.headers.get("Last-Modified")).toBe(expected);
const head = await worker.fetch(await signed("/test-bucket/dated.txt", { method: "HEAD" }), ENV, CTX);
expect(head.headers.get("Last-Modified")).toBe(expected);
});
it("forwards Range and returns a standard XML NoSuchKey", async () => {
await worker.fetch(await signed("/test-bucket/range.bin", { method: "PUT", body: "0123456789" }), ENV, CTX);
const response = await worker.fetch(await signed("/test-bucket/range.bin", { method: "GET", headers: { Range: "bytes=2-5" } }), ENV, CTX);