@@ -12,6 +12,7 @@ const backbeatProxy = httpProxy.createProxyServer({
1212} ) ;
1313const { auth, errors, errorInstances, s3middleware, s3routes, models, storage, versioning } = require ( 'arsenal' ) ;
1414const { decode, encode } = versioning . VersionID ;
15+ const { ExternalNullVersionId } = versioning . VersioningConstants ;
1516const {
1617 VersionIdCollisionException,
1718 StaleMicroVersionIdException,
@@ -434,35 +435,28 @@ function putData(request, response, bucketInfo, objMd, log, callback) {
434435
435436 const incomingVersionIdEncoded = request . headers [ 'x-scal-version-id' ] ;
436437 if ( incomingVersionIdEncoded !== undefined ) {
437- const incomingVersionIdDecoded =
438- incomingVersionIdEncoded !== 'null' ? decode ( incomingVersionIdEncoded ) : 'null' ;
439- if ( incomingVersionIdDecoded instanceof Error ) {
440- log . error ( 'crr putData: failed to decode x-scal-version-id header' , {
441- method : 'putData' ,
442- error : incomingVersionIdDecoded . message ,
443- } ) ;
444- return callback (
445- errorInstances . BadRequest . customizeDescription ( 'bad request: invalid x-scal-version-id header' ) ,
446- ) ;
447- }
448- if ( objMd && objMd . versionId === incomingVersionIdDecoded ) {
449- // Data already at destination for this version; return 409 with the existing
450- // microVersionId so backbeat can decide if putMetadata is still needed.
451- log . debug ( 'crr putData: version already at destination' , {
452- method : 'putData' ,
453- bucketName : request . bucketName ,
454- objectKey : request . objectKey ,
455- hasMicroVersionId : ! ! objMd . microVersionId ,
456- } ) ;
457- request . resume ( ) ;
458- return _respondWithHeaderCrrConflict (
459- response ,
460- log ,
461- callback ,
462- VersionIdCollisionException . name ,
463- 'version id already at destination' ,
464- objMd . microVersionId ,
465- ) ;
438+ // ExternalNullVersionId means a null version, which does not need decoding
439+ if ( incomingVersionIdEncoded !== ExternalNullVersionId ) {
440+ if ( objMd ) {
441+ // objMd is the specific version requested by the header x-scal-version-id.
442+ // Its existence means the data is already at the destination. Return 409 with the
443+ // existing microVersionId so backbeat can decide if putMetadata is still needed.
444+ log . debug ( 'crr putData: version already at destination' , {
445+ method : 'putData' ,
446+ bucketName : request . bucketName ,
447+ objectKey : request . objectKey ,
448+ hasMicroVersionId : ! ! objMd . microVersionId ,
449+ } ) ;
450+ request . resume ( ) ;
451+ return _respondWithHeaderCrrConflict (
452+ response ,
453+ log ,
454+ callback ,
455+ VersionIdCollisionException . name ,
456+ 'version id already at destination' ,
457+ objMd . microVersionId ,
458+ ) ;
459+ }
466460 }
467461 }
468462
@@ -2039,15 +2033,31 @@ function routeBackbeat(clientIP, request, response, log) {
20392033 if ( ! isObjectRequest ) {
20402034 return routeNonObjectRequest ( request , response , userInfo , log , next ) ;
20412035 }
2042- const decodedVidResult = decodeVersionId ( request . query ) ;
2043- if ( decodedVidResult instanceof Error ) {
2044- log . trace ( 'invalid versionId query' , {
2045- versionId : request . query . versionId ,
2046- error : decodedVidResult ,
2047- } ) ;
2048- return next ( errors . InvalidArgument ) ;
2036+ const versionIdHeader = request . headers [ 'x-scal-version-id' ] ;
2037+ let versionId ;
2038+ if ( versionIdHeader !== undefined ) {
2039+ if ( versionIdHeader !== ExternalNullVersionId ) {
2040+ const decoded = decode ( versionIdHeader ) ;
2041+ if ( decoded instanceof Error ) {
2042+ return next (
2043+ errorInstances . BadRequest . customizeDescription (
2044+ 'bad request: invalid x-scal-version-id header' ,
2045+ ) ,
2046+ ) ;
2047+ }
2048+ versionId = decoded ;
2049+ }
2050+ } else {
2051+ const decodedVidResult = decodeVersionId ( request . query ) ;
2052+ if ( decodedVidResult instanceof Error ) {
2053+ log . trace ( 'invalid versionId query' , {
2054+ versionId : request . query . versionId ,
2055+ error : decodedVidResult ,
2056+ } ) ;
2057+ return next ( errors . InvalidArgument ) ;
2058+ }
2059+ versionId = decodedVidResult ;
20492060 }
2050- const versionId = decodedVidResult ;
20512061 if ( useMultipleBackend ) {
20522062 if ( request . resourceType === 'multiplebackendmetadata' ) {
20532063 return backbeatRoutes [ request . method ] [ request . resourceType ] ( request , response , log , next ) ;
0 commit comments