Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/cross/_cross_uploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ async function uploadBlobInternal(
...(httpOptions?.headers || {}),
'X-Goog-Upload-Command': uploadCommand,
'X-Goog-Upload-Offset': String(offset),
'Content-Length': String(chunkSize),
// Don't set Content-Length: fetch derives it from the body, and a
// duplicate is rejected by undici >= 7.26 (#1718).
};

response = await apiClient.request({
Expand Down
3 changes: 2 additions & 1 deletion src/node/_node_uploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,9 @@ export class NodeUploader implements Uploader {
...(httpOptions?.headers || {}),
'X-Goog-Upload-Command': uploadCommand,
'X-Goog-Upload-Offset': String(offset),
'Content-Length': String(bytesRead),
'X-Goog-Upload-File-Name': fileName,
// Don't set Content-Length: fetch derives it from the body, and a
// duplicate is rejected by undici >= 7.26 (#1718).
};

response = await apiClient.request({
Expand Down
33 changes: 33 additions & 0 deletions test/unit/file_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,39 @@ describe('File', () => {
}
expect(byteProcessed).toBe(fileSize);
});
it('It should not send a Content-Length that undici >= 7.26 would reject.', async () => {
const testBlob = new Blob([new Uint8Array(8)], {
type: DEFAULT_TEST_MIMETYPE,
});

spyOn(global, 'fetch').and.callFake((_input, init) => {
const headers = init?.headers as Headers | undefined;
// Mimic undici >= 7.26, which rejects a request that carries both a
// body and an explicit Content-Length (#1718).
if (init?.body && headers?.get('Content-Length')) {
return Promise.reject(
new TypeError('fetch failed', {
cause: {code: 'UND_ERR_INVALID_ARG'},
}),
);
}
// The chunk request carries the upload offset; anything else is the
// initial request that returns the upload url.
if (headers?.get('X-Goog-Upload-Offset') !== null) {
return Promise.resolve(
new Response(
JSON.stringify({file: {name: 'files/test-file'}}),
lastCorrectFetchOkOptions,
),
);
}
return Promise.resolve(new Response('', createUrlOkoptions));
});

const uploaded = await client.files.upload({file: testBlob});

expect(uploaded.name).toBe('files/test-file');
});
});
});
describe('registerFiles', () => {
Expand Down