aws-sdkを使ってRiakCSにマルチパードアップロードするときに403エラーでハマった時のメモ。
#原因
lib/signers/s3.js内でsignatureを生成する際に、uploadIdに含まれる=
が%3D
にエスケープされているせいで認証に失敗してしまっている様子。
#回避策
途中で%3D
を=
に戻してあげる
aws-sdk-custom.js
'use strict';
var AWS = require('aws-sdk');
var inherit = AWS.util.inherit;
/**
* @api private
*/
AWS.Signers.S3 = inherit(AWS.Signers.S3, {
canonicalizedResource: function canonicalizedResource() {
var r = this.request;
var parts = r.path.split('?');
var path = parts[0];
var querystring = parts[1];
var resource = '';
if (r.virtualHostedBucket)
resource += '/' + r.virtualHostedBucket;
resource += path;
if (querystring) {
// collect a list of sub resources and query params that need to be signed
var resources = [];
AWS.util.arrayEach.call(this, querystring.split('&'), function (param) {
var name = param.split('=')[0];
var value = param.split('=')[1];
if (this.subResources[name] || this.responseHeaders[name]) {
var subresource = { name: name };
if (value !== undefined) {
if (this.subResources[name]) {
subresource.value = value;
} else {
subresource.value = decodeURIComponent(value);
}
}
resources.push(subresource);
}
});
resources.sort(function (a, b) { return a.name < b.name ? -1 : 1; });
if (resources.length) {
querystring = [];
AWS.util.arrayEach(resources, function (res) {
if (res.value === undefined)
querystring.push(res.name);
else {
// '%3D'を'='に置換
if (res.name === 'uploadId') {
res.value = res.value.replace(/%3D/g, '=');
}
querystring.push(res.name + '=' + res.value);
}
});
resource += '?' + querystring.join('&');
}
}
return resource;
},
});
module.exports = AWS;
###使用例
demo.js
var fs = require('fs');
var AWS = require('./aws-sdk-custom');
var config = require('./config.json');
var s3 = new AWS.S3(config);
var params = {
Bucket: 'bucket',
Key: 'key',
Body: fs.createReadStream('./bigfile')
};
s3.upload(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
もっといい方法がある気がする。