mirror of
https://github.com/Nezumi-2711/google-drive-s3.git
synced 2026-09-22 05:31:47 +00:00
fix: add modified value for object
This commit is contained in:
+3
-1
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user