Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions lib/sproxyd.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class SproxydClient {
// when current endpoint matches the endpoint of the failed request
const currentBootstrap = this.getCurrentBootstrap();

this._handleRequest(method, stream, size, key, log, (err, ret) => {
this._handleRequest(method, stream, size, key, log, (err, ...rest) => {
if (err && !err.isExpected) {
if (receivedResponse === true) {
log.fatal('multiple responses from sproxyd, trying to '
Expand Down Expand Up @@ -273,7 +273,7 @@ class SproxydClient {
}
receivedResponse = true;
log.end().debug('request received response');
return callback(err, ret);
return callback(err, ...rest);
}, args, payload);
}

Expand Down Expand Up @@ -315,11 +315,10 @@ class SproxydClient {
}
return callback(errorProcessed);
}
// We return the key
log.debug('stored to sproxyd', {
statusCode: response.statusCode,
});
return callback(null, newKey);
return callback(null, newKey, response);
});

const startPayloadStreaming = () => {
Expand Down Expand Up @@ -420,11 +419,13 @@ class SproxydClient {
*/
put(stream, size, params, reqUids, callback, keyScheme) {
const log = this.createLogger(reqUids);
this._failover('PUT', stream, size, keyScheme, 0, log, (err, key) => {
this._failover('PUT', stream, size, keyScheme, 0, log, (err, key, response) => {
if (err) {
return callback(err);
}
return callback(null, key);
const version = response && response.headers
? response.headers['x-scal-version'] : undefined;
return callback(null, key, version);
}, params);
}

Expand Down Expand Up @@ -455,6 +456,24 @@ class SproxydClient {
}, reqParams);
}

/**
* Update the user metadata of an existing object without replacing its content.
* Sends a zero-byte PUT with x-scal-cmd: update-usermd.
* @param {string} keyScheme - sproxyd key
* @param {string} metadata - metadata to set in x-scal-usermd header
* @param {string} reqUids - The serialized request id
* @param {SproxydClient~putCallback} callback - callback
* @returns {undefined}
*/
putUserMetadata(keyScheme, metadata, params, reqUids, callback) {
const reqParams = Object.assign({}, params, {
headers: Object.assign({}, params && params.headers, {
'x-scal-cmd': 'update-usermd',
}),
});
this.putEmptyObject(keyScheme, metadata, reqParams, reqUids, callback);
}

/**
* This sends a GET request to sproxyd.
* @param {String} key - The key associated to the value
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"engines": {
"node": ">=20"
},
"version": "9.0.0",
"version": "9.1.0",
"description": "sproxyd client",
"main": "index.js",
"scripts": {
Expand Down
66 changes: 57 additions & 9 deletions tests/unit/sproxyd.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,25 @@ function handler(req, res) {
return;
}
}
server[key] = Buffer.alloc(0);
if (req.headers['x-scal-usermd']) {
md[key] = req.headers['x-scal-usermd'];
}
versions[key] = (versions[key] || 0) + 64;
req.on('data', data => {
server[key] = Buffer.concat([server[key], data]);
})
.on('end', () => makeResponse(res, 200, 'OK', null, null,
if (req.headers['x-scal-cmd'] === 'update-usermd') {
if (req.headers['x-scal-usermd']) {
md[key] = req.headers['x-scal-usermd'];
}
versions[key] = (versions[key] || 0) + 64;
req.resume().on('end', () => makeResponse(res, 200, 'OK', null, null,
versions[key]));
} else {
server[key] = Buffer.alloc(0);
if (req.headers['x-scal-usermd']) {
md[key] = req.headers['x-scal-usermd'];
}
versions[key] = (versions[key] || 0) + 64;
req.on('data', data => {
server[key] = Buffer.concat([server[key], data]);
})
.on('end', () => makeResponse(res, 200, 'OK', null, null,
versions[key]));
}
} else if (req.method === 'GET') {
if (!server[key]) {
consumeAndMakeResponse(req, res, 404, 'NoSuchPath');
Expand Down Expand Up @@ -323,6 +332,45 @@ const clientImmutableWithFailover = new Sproxy({
});
});

it('should update user metadata via putUserMetadata without altering content', done => {
const newMd = generateMD();
let testKey;
let initialVersion;
const upStream = new stream.PassThrough();
upStream.write(upload);
upStream.end();
async.series([
next => client.put(upStream, upload.length, parameters, reqUid,
(err, key, version) => {
testKey = key;
initialVersion = version;
next(err);
}),
next => client.putUserMetadata(testKey, newMd,
{ query: { version: initialVersion } }, reqUid, next),
next => client.getUserMetadata(testKey, reqUid, (err, data) => {
assert.strictEqual(data, newMd);
next(err);
}),
next => checkKeyContent(client, testKey, upload, reqUid, next),
], done);
});

it('should fail putUserMetadata with wrong version', done => {
const upStream = new stream.PassThrough();
upStream.write(upload);
upStream.end();
async.waterfall([
next => client.put(upStream, upload.length, parameters, reqUid, next),
(key, version, next) => client.putUserMetadata(key, generateMD(),
{ query: { version: 0 } }, reqUid, err => {
assert(err, 'expected error for wrong version');
assert.strictEqual(err.code, 412);
next();
}),
], done);
});

it('Get HEAD should return an error', done => {
client.getUserMetadata(generateKey(), reqUid, err => {
assert.notStrictEqual(err, null);
Expand Down
Loading