diff --git a/src/internal/helper.ts b/src/internal/helper.ts index de58c485..6d97803d 100644 --- a/src/internal/helper.ts +++ b/src/internal/helper.ts @@ -462,6 +462,10 @@ export function sanitizeObjectKey(objectName: string): string { return decodeURIComponent(asStrName) } +export function sanitizeSize(size?: string): number | undefined { + return size ? Number.parseInt(size) : undefined +} + export const PART_CONSTRAINTS = { // absMinPartSize - absolute minimum part size (5 MiB) ABS_MIN_PART_SIZE: 1024 * 1024 * 5, diff --git a/src/xml-parsers.js b/src/xml-parsers.js index d551a0d2..935ea9dc 100644 --- a/src/xml-parsers.js +++ b/src/xml-parsers.js @@ -15,10 +15,19 @@ */ import crc32 from 'buffer-crc32' +import { XMLParser } from 'fast-xml-parser' import * as errors from './errors.ts' import { SelectResults } from './helpers.ts' -import { isObject, parseXml, readableStream, sanitizeETag, sanitizeObjectKey, toArray } from './internal/helper.ts' +import { + isObject, + parseXml, + readableStream, + sanitizeETag, + sanitizeObjectKey, + sanitizeSize, + toArray, +} from './internal/helper.ts' import { RETENTION_VALIDITY_UNITS } from './internal/type.ts' // parse XML response for copy object @@ -216,12 +225,13 @@ const formatObjInfo = (content, opts = {}) => { const name = sanitizeObjectKey(toArray(Key)[0]) const lastModified = new Date(toArray(LastModified)[0]) const etag = sanitizeETag(toArray(ETag)[0]) + const size = sanitizeSize(Size) return { name, lastModified, etag, - size: Size, + size, versionId: VersionId, isLatest: IsLatest, isDeleteMarker: opts.IsDeleteMarker ? opts.IsDeleteMarker : false, @@ -236,7 +246,12 @@ export function parseListObjects(xml) { } let isTruncated = false let nextMarker, nextVersionKeyMarker - const xmlobj = parseXml(xml) + const fxp = new XMLParser({ + numberParseOptions: { + skipLike: /./, + }, + }) + const xmlobj = fxp.parse(xml) const parseCommonPrefixesEntity = (responseEntity) => { if (responseEntity) { @@ -258,7 +273,7 @@ export function parseListObjects(xml) { const name = sanitizeObjectKey(toArray(content.Key)[0]) const lastModified = new Date(toArray(content.LastModified)[0]) const etag = sanitizeETag(toArray(content.ETag)[0]) - const size = content.Size + const size = sanitizeSize(content.Size) result.objects.push({ name, lastModified, etag, size }) }) } diff --git a/tests/unit/test.js b/tests/unit/test.js index 05e43ade..1b9f3de4 100644 --- a/tests/unit/test.js +++ b/tests/unit/test.js @@ -29,6 +29,7 @@ import { partsRequired, } from '../../src/internal/helper.ts' import * as Minio from '../../src/minio.js' +import { parseListObjects } from '../../src/xml-parsers.ts' const Package = { version: 'development' } @@ -2078,3 +2079,56 @@ describe('IP Address Validations', () => { }) }) }) + +describe('xml-parser', () => { + describe('#listObjects()', () => { + describe('value type casting', () => { + const xml = ` + + + some-bucket + 42 + / + false + url + + + + true + 1234 + "767dedcb515a0e2d995ed95191b75484-29" + 1337 + 2023-07-12T14:41:46.000Z + 151306240 + + + false + 1337 + 2023-07-12T14:39:22.000Z + 5678 + + + 42 + + + ` + + it('should parse VersionId as string even if number is provided', () => { + const { objects } = parseListObjects(xml) + + assert.equal(objects[0].versionId, '1234') + assert.equal(objects[1].versionId, '5678') + assert.equal(objects[0].name, '1337') + assert.equal(objects[1].name, '1337') + assert.deepEqual(objects[2], { prefix: '42', size: 0 }) + }) + + it('should parse Size as number', () => { + const { objects } = parseListObjects(xml) + + assert.equal(objects[0].size, 151306240) + assert.equal(objects[1].size, undefined) + }) + }) + }) +})