Skip to content

Commit 9616392

Browse files
committed
fix: prevent binary download failures with compressed server responses
Request identity encoding and disable axios decompression for all downloads to avoid failures when servers or proxies apply unexpected content encoding. Fall back to x-original-content-length header for progress tracking when content-length is absent.
1 parent 8ef32d4 commit 9616392

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

src/core/cliManager.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,6 @@ export class CliManager {
355355
binSource,
356356
writeStream,
357357
{
358-
"Accept-Encoding": "gzip",
359358
"If-None-Match": `"${etag}"`,
360359
},
361360
onProgress,
@@ -467,15 +466,19 @@ export class CliManager {
467466
signal: controller.signal,
468467
baseURL: baseUrl,
469468
responseType: "stream",
470-
headers,
471-
decompress: true,
469+
headers: {
470+
"Accept-Encoding": "identity",
471+
...headers,
472+
},
473+
decompress: false,
472474
// Ignore all errors so we can catch a 404!
473475
validateStatus: () => true,
474476
});
475477
this.output.info("Got status code", resp.status);
476478

477479
if (resp.status === 200) {
478-
const rawContentLength = resp.headers["content-length"] as unknown;
480+
const rawContentLength = (resp.headers["content-length"] ??
481+
resp.headers["x-original-content-length"]) as unknown;
479482
const contentLength = Number.parseInt(
480483
typeof rawContentLength === "string" ? rawContentLength : "",
481484
);

test/unit/core/cliManager.test.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ describe("CliManager", () => {
275275
expect.objectContaining({
276276
responseType: "stream",
277277
headers: expect.objectContaining({
278-
"Accept-Encoding": "gzip",
278+
"Accept-Encoding": "identity",
279279
"If-None-Match": '""',
280280
}),
281281
}),
@@ -290,7 +290,7 @@ describe("CliManager", () => {
290290
"/custom/path",
291291
expect.objectContaining({
292292
responseType: "stream",
293-
decompress: true,
293+
decompress: false,
294294
validateStatus: expect.any(Function),
295295
}),
296296
);
@@ -425,10 +425,33 @@ describe("CliManager", () => {
425425

426426
it("handles missing content-length", async () => {
427427
withSuccessfulDownload({ headers: {} });
428+
mockProgress.clearProgressReports();
428429
const result = await manager.fetchBinary(mockApi, "test");
429430
expectPathsEqual(result, BINARY_PATH);
430431
expect(memfs.existsSync(BINARY_PATH)).toBe(true);
431-
});
432+
// Without any content-length header, increment should be undefined.
433+
const reports = mockProgress.getProgressReports();
434+
expect(reports).not.toHaveLength(0);
435+
for (const report of reports) {
436+
expect(report).toMatchObject({ increment: undefined });
437+
}
438+
});
439+
440+
it.each(["content-length", "x-original-content-length"])(
441+
"reports progress with %s header",
442+
async (header) => {
443+
withSuccessfulDownload({ headers: { [header]: "1024" } });
444+
mockProgress.clearProgressReports();
445+
const result = await manager.fetchBinary(mockApi, "test");
446+
expectPathsEqual(result, BINARY_PATH);
447+
expect(memfs.existsSync(BINARY_PATH)).toBe(true);
448+
const reports = mockProgress.getProgressReports();
449+
expect(reports).not.toHaveLength(0);
450+
for (const report of reports) {
451+
expect(report).toMatchObject({ increment: expect.any(Number) });
452+
}
453+
},
454+
);
432455
});
433456

434457
describe("Download Progress Tracking", () => {

0 commit comments

Comments
 (0)