Skip to content

Commit

Permalink
BosClient 支持 PostObject 的功能
Browse files Browse the repository at this point in the history
  • Loading branch information
leeight committed Mar 28, 2016
1 parent a6679d4 commit f6676e6
Show file tree
Hide file tree
Showing 5 changed files with 401 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/bos_client.js
Expand Up @@ -33,6 +33,7 @@ var HttpClient = require('./http_client');
var BceBaseClient = require('./bce_base_client');
var MimeType = require('./mime.types');
var WMStream = require('./wm_stream');
var Multipart = require('./multipart');

// var MIN_PART_SIZE = 1048576; // 1M
// var THREAD = 2;
Expand Down Expand Up @@ -627,6 +628,84 @@ BosClient.prototype.listMultipartUploads = function (bucketName, options) {
});
};

/**
* Generate PostObject policy signature.
*
* @param {Object} policy The policy object.
* @return {string}
*/
BosClient.prototype.signPostObjectPolicy = function (policy) {
var credentials = this.config.credentials;
var auth = new Auth(credentials.ak, credentials.sk);

policy = new Buffer(JSON.stringify(policy)).toString('base64');
var signature = auth.hash(policy, credentials.sk);

return {
policy: policy,
signature: signature
};
};

/**
* Post an object.
*
* @see {http://wiki.baidu.com/pages/viewpage.action?pageId=161461681}
*
* @param {string} bucketName The bucket name.
* @param {string} key The object name.
* @param {string|Buffer} data The file raw data or file path.
* @param {Object} options The form fields.
* @return {Promise}
*/
BosClient.prototype.postObject = function (bucketName, key, data, options) {
var boundary = 'MM8964' + (Math.random() * Math.pow(2, 63)).toString(36);
var contentType = 'multipart/form-data; boundary=' + boundary;

if (u.isString(data)) {
data = fs.readFileSync(data);
}
else if (!Buffer.isBuffer(data)) {
throw new Error('Invalid data type.');
}

var credentials = this.config.credentials;
var ak = credentials.ak;

var blacklist = ['signature', 'accessKey', 'key', 'file'];
options = u.omit(options || {}, blacklist);

var multipart = new Multipart(boundary);
for (var k in options) {
if (options.hasOwnProperty(k)) {
if (k !== 'policy') {
multipart.addPart(k, options[k]);
}
}
}

if (options.policy) {
var rv = this.signPostObjectPolicy(options.policy);
multipart.addPart('policy', rv.policy);
multipart.addPart('signature', rv.signature);
}

multipart.addPart('accessKey', ak);
multipart.addPart('key', key);
multipart.addPart('file', data);

var body = multipart.encode();

var headers = {};
headers[H.CONTENT_TYPE] = contentType;

return this.sendRequest('POST', {
bucketName: bucketName,
body: body,
headers: headers
});
};

// --- E N D ---

BosClient.prototype.sendRequest = function (httpMethod, varArgs) {
Expand Down
83 changes: 83 additions & 0 deletions src/multipart.js
@@ -0,0 +1,83 @@
/**
* Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @file src/multipart.js
* @author leeight
*/

var util = require('util');

var u = require('underscore');

/**
* Multipart Encoder
*
* @param {string} boundary The multipart boundary.
*/
function Multipart(boundary) {
this._boundary = boundary;

/**
* @type {Array.<Buffer>}
*/
this._parts = [];
}

/**
* Add a part
*
* @param {string} name The part name.
* @param {string|Buffer} data The part data.
*/
Multipart.prototype.addPart = function (name, data) {
var part = [];

var header = util.format(
'--%s\r\nContent-Disposition: form-data; name="%s"%s\r\n\r\n',
this._boundary, name, '');
part.push(new Buffer(header));

if (Buffer.isBuffer(data)) {
part.push(data);
part.push(new Buffer('\r\n'));
}
else if (u.isString(data)) {
part.push(new Buffer(data + '\r\n'));
}
else {
throw new Error('Invalid data type.');
}

this._parts.push(Buffer.concat(part));
};

Multipart.prototype.encode = function () {
return Buffer.concat(
[
Buffer.concat(this._parts),
new Buffer(util.format('--%s--', this._boundary))
]
);
};

module.exports = Multipart;










/* vim: set ts=4 sw=4 sts=4 tw=120: */
1 change: 1 addition & 0 deletions test/run-all.sh
Expand Up @@ -55,6 +55,7 @@ SPECS=(
test/sdk/sts.spec.js
test/sdk/crypto.spec.js
test/sdk/auth.spec.js
test/sdk/multipart.spec.js
test/sdk/http_client.spec.js
test/sdk/mime.types.spec.js
test/sdk/bos_client.spec.js
Expand Down
73 changes: 73 additions & 0 deletions test/sdk/multipart.spec.js
@@ -0,0 +1,73 @@
/**
* Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

var expect = require('expect.js');

var Multipart = require('../../src/multipart');

describe('Multipart', function () {
it('invalid data type', function () {
var multipart = new Multipart('hahaha');
try {
multipart.addPart('accessKey', null);
expect().fail('SHOULD NOT REACH HERE');
}
catch (ex) {
expect(ex).to.be.an(Error);
}
});

it('encode', function () {
var multipart = new Multipart('hahaha');
multipart.addPart('accessKey', '499d0610679c4da2a69b64086a4cc3bc');
multipart.addPart('policy', 'eyJleHBpcmF0aW9uIjoiMjA=');
multipart.addPart('signature', 'd1a617a725122c20319');
multipart.addPart('key', new Buffer('world.txt'));
multipart.addPart('Content-Disposition', 'attachment;filename="download/object"');
multipart.addPart('x-bce-meta-object-tag', new Buffer('test1'));

var encoded = multipart.encode().toString();
expect(encoded).to.eql(
'--hahaha\r\n' +
'Content-Disposition: form-data; name="accessKey"\r\n\r\n' +
'499d0610679c4da2a69b64086a4cc3bc\r\n' +
'--hahaha\r\n' +
'Content-Disposition: form-data; name="policy"\r\n\r\n' +
'eyJleHBpcmF0aW9uIjoiMjA=\r\n' +
'--hahaha\r\n' +
'Content-Disposition: form-data; name="signature"\r\n\r\n' +
'd1a617a725122c20319\r\n' +
'--hahaha\r\n' +
'Content-Disposition: form-data; name="key"\r\n\r\n' +
'world.txt\r\n' +
'--hahaha\r\n' +
'Content-Disposition: form-data; name="Content-Disposition"\r\n\r\n' +
'attachment;filename="download/object"\r\n' +
'--hahaha\r\n' +
'Content-Disposition: form-data; name="x-bce-meta-object-tag"\r\n\r\n' +
'test1\r\n' +
'--hahaha--'
);
});
});










/* vim: set ts=4 sw=4 sts=4 tw=120: */

0 comments on commit f6676e6

Please sign in to comment.