Compare commits
5 Commits
developmen
...
ft/ks
Author | SHA1 | Date |
---|---|---|
Vinh Tao | 28a5ef756a | |
Vinh Tao | 626538f0c4 | |
Vinh Tao | 4e5f9ee9ff | |
Vinh Tao | 11464ff33b | |
Vinh Tao | 33edd9591a |
|
@ -6,6 +6,8 @@ import escapeForXML from '../utilities/escapeForXML';
|
||||||
import { pushMetric } from '../utapi/utilities';
|
import { pushMetric } from '../utapi/utilities';
|
||||||
import { errors } from 'arsenal';
|
import { errors } from 'arsenal';
|
||||||
|
|
||||||
|
import utils from '../utils';
|
||||||
|
|
||||||
// Sample XML response:
|
// Sample XML response:
|
||||||
/* <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
/* <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
||||||
<Name>example-bucket</Name>
|
<Name>example-bucket</Name>
|
||||||
|
@ -68,9 +70,9 @@ export default function bucketGet(authInfo, request, log, callback) {
|
||||||
};
|
};
|
||||||
const listParams = {
|
const listParams = {
|
||||||
maxKeys: actualMaxKeys,
|
maxKeys: actualMaxKeys,
|
||||||
delimiter: params.delimiter,
|
delimiter: utils.encodeObjectKey(params.delimiter),
|
||||||
marker: params.marker,
|
marker: utils.encodeObjectKey(params.marker),
|
||||||
prefix: params.prefix,
|
prefix: utils.encodeObjectKey(params.prefix),
|
||||||
};
|
};
|
||||||
|
|
||||||
services.metadataValidateAuthorization(metadataValParams, err => {
|
services.metadataValidateAuthorization(metadataValParams, err => {
|
||||||
|
@ -93,11 +95,12 @@ export default function bucketGet(authInfo, request, log, callback) {
|
||||||
);
|
);
|
||||||
const isTruncated = list.IsTruncated ? 'true' : 'false';
|
const isTruncated = list.IsTruncated ? 'true' : 'false';
|
||||||
const xmlParams = [
|
const xmlParams = [
|
||||||
{ tag: 'Prefix', value: listParams.prefix },
|
{ tag: 'Prefix', value: params.prefix },
|
||||||
{ tag: 'NextMarker', value: list.NextMarker },
|
{ tag: 'NextMarker',
|
||||||
{ tag: 'Marker', value: listParams.marker },
|
value: utils.decodeObjectKey(list.NextMarker) },
|
||||||
|
{ tag: 'Marker', value: params.marker },
|
||||||
{ tag: 'MaxKeys', value: requestMaxKeys },
|
{ tag: 'MaxKeys', value: requestMaxKeys },
|
||||||
{ tag: 'Delimiter', value: listParams.delimiter },
|
{ tag: 'Delimiter', value: params.delimiter },
|
||||||
{ tag: 'EncodingType', value: encoding },
|
{ tag: 'EncodingType', value: encoding },
|
||||||
{ tag: 'IsTruncated', value: isTruncated },
|
{ tag: 'IsTruncated', value: isTruncated },
|
||||||
];
|
];
|
||||||
|
@ -114,7 +117,7 @@ export default function bucketGet(authInfo, request, log, callback) {
|
||||||
|
|
||||||
list.Contents.forEach(item => {
|
list.Contents.forEach(item => {
|
||||||
const v = item.value;
|
const v = item.value;
|
||||||
const objectKey = escapeXmlFn(item.key);
|
const objectKey = escapeXmlFn(utils.decodeObjectKey(item.key));
|
||||||
|
|
||||||
xml.push(
|
xml.push(
|
||||||
'<Contents>',
|
'<Contents>',
|
||||||
|
@ -131,7 +134,7 @@ export default function bucketGet(authInfo, request, log, callback) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
list.CommonPrefixes.forEach(item => {
|
list.CommonPrefixes.forEach(item => {
|
||||||
const val = escapeXmlFn(item);
|
const val = escapeXmlFn(utils.decodeObjectKey(item));
|
||||||
xml.push(
|
xml.push(
|
||||||
`<CommonPrefixes><Prefix>${val}</Prefix></CommonPrefixes>`
|
`<CommonPrefixes><Prefix>${val}</Prefix></CommonPrefixes>`
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,6 +42,11 @@ function checkUnsuportedRoutes(req, res, log) {
|
||||||
}
|
}
|
||||||
const method = routeMap[req.method.toUpperCase()];
|
const method = routeMap[req.method.toUpperCase()];
|
||||||
if (method) {
|
if (method) {
|
||||||
|
if (req.objectKey) {
|
||||||
|
const request = req;
|
||||||
|
request.objectKey = utils.encodeObjectKey(request.objectKey);
|
||||||
|
return method(request, res, log, statsClient);
|
||||||
|
}
|
||||||
return method(req, res, log, statsClient);
|
return method(req, res, log, statsClient);
|
||||||
}
|
}
|
||||||
return routesUtils.responseXMLBody(errors.MethodNotAllowed, null, res, log);
|
return routesUtils.responseXMLBody(errors.MethodNotAllowed, null, res, log);
|
||||||
|
|
44
lib/utils.js
44
lib/utils.js
|
@ -7,6 +7,8 @@ import constants from '../constants';
|
||||||
|
|
||||||
const utils = {};
|
const utils = {};
|
||||||
|
|
||||||
|
const WIDTH = 8; // byte length of the hexa representation of a UTF-8 character
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bucket name from the request of a virtually hosted bucket
|
* Get bucket name from the request of a virtually hosted bucket
|
||||||
* @param {object} request - HTTP request object
|
* @param {object} request - HTTP request object
|
||||||
|
@ -314,4 +316,46 @@ utils.mapHeaders = function mapHeaders(headers, addHeaders) {
|
||||||
return headers;
|
return headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a padded hexa representation of a string; each UTF-8 character of a
|
||||||
|
* string is represented by the 8-bytes hexa string of its character code.
|
||||||
|
*
|
||||||
|
* @param {string} key - the key to be encoded, applications using this
|
||||||
|
* must ensure that the key is a non-empty string
|
||||||
|
* @return {string} - the padded hexa representation of the key
|
||||||
|
*/
|
||||||
|
utils.encodeObjectKey = function encodeObjectKey(key) {
|
||||||
|
if (key) {
|
||||||
|
let encoded = '';
|
||||||
|
const length = key.length;
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
// padding the hexa of each character
|
||||||
|
encoded += `000000${key.charCodeAt(i).toString(16)}`.slice(-WIDTH);
|
||||||
|
}
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recover the original UTF-8 representation of a padded hexa string.
|
||||||
|
*
|
||||||
|
* @param {string} hex - the padded hexa string to be decoded; applications
|
||||||
|
* must ensure the validity of the string
|
||||||
|
*
|
||||||
|
* @return {string} - the decoded UTF-8 string of the padded hexa string
|
||||||
|
*/
|
||||||
|
utils.decodeObjectKey = function decodeObjectKey(hex) {
|
||||||
|
if (hex) {
|
||||||
|
let decoded = '';
|
||||||
|
const length = hex.length;
|
||||||
|
for (let i = 0; i < length; i += WIDTH) {
|
||||||
|
decoded += String.fromCharCode(
|
||||||
|
Number.parseInt(hex.slice(i, i + WIDTH), 16));
|
||||||
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
};
|
||||||
|
|
||||||
export default utils;
|
export default utils;
|
||||||
|
|
|
@ -12,6 +12,8 @@ import DummyRequest from '../DummyRequest';
|
||||||
|
|
||||||
import { errors } from 'arsenal';
|
import { errors } from 'arsenal';
|
||||||
|
|
||||||
|
import utils from '../../../lib/utils';
|
||||||
|
|
||||||
const authInfo = makeAuthInfo('accessKey1');
|
const authInfo = makeAuthInfo('accessKey1');
|
||||||
const bucketName = 'bucketname';
|
const bucketName = 'bucketname';
|
||||||
const delimiter = '/';
|
const delimiter = '/';
|
||||||
|
@ -44,21 +46,21 @@ describe('bucketGet API', () => {
|
||||||
headers: {},
|
headers: {},
|
||||||
url: `/${bucketName}/${objectName1}`,
|
url: `/${bucketName}/${objectName1}`,
|
||||||
namespace,
|
namespace,
|
||||||
objectKey: objectName1,
|
objectKey: utils.encodeObjectKey(objectName1),
|
||||||
}, postBody);
|
}, postBody);
|
||||||
testPutObjectRequest2 = new DummyRequest({
|
testPutObjectRequest2 = new DummyRequest({
|
||||||
bucketName,
|
bucketName,
|
||||||
headers: {},
|
headers: {},
|
||||||
url: `/${bucketName}/${objectName2}`,
|
url: `/${bucketName}/${objectName2}`,
|
||||||
namespace,
|
namespace,
|
||||||
objectKey: objectName2,
|
objectKey: utils.encodeObjectKey(objectName2),
|
||||||
}, postBody);
|
}, postBody);
|
||||||
testPutObjectRequest3 = new DummyRequest({
|
testPutObjectRequest3 = new DummyRequest({
|
||||||
bucketName,
|
bucketName,
|
||||||
headers: {},
|
headers: {},
|
||||||
url: `/${bucketName}/${objectName3}`,
|
url: `/${bucketName}/${objectName3}`,
|
||||||
namespace,
|
namespace,
|
||||||
objectKey: objectName3,
|
objectKey: utils.encodeObjectKey(objectName3),
|
||||||
}, postBody);
|
}, postBody);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -231,7 +233,7 @@ describe('bucketGet API', () => {
|
||||||
query: {},
|
query: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
testPutObjectRequest1.objectKey += '&><"\'';
|
testPutObjectRequest1.objectKey += utils.encodeObjectKey('&><"\'');
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
next => bucketPut(authInfo, testPutBucketRequest,
|
next => bucketPut(authInfo, testPutBucketRequest,
|
||||||
locationConstraint, log, next),
|
locationConstraint, log, next),
|
||||||
|
@ -243,7 +245,7 @@ describe('bucketGet API', () => {
|
||||||
],
|
],
|
||||||
(err, result) => {
|
(err, result) => {
|
||||||
assert.strictEqual(result.ListBucketResult.Contents[0].Key[0],
|
assert.strictEqual(result.ListBucketResult.Contents[0].Key[0],
|
||||||
testPutObjectRequest1.objectKey);
|
utils.decodeObjectKey(testPutObjectRequest1.objectKey));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue