reject empty file

This commit is contained in:
mertalev 2025-10-10 21:08:16 -04:00
parent 504d8dc96c
commit 85a3854208
No known key found for this signature in database
GPG key ID: DF6ABC77AAD98C95
4 changed files with 9 additions and 22 deletions

View file

@ -974,7 +974,7 @@ describe('/upload', () => {
expect(status).toBe(204); expect(status).toBe(204);
expect(headers['upload-offset']).toBe('512'); expect(headers['upload-offset']).toBe('512');
expect(headers['upload-complete']).toBe('?0'); expect(headers['upload-complete']).toBe('?0');
expect(headers['upload-limit']).toEqual('min-size=0, max-age=259200'); expect(headers['upload-limit']).toEqual('min-size=1, max-age=259200');
expect(headers['cache-control']).toBe('no-store'); expect(headers['cache-control']).toBe('no-store');
}); });
@ -993,7 +993,7 @@ describe('/upload', () => {
const { status, headers } = await request(app).options('/upload'); const { status, headers } = await request(app).options('/upload');
expect(status).toBe(204); expect(status).toBe(204);
expect(headers['upload-limit']).toEqual('min-size=0, max-age=259200'); expect(headers['upload-limit']).toEqual('min-size=1, max-age=259200');
}); });
}); });
}); });

View file

@ -115,20 +115,7 @@ describe(AssetUploadController.name, () => {
expect(body).toEqual(expect.objectContaining({ message: 'Expected valid upload-complete header' })); expect(body).toEqual(expect.objectContaining({ message: 'Expected valid upload-complete header' }));
}); });
it('should require Upload-Length header', async () => { it('should infer upload length from non-empty content length if complete upload', async () => {
const { status, body } = await request(ctx.getHttpServer())
.post('/upload')
.set('Upload-Draft-Interop-Version', '8')
.set('X-Immich-Asset-Data', makeAssetData())
.set('Repr-Digest', checksum)
.set('Upload-Complete', '?0')
.send(buffer);
expect(status).toBe(400);
expect(body).toEqual(expect.objectContaining({ message: 'Missing upload-length header' }));
});
it('should infer upload length from content length if complete upload', async () => {
const { status } = await request(ctx.getHttpServer()) const { status } = await request(ctx.getHttpServer())
.post('/upload') .post('/upload')
.set('Upload-Draft-Interop-Version', '8') .set('Upload-Draft-Interop-Version', '8')
@ -258,7 +245,7 @@ describe(AssetUploadController.name, () => {
expect(body).toEqual(expect.objectContaining({ message: 'Expected valid upload-complete header' })); expect(body).toEqual(expect.objectContaining({ message: 'Expected valid upload-complete header' }));
}); });
it('should validate Upload-Length is a non-negative integer', async () => { it('should validate Upload-Length is a positive integer', async () => {
const { status, body } = await request(ctx.getHttpServer()) const { status, body } = await request(ctx.getHttpServer())
.post('/upload') .post('/upload')
.set('Upload-Draft-Interop-Version', '8') .set('Upload-Draft-Interop-Version', '8')
@ -271,7 +258,7 @@ describe(AssetUploadController.name, () => {
expect(status).toBe(400); expect(status).toBe(400);
expect(body).toEqual( expect(body).toEqual(
expect.objectContaining({ expect.objectContaining({
message: expect.arrayContaining(['uploadLength must not be less than 0']), message: expect.arrayContaining(['uploadLength must not be less than 1']),
}), }),
); );
}); });

View file

@ -112,7 +112,7 @@ export class StartUploadDto extends BaseUploadHeadersDto {
checksum!: Buffer; checksum!: Buffer;
@Expose() @Expose()
@Min(0) @Min(1)
@IsInt() @IsInt()
@Transform(({ obj }) => { @Transform(({ obj }) => {
const uploadLength = obj[Header.UploadLength]; const uploadLength = obj[Header.UploadLength];
@ -121,7 +121,7 @@ export class StartUploadDto extends BaseUploadHeadersDto {
} }
const contentLength = obj[Header.ContentLength]; const contentLength = obj[Header.ContentLength];
if (contentLength != undefined && isUploadComplete(obj)) { if (contentLength && isUploadComplete(obj)) {
return Number(contentLength); return Number(contentLength);
} }
throw new BadRequestException(`Missing ${Header.UploadLength} header`); throw new BadRequestException(`Missing ${Header.UploadLength} header`);
@ -136,7 +136,7 @@ export class ResumeUploadDto extends BaseUploadHeadersDto {
contentType!: string; contentType!: string;
@Expose({ name: Header.UploadLength }) @Expose({ name: Header.UploadLength })
@Min(0) @Min(1)
@IsInt() @IsInt()
@Type(() => Number) @Type(() => Number)
@Optional() @Optional()

View file

@ -440,6 +440,6 @@ export class AssetUploadService extends BaseService {
} }
private getUploadLimits({ upload }: SystemConfig['backup']) { private getUploadLimits({ upload }: SystemConfig['backup']) {
return `min-size=0, max-age=${upload.maxAgeHours * 3600}`; return `min-size=1, max-age=${upload.maxAgeHours * 3600}`;
} }
} }