Skip to content

Commit 6ee6db0

Browse files
authored
🐛 OneDrive zero-byte upload fix (#1405)
1 parent 5aea479 commit 6ee6db0

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

packages/filesystem/onedrive/onedrive.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,55 @@ describe("OneDriveFileSystem", () => {
127127
name: "B",
128128
});
129129
});
130+
131+
it("writer should upload empty string with simple PUT", async () => {
132+
const fs = new OneDriveFileSystem("/", "token");
133+
const requestSpy = vi.spyOn(fs, "request").mockResolvedValue({});
134+
135+
const writer = await fs.create("empty.txt");
136+
await writer.write("");
137+
138+
expect(requestSpy).toHaveBeenCalledTimes(1);
139+
expect(requestSpy.mock.calls[0][0]).toBe(
140+
"https://graph.microsoft.com/v1.0/me/drive/special/approot:/empty.txt:/content"
141+
);
142+
expect(requestSpy.mock.calls[0][1]).toMatchObject({
143+
method: "PUT",
144+
body: "",
145+
});
146+
});
147+
148+
it("writer should upload empty Blob with simple PUT", async () => {
149+
const fs = new OneDriveFileSystem("/", "token");
150+
const requestSpy = vi.spyOn(fs, "request").mockResolvedValue({});
151+
const emptyBlob = new Blob([]);
152+
153+
const writer = await fs.create("empty.bin");
154+
await writer.write(emptyBlob);
155+
156+
expect(requestSpy).toHaveBeenCalledTimes(1);
157+
expect(requestSpy.mock.calls[0][0]).toBe(
158+
"https://graph.microsoft.com/v1.0/me/drive/special/approot:/empty.bin:/content"
159+
);
160+
expect((requestSpy.mock.calls[0][1] as RequestInit).body).toBe(emptyBlob);
161+
});
162+
163+
it("writer should keep upload session for non-empty content", async () => {
164+
const fs = new OneDriveFileSystem("/", "token");
165+
const requestSpy = vi
166+
.spyOn(fs, "request")
167+
.mockResolvedValueOnce({ uploadUrl: "https://upload.example/session" })
168+
.mockResolvedValueOnce({});
169+
170+
const writer = await fs.create("not-empty.txt");
171+
await writer.write("abc");
172+
173+
expect(requestSpy).toHaveBeenCalledTimes(2);
174+
expect(requestSpy.mock.calls[0][0]).toBe(
175+
"https://graph.microsoft.com/v1.0/me/drive/special/approot:/not-empty.txt:/createUploadSession"
176+
);
177+
expect(requestSpy.mock.calls[1][0]).toBe("https://upload.example/session");
178+
const headers = (requestSpy.mock.calls[1][1] as RequestInit).headers as Headers;
179+
expect(headers.get("Content-Range")).toBe("bytes 0-2/3");
180+
});
130181
});

packages/filesystem/onedrive/rw.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,14 @@ export class OneDriveFileWriter implements FileWriter {
5858

5959
async write(content: string | Blob): Promise<void> {
6060
// 预上传获取id
61-
const size = this.size(content).toString();
61+
const size = this.size(content);
62+
if (size === 0) {
63+
return this.fs.request(`https://graph.microsoft.com/v1.0/me/drive/special/approot:${this.path}:/content`, {
64+
method: "PUT",
65+
body: content,
66+
});
67+
}
68+
6269
let myHeaders = new Headers();
6370
myHeaders.append("Content-Type", "application/json");
6471
const uploadUrl = await this.fs
@@ -83,7 +90,7 @@ export class OneDriveFileWriter implements FileWriter {
8390
return data.uploadUrl;
8491
});
8592
myHeaders = new Headers();
86-
myHeaders.append("Content-Range", `bytes 0-${parseInt(size, 10) - 1}/${size}`);
93+
myHeaders.append("Content-Range", `bytes 0-${size - 1}/${size}`);
8794
return this.fs.request(uploadUrl, {
8895
method: "PUT",
8996
body: content,

0 commit comments

Comments
 (0)