List files
diff --git a/example/index.js b/example/index.js
index 67fc4803f..2633e8b64 100644
--- a/example/index.js
+++ b/example/index.js
@@ -174,6 +174,14 @@ const uploadContent = function (client) {
return client.put(key, new Buffer(content)).then(res => listFiles(client));
};
+const uploadBlob = function (client) {
+ const content = document.getElementById('file-blob').value.trim();
+ const key = document.getElementById('object-key-blob').value.trim() || 'blob';
+ console.log(`content => ${key}`);
+
+ return client.put(key, new Blob([content], { type: 'text/plain' })).then(res => listFiles(client));
+}
+
const downloadFile = function (client) {
const object = document.getElementById('dl-object-key').value.trim();
@@ -209,6 +217,10 @@ window.onload = function () {
applyTokenDo(uploadContent);
};
+ document.getElementById('blob-button').onclick = function () {
+ applyTokenDo(uploadBlob);
+ };
+
document.getElementById('list-files-button').onclick = function () {
applyTokenDo(listFiles);
};
diff --git a/lib/browser/managed_upload.js b/lib/browser/managed_upload.js
index 5c0f6fbb6..f7c47f0bb 100644
--- a/lib/browser/managed_upload.js
+++ b/lib/browser/managed_upload.js
@@ -36,8 +36,17 @@ proto.multipartUpload = function* multipartUpload(name, file, options) {
}
const minPartSize = 100 * 1024;
- const filename = is.file(file) ? file.name : file;
- options.mime = options.mime || mime.getType(path.extname(filename));
+
+ if (!options.mime) {
+ if (is.file(file)) {
+ options.mime = mime.getType(path.extname(file.name));
+ } else if (is.blob(file)) {
+ options.mime = file.type;
+ } else {
+ options.mime = mime.getType(path.extname(file));
+ }
+ }
+
options.headers = options.headers || {};
this._convertMetaToHeaders(options.meta, options.headers);
@@ -182,13 +191,17 @@ is.file = function file(obj) {
return typeof (File) !== 'undefined' && obj instanceof File;
};
+is.blob = function (blob) {
+ return typeof (Blob) !== 'undefined' && blob instanceof Blob;
+};
+
/**
* Get file size
*/
proto._getFileSize = function* _getFileSize(file) {
if (is.buffer(file)) {
return file.length;
- } else if (is.file(file)) {
+ } else if (is.blob(file) || is.file(file)) {
return file.size;
} if (is.string(file)) {
const stat = yield this._statFile(file);
@@ -261,7 +274,7 @@ WebFileReadStream.prototype._read = function _read(size) {
};
proto._createStream = function _createStream(file, start, end) {
- if (is.file(file)) {
+ if (is.blob(file) || is.file(file)) {
return new WebFileReadStream(file.slice(start, end));
}
// else if (is.string(file)) {
diff --git a/lib/browser/object.js b/lib/browser/object.js
index 6ceed25ac..23fd543d0 100644
--- a/lib/browser/object.js
+++ b/lib/browser/object.js
@@ -65,15 +65,20 @@ proto.put = function* put(name, file, options) {
options = options || {};
if (is.buffer(file)) {
content = file;
- } else if (is.string(file)) {
- options.mime = options.mime || mime.getType(path.extname(file));
- const stream = fs.createReadStream(file);
+ } else if (is.blob(file) || is.file(file)) {
+ if (!options.mime) {
+ if (is.file(file)) {
+ options.mime = mime.getType(path.extname(file.name));
+ } else {
+ options.mime = file.type;
+ }
+ }
+
+ const stream = this._createStream(file, 0, file.size);
options.contentLength = yield this._getFileSize(file);
return yield this.putStream(name, stream, options);
- } else if (is.readableStream(file)) {
- return yield this.putStream(name, file, options);
} else {
- throw new TypeError('Must provide String/Buffer/ReadableStream for put.');
+ throw new TypeError('Must provide Buffer/Blob for put.');
}
options.headers = options.headers || {};
diff --git a/test/browser/browser.test.js b/test/browser/browser.test.js
index e169bc184..48d0747aa 100644
--- a/test/browser/browser.test.js
+++ b/test/browser/browser.test.js
@@ -471,6 +471,28 @@ describe('browser', () => {
assert.equal(resultGet.content.toString(), body.toString());
+ const resultDel = yield this.store.delete(name);
+ assert.equal(resultDel.res.status, 204);
+ });
+ it('GETs and PUTs blob to a bucket', function* () {
+ const name = `${prefix}put/test`;
+ const body = new Blob(['blobBody'], { type: 'text/plain' });
+ const resultPut = yield this.store.put(name, body);
+ assert.equal(resultPut.res.status, 200);
+ const resultGet = yield this.store.get(name);
+ assert.equal(resultGet.res.status, 200);
+
+
+ yield new Promise((resolve) => {
+ const fr = new FileReader();
+ fr.onload = function () {
+ console.log(fr.result);
+ assert.equal(resultGet.content.toString(), fr.result);
+ resolve();
+ };
+ fr.readAsText(body, 'utf-8');
+ });
+
const resultDel = yield this.store.delete(name);
assert.equal(resultDel.res.status, 204);
});
@@ -762,6 +784,39 @@ describe('browser', () => {
assert.deepEqual(md5(object.content), md5(fileBuf));
});
+ it('should upload file using multipart upload', function* () {
+ // create a file with 1M random data
+ const blobContent = Array(1024 * 1024).fill('a').join('');
+ const blob = new Blob([blobContent], { type: 'text/plain' });
+
+ const name = `${prefix}multipart/upload-blob.js`;
+ let progress = 0;
+ const result = yield this.store.multipartUpload(name, blob, {
+ partSize: 100 * 1024,
+ progress() {
+ return function (done) {
+ progress++;
+ done();
+ };
+ },
+ });
+ sinon.restore();
+ assert.equal(result.res.status, 200);
+ assert.equal(progress, 12);
+
+ const object = yield this.store.get(name);
+ assert.equal(object.res.status, 200);
+
+ const blobBuf = new Uint8Array(blobContent.length);
+ for (let i = 0, j = blobContent.length; i < j; ++i) {
+ blobBuf[i] = blobContent.charCodeAt(i);
+ }
+
+ assert.equal(object.content.length, blobBuf.length);
+ // avoid comparing buffers directly for it may hang when generating diffs
+ assert.deepEqual(md5(object.content), md5(blobBuf));
+ });
+
it('should return requestId in init, upload part, complete', function* () {
const fileContent = Array(1024 * 1024).fill('a').join('');
const file = new File([fileContent], 'multipart-fallback');