Skip to content

Loading…

Added support for ListAllMyBuckets, ListBucket and ?delete and such #70

Closed
wants to merge 4 commits into from

2 participants

@richtera
  1. Made the bucket an optional parameter (for ListAllMyBuckets)
  2. Fixed signing so things like ?delete would properly get signed (used to assume ?delete=...)
  3. Added tests for those two.
@domenic

Added the ?delete stuff to my fork at https://github.com/domenic/knox/tree/patches-2

@domenic

So I think the only thing left is ListAllMyBuckets; you can do ListBucket with .get("") (although perhaps a sugar method would be useful, although it would need XML parsing). Knox is entirely centered around one client-per-bucket right now though, so it'd be a bit tricky. Maybe a new top-level API like knox.listBuckets({ key, secret }).

Would you be up for implementing something like that?

@richtera

That would be possible, yes. I'll look into it although it might take a little bit of time due to other projects getting in the way.

@domenic

Closing in favor of #104 and #101.

@domenic domenic closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 11, 2012
  1. @richtera
Commits on Apr 15, 2012
  1. @richtera
  2. @richtera

    Kick version number.

    richtera committed
Commits on May 5, 2012
  1. @richtera

    Add and fix tests.

    richtera committed
This page is out of date. Refresh to see the latest.
Showing with 130 additions and 50 deletions.
  1. +4 −2 lib/knox/auth.js
  2. +2 −1 lib/knox/client.js
  3. +1 −1 package.json
  4. +14 −10 test/auth.test.js
  5. +102 −32 test/knox.test.js
  6. +7 −4 test/utils.test.js
View
6 lib/knox/auth.js
@@ -179,9 +179,11 @@ exports.canonicalizeResource = function(resource){
, buf = [];
Object.keys(url.query).forEach(function(key){
- if (!~keys.indexOf(key)) return;
var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]);
- buf.push(key + val);
+ if (key === '') // this is something like ?delete (which is part of the S3 api) so it has no key because there is no '='
+ buf.push(val.substring(1));
+ else
+ buf.push(key + val);
});
return path + (buf.length
View
3 lib/knox/client.js
@@ -36,7 +36,8 @@ var Client = module.exports = exports = function Client(options) {
this.port = 80;
if (!options.key) throw new Error('aws "key" required');
if (!options.secret) throw new Error('aws "secret" required');
- if (!options.bucket) throw new Error('aws "bucket" required');
+ // Not requiring a bucket to allow listing or buckets for example.
+ //if (!options.bucket) throw new Error('aws "bucket" required');
utils.merge(this, options);
};
View
2 package.json
@@ -2,7 +2,7 @@
"name": "knox",
"description": "Amazon S3 client",
"keywords": ["aws", "amazon", "s3"],
- "version": "0.0.9",
+ "version": "0.0.11",
"author": "TJ Holowaychuk <tj@learnboost.com>",
"main": "./index.js",
"engines": { "node": ">= 0.2.0" },
View
24 test/auth.test.js
@@ -4,10 +4,11 @@
*/
var knox = require('knox')
- , auth = knox.auth;
+ , auth = knox.auth
+ , assert = require('assert');
module.exports = {
- 'test .stringToSign()': function(assert){
+ 'test .stringToSign()': function(done){
var str = auth.stringToSign({
verb: 'PUT'
, md5: '09c68b914d66457508f6ad727d860d5b'
@@ -15,7 +16,7 @@ module.exports = {
, resource: '/learnboost'
, date: new Date('Mon, May 25 1987 00:00:00 GMT')
});
-
+
var expected = [
'PUT'
, '09c68b914d66457508f6ad727d860d5b'
@@ -23,11 +24,12 @@ module.exports = {
, new Date('Mon, May 25 1987 00:00:00 GMT').toUTCString()
, '/learnboost'
].join('\n');
-
+
assert.equal(expected, str);
+ done();
},
-
- 'test .sign()': function(assert){
+
+ 'test .sign()': function(done){
var str = auth.sign({
verb: 'PUT'
, secret: 'test'
@@ -38,22 +40,24 @@ module.exports = {
});
assert.equal('7xIdjyy+W17/k0le5kwBnfrZTiM=', str);
+ done();
},
-
- 'test .canonicalizeHeaders()': function(assert){
+
+ 'test .canonicalizeHeaders()': function(done){
var str = auth.canonicalizeHeaders({
'X-Amz-Date': 'some date'
, 'X-Amz-Acl': 'private'
, 'X-Foo': 'bar'
});
-
+
var expected = [
'x-amz-acl:private'
, 'x-amz-date:some date'
].join('\n');
assert.equal(expected, str);
-
+
assert.equal('', auth.canonicalizeHeaders({}));
+ done();
}
};
View
134 test/knox.test.js
@@ -4,7 +4,9 @@
*/
var knox = require('knox')
- , fs = require('fs');
+ , fs = require('fs')
+ , assert = require('assert')
+ , crypto = require('crypto');
try {
var auth = JSON.parse(fs.readFileSync('auth', 'ascii'));
@@ -18,11 +20,12 @@ try {
var jsonFixture = __dirname + '/fixtures/user.json';
module.exports = {
- 'test .version': function(assert){
+ 'test .version': function(done){
assert.match(knox.version, /^\d+\.\d+\.\d+$/);
+ done();
},
-
- 'test .createClient() invalid': function(assert){
+
+ 'test .createClient() invalid': function(done){
var err;
try {
knox.createClient({});
@@ -30,7 +33,7 @@ module.exports = {
err = e;
}
assert.equal('aws "key" required', err.message);
-
+
var err;
try {
knox.createClient({ key: 'foo' });
@@ -38,7 +41,8 @@ module.exports = {
err = e;
}
assert.equal('aws "secret" required', err.message);
-
+
+/* Bucket no longer required
var err;
try {
knox.createClient({ key: 'foo', secret: 'bar' });
@@ -46,22 +50,38 @@ module.exports = {
err = e;
}
assert.equal('aws "bucket" required', err.message);
+*/
+ done();
},
-
- 'test .createClient() valid': function(assert){
+
+ 'test .createClient() valid': function(done){
var client = knox.createClient({
key: 'foobar'
, secret: 'baz'
, bucket: 'misc'
});
-
+
assert.equal('foobar', client.key);
assert.equal('baz', client.secret);
assert.equal('misc', client.bucket);
assert.equal('s3.amazonaws.com', client.endpoint);
+ done();
+ },
+
+ 'test .createClient() valid': function(done){
+ var client = knox.createClient({
+ key: 'foobar'
+ , secret: 'baz'
+ });
+
+ assert.equal('foobar', client.key);
+ assert.equal('baz', client.secret);
+ assert.equal(undefined, client.bucket);
+ assert.equal('s3.amazonaws.com', client.endpoint);
+ done();
},
-
- 'test .createClient() custom endpoint': function(assert){
+
+ 'test .createClient() custom endpoint': function(done){
var client = knox.createClient({
key: 'foobar'
, secret: 'baz'
@@ -70,9 +90,10 @@ module.exports = {
});
assert.equal('s3-eu-west-1.amazonaws.com', client.endpoint);
+ done();
},
- 'test .putFile()': function(assert, done){
+ 'test .putFile()': function(done){
var n = 0;
client.putFile(jsonFixture, '/test/user2.json', function(err, res){
assert.ok(!err, 'putFile() got an error!');
@@ -83,8 +104,17 @@ module.exports = {
}).end();
});
},
-
- 'test .put()': function(assert, done){
+
+ 'test .putFile()': function(done){
+ var n = 0;
+ client.putFile(jsonFixture, '/test/user3.json', function(err, res){
+ assert.ok(!err, 'putFile() got an error!');
+ assert.equal(200, res.statusCode);
+ done();
+ });
+ },
+
+ 'test .put()': function(done){
var n = 0;
fs.stat(jsonFixture, function(err, stat){
if (err) throw err;
@@ -109,8 +139,8 @@ module.exports = {
})
});
},
-
- 'test .putStream()': function(assert, done){
+
+ 'test .putStream()': function(done){
var stream = fs.createReadStream(jsonFixture);
client.putStream(stream, '/test/user.json', function(err, res){
assert.ok(!err);
@@ -118,8 +148,29 @@ module.exports = {
done();
});
},
-
- 'test .getFile()': function(assert, done){
+
+ 'test listing buckets': function (done){
+ var client = knox.createClient({
+ key: auth.key
+ , secret: auth.secret
+ });
+
+ client.getFile('', function(err, res){
+ assert.ok(!err);
+ assert.equal(200, res.statusCode);
+ assert.equal('application/xml', res.headers['content-type']);
+ var data = '';
+ res.on('data', function (chunk) {
+ data += chunk;
+ });
+ res.on('end', function () {
+ assert.match(data, /<ListAllMyBucketsResult/, "doesn't contain a listallmybuckets output");
+ done();
+ });
+ });
+ },
+
+ 'test .getFile()': function(done){
client.getFile('/test/user.json', function(err, res){
assert.ok(!err);
assert.equal(200, res.statusCode);
@@ -128,8 +179,8 @@ module.exports = {
done();
});
},
-
- 'test .get()': function(assert, done){
+
+ 'test .get()': function(done){
client.get('/test/user.json').on('response', function(res){
assert.equal(200, res.statusCode);
assert.equal('application/json', res.headers['content-type'])
@@ -137,8 +188,8 @@ module.exports = {
done();
}).end();
},
-
- 'test .head()': function(assert, done){
+
+ 'test .head()': function(done){
client.head('/test/user.json').on('response', function(res){
assert.equal(200, res.statusCode);
assert.equal('application/json', res.headers['content-type'])
@@ -146,8 +197,8 @@ module.exports = {
done();
}).end();
},
-
- 'test .headFile()': function(assert, done){
+
+ 'test .headFile()': function(done){
client.headFile('/test/user.json', function(err, res){
assert.ok(!err);
assert.equal(200, res.statusCode);
@@ -156,30 +207,49 @@ module.exports = {
done();
});
},
-
- 'test .del()': function(assert, done){
+
+ 'test .del()': function(done){
client.del('/test/user.json').on('response', function(res){
assert.equal(204, res.statusCode);
done();
}).end();
},
-
- 'test .deleteFile()': function(assert, done){
+
+ 'test .deleteFile()': function(done){
client.deleteFile('/test/user2.json', function(err, res){
assert.ok(!err);
assert.equal(204, res.statusCode);
done();
});
},
-
- 'test .get() 404': function(assert, done){
+
+ 'test /?delete': function (done) {
+ var xml = ['<?xml version="1.0" encoding="UTF-8"?>\n','<Delete>'];
+ xml.push('<Object><Key>/test/user3.json</Key></Object>');
+ xml.push('</Delete>');
+ xml = xml.join('');
+ var req = client.request('POST', '/?delete', {
+ 'Content-Length': xml.length,
+ 'Content-MD5': crypto.createHash('md5').update(xml).digest('base64'),
+ 'Accept:': '*/*',
+ }).on('error', function (err) {
+ assert.ok(!err);
+ }).on('response', function (res) {
+ assert.equal(200, res.statusCode);
+ done();
+ });
+ req.write(xml);
+ req.end();
+ },
+
+ 'test .get() 404': function(done){
client.get('/test/user.json').on('response', function(res){
assert.equal(404, res.statusCode);
done();
}).end();
},
-
- 'test .head() 404': function(assert, done){
+
+ 'test .head() 404': function(done){
client.head('/test/user.json').on('response', function(res){
assert.equal(404, res.statusCode);
done();
View
11 test/utils.test.js
@@ -4,14 +4,17 @@
*/
var knox = require('knox')
- , utils = knox.utils;
+ , utils = knox.utils
+ , assert = require('assert');
module.exports = {
- 'test .base64.encode()': function(assert){
+ 'test .base64.encode()': function(done){
assert.equal('aGV5', utils.base64.encode('hey'));
+ done();
},
-
- 'test .base64.decode()': function(assert){
+
+ 'test .base64.decode()': function(done){
assert.equal('hey', utils.base64.decode('aGV5'));
+ done();
}
};
Something went wrong with that request. Please try again.