Skip to content

Commit

Permalink
Make the mox client return 404 for nonexistent files.
Browse files Browse the repository at this point in the history
To match the behaviour of S3, make the mox client return responses
with status code 404 when trying to GET or HEAD a file that doesn't
exist.

Similarly, when trying to DELETE a file that doesn't exist,
don't return an error, but respond with a 204 status code.
  • Loading branch information
mtyaka committed Jan 4, 2012
1 parent 646a60c commit f2d2b3c
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 39 deletions.
18 changes: 6 additions & 12 deletions mox.js
Expand Up @@ -206,7 +206,7 @@ exports.createClient = function createClient(options) {
if (err) {
if (err.code === 'ENOENT') {
// no such file
emitResponse(request, {code:403, err:{code:'AccessDenied', msg:'Access Denied'}});
emitResponse(request, {code:404, err:{code:'NoSuchKey', msg:'The specified key does not exist.'}});
}
else {
// other error
Expand Down Expand Up @@ -246,7 +246,7 @@ exports.createClient = function createClient(options) {
if (err) {
if (err.code === 'ENOENT') {
// no such file
emitResponse(request, {code:403, err:{code:'AccessDenied', msg:'Access Denied'}});
emitResponse(request, {code:404, err:{code:'NoSuchKey', msg:'The specified key does not exist.'}});
}
else {
// other error
Expand All @@ -272,20 +272,14 @@ exports.createClient = function createClient(options) {

// remove the file
fs.unlink(filePath, function(err) {
if (err) {
if (err.code === 'ENOENT') {
// no such file
emitResponse(request, {code:403, err:{code:'AccessDenied', msg:'Access Denied'}});
}
else {
// other error
emitResponse(request, {code:500, err:{code:'InternalError', msg:err.message}});
}
// ignore "no such file" errors
if (err && err.code !== 'ENOENT') {
emitResponse(request, {code:500, err:{code:'InternalError', msg:err.message}});
return;
}
// remove meta data file
fs.unlink(filePath + '.meta', function(err) {
if (err) {
if (err && err.code !== 'ENOENT') {
emitResponse(request, {code:500, err:{code:'InternalError', msg:err.message}});
return;
}
Expand Down
111 changes: 84 additions & 27 deletions test-noxmox.js
Expand Up @@ -10,6 +10,7 @@
var fs = require('fs');
var crypto = require('crypto');
var util = require('util');
var assert = require('assert');

var nox = require('./nox.js');
var mox = require('./mox.js');
Expand All @@ -28,7 +29,7 @@ function runTests() {
var moxclient = mox.createClient(options);
test(moxclient, function() {
var noxclient = nox.createClient(options);
console.log('Testing nox client');
console.log('\nTesting nox client');
test(noxclient, function(){
console.log('\nAll tests completed');
});
Expand All @@ -51,10 +52,30 @@ function test(client, callback) {
download(client, name, t4);
}
function t4() {
remove(client, name, callback);
remove(client, name, t5);
}
function t5() {
statRemoved(client, name, t6);
}
function t6() {
downloadRemoved(client, name, t7);
}
function t7() {
removeRemoved(client, name, callback);
}
}


function logErrors(req) {
req.on('error', function(err) {
console.log(err.message || err);
});
}

function logResponse(res) {
console.log('status code: ' + res.statusCode);
console.log('headers: ' + util.inspect(res.headers));
}


function upload(client, name, buf, callback) {
console.log('\nFile upload');
Expand All @@ -63,62 +84,93 @@ function upload(client, name, buf, callback) {
'Content-Length':buf.length,
'Content-MD5': crypto.createHash('md5').update(buf).digest('base64')
});
req.on('error', function(err) {
console.log(err.message || err);
});
logErrors(req);
req.on('continue', function() {
req.end(buf);
});
req.on('response', function(res) {
console.log('status code: ' + res.statusCode);
console.log('headers: ' + util.inspect(res.headers));
logResponse(res);
res.on('data', function(chunk) {
console.log(chunk);
});
res.on('end', function() {
console.log('Response finished');
if (res.statusCode === 200) callback();
assert.equal(res.statusCode, 200);
callback();
});
});
}


function stat(client, name, callback) {
var req = client.head(name);
req.on('error', function(err) {
console.log(err.message || err);
});
logErrors(req);
console.log('\nFile stat');
req.on('response', function(res) {
console.log('status code: ' + res.statusCode);
console.log('headers: ' + util.inspect(res.headers));
logResponse(res);
res.on('data', function(chunk) {
console.log(chunk);
});
res.on('end', function() {
console.log('Response finished');
assert.equal(res.statusCode, 200);
callback();
});
});
req.end();
}


function statRemoved(client, name, callback) {
var req = client.head(name);
logErrors(req);
console.log('\nNonexistent file stat');
req.on('response', function(res) {
logResponse(res);
res.on('data', function(chunk) {
console.log(chunk);
});
res.on('end', function() {
console.log('Response finished');
if (res.statusCode === 200) callback();
assert.equal(res.statusCode, 404);
callback();
});
});
req.end();
}


function download(client, name, callback) {
var req = client.get(name);
req.on('error', function(err) {
console.log(err.message || err);
});
logErrors(req);
console.log('\nFile download');
req.on('response', function(res) {
console.log('status code: ' + res.statusCode);
console.log('headers: ' + util.inspect(res.headers));
logResponse(res);
var len = 0;
res.on('data', function(chunk) {
len += chunk.length;
});
res.on('end', function() {
console.log('Downloaded ' + len + ' bytes of file data');
if (res.statusCode === 200) callback();
assert.equal(res.statusCode, 200);
callback();
});
});
req.end();
}

function downloadRemoved(client, name, callback) {
var req = client.get(name);
logErrors(req);
console.log('\nNonexistent file download');
req.on('response', function(res) {
logResponse(res);
res.on('data', function(chunk) {
console.log(chunk.toString());
});
res.on('end', function() {
assert.equal(res.statusCode, 404);
callback();
});
});
req.end();
Expand All @@ -127,20 +179,25 @@ function download(client, name, callback) {

function remove(client, name, callback) {
var req = client.del(name);
req.on('error', function(err) {
console.log(err.message || err);
});
logErrors(req);
console.log('\nFile delete');
req.on('response', function(res) {
console.log('status code: ' + res.statusCode);
console.log('headers: ' + util.inspect(res.headers));
logResponse(res);
res.on('data', function(chunk) {
console.log(chunk);
});
res.on('end', function() {
console.log('Response finished');
if (res.statusCode === 204) callback();
assert.equal(res.statusCode, 204);
callback();
});
});
req.end();
}


function removeRemoved(client, name, callback) {
// Trying to removing a nonexistent file, looks the same
// as removing an existent file (status code 204).
remove(client, name, callback);
}

0 comments on commit f2d2b3c

Please sign in to comment.