mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-17 16:50:22 +00:00
@uppy/aws-s3: wrong upload meta in upload-success event (#6234)
right now whenever you upload any file through multipart upload you'll find empty body returned in `upload-success` event cause : response from completeMultipartRequest returned in CamelCase which was not parsed correctly ```xml <?xml version="1.0" encoding="UTF-8"?> <CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Location>https://testbucketnewfix.s3.eu-north-1.amazonaws.com/13febe01-8d5b-4ed3-bda1-9620fc37c694-VSCode-darwin-universal.dmg</Location><Bucket>testbucketnewfix</Bucket><Key>13febe01-8d5b-4ed3-bda1-9620fc37c694-VSCode-darwin-universal.dmg</Key><ETag>"be4129821e06a893b453f1373995202b-49"</ETag><ChecksumCRC64NVME>Wjr7mcJOfU0=</ChecksumCRC64NVME><ChecksumType>FULL_OBJECT</ChecksumType></CompleteMultipartUploadResult> ``` --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
50de6d1066
commit
da46951771
4 changed files with 27 additions and 39 deletions
|
|
@ -621,25 +621,36 @@ class S3mini {
|
|||
|
||||
const parsed = U.parseXml(await res.text()) as Record<string, unknown>
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
// Check for both cases
|
||||
// Check for both cases (camelCase from our parser, PascalCase from S3)
|
||||
const result =
|
||||
parsed.completeMultipartUploadResult ||
|
||||
parsed.CompleteMultipartUploadResult ||
|
||||
parsed
|
||||
|
||||
if (result && typeof result === 'object') {
|
||||
const resultObj = result as Record<string, unknown>
|
||||
const r = result as Record<string, unknown>
|
||||
|
||||
// Handle ETag in all its variations
|
||||
const etag = resultObj.ETag || resultObj.eTag || resultObj.etag
|
||||
if (etag && typeof etag === 'string') {
|
||||
return {
|
||||
...resultObj,
|
||||
etag: U.sanitizeETag(etag),
|
||||
} as IT.CompleteMultipartUploadResult
|
||||
// S3 returns PascalCase (Location, Bucket, Key, ETag).
|
||||
// Normalize to lowercase for our type interface.
|
||||
const resultLocation = (r.Location || r.location) as string | undefined
|
||||
const resultBucket = (r.Bucket || r.bucket) as string | undefined
|
||||
const resultKey = (r.Key || r.key) as string | undefined
|
||||
const rawEtag = (r.ETag || r.eTag || r.etag) as string | undefined
|
||||
|
||||
if (!resultLocation || !resultKey) {
|
||||
throw new Error(
|
||||
`${C.ERROR_PREFIX}CompleteMultipartUpload response missing Location or Key: ${JSON.stringify(r)}`,
|
||||
)
|
||||
}
|
||||
|
||||
return result as IT.CompleteMultipartUploadResult
|
||||
const etag = rawEtag ? U.sanitizeETag(rawEtag) : ''
|
||||
|
||||
return {
|
||||
location: resultLocation,
|
||||
bucket: resultBucket ?? '',
|
||||
key: resultKey,
|
||||
etag,
|
||||
} satisfies IT.CompleteMultipartUploadResult
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ export { S3mini } from './S3.js'
|
|||
export type {
|
||||
CompleteMultipartUploadResult,
|
||||
ErrorWithCode,
|
||||
ListMultipartUploadResponse,
|
||||
S3Config,
|
||||
UploadPart,
|
||||
} from './types.js'
|
||||
|
|
|
|||
|
|
@ -85,30 +85,6 @@ export interface CompleteMultipartUploadResult {
|
|||
bucket: string
|
||||
key: string
|
||||
etag: string
|
||||
eTag: string // for backward compatibility
|
||||
ETag: string // for backward compatibility
|
||||
}
|
||||
|
||||
export interface ListMultipartUploadSuccess {
|
||||
listMultipartUploadsResult: {
|
||||
bucket: string
|
||||
key: string
|
||||
uploadId: string
|
||||
size?: number
|
||||
mtime?: Date
|
||||
etag?: string
|
||||
eTag?: string // for backward compatibility
|
||||
parts: UploadPart[]
|
||||
isTruncated: boolean
|
||||
uploads: UploadPart[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface MultipartUploadError {
|
||||
error: {
|
||||
code: string
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ErrorWithCode {
|
||||
|
|
@ -116,10 +92,6 @@ export interface ErrorWithCode {
|
|||
cause?: { code?: string }
|
||||
}
|
||||
|
||||
export type ListMultipartUploadResponse =
|
||||
| ListMultipartUploadSuccess
|
||||
| MultipartUploadError
|
||||
|
||||
export type HttpMethod = 'POST' | 'GET' | 'HEAD' | 'PUT' | 'DELETE'
|
||||
|
||||
export type XmlValue = string | XmlMap | boolean | number | null
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ const minioSpecific = (bucket) => {
|
|||
uploaded,
|
||||
])
|
||||
expect(result.etag).toBeDefined()
|
||||
expect(result.location).toBeDefined()
|
||||
expect(result.location).toContain(key)
|
||||
expect(result.key).toBe(key)
|
||||
|
||||
await s3client.deleteObject(key)
|
||||
})
|
||||
|
|
@ -223,6 +226,9 @@ const minioSpecific = (bucket) => {
|
|||
|
||||
const result = await s3.completeMultipartUpload(key, uploadId, [uploaded])
|
||||
expect(result.etag).toBeDefined()
|
||||
expect(result.location).toBeDefined()
|
||||
expect(result.location).toContain(key)
|
||||
expect(result.key).toBe(key)
|
||||
|
||||
await s3.deleteObject(key)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue