Skip to content

Commit

Permalink
feat: browser support blob (#409)
Browse files Browse the repository at this point in the history
* feature: add support with blob

* fix: fix typo

* test: add test cases for blob's upload operation

* feat: rm unused test data (#401)

* fix: add invalidation for security

* test: update test case

* feat: add example about upload blob

* fix: restore test data

* fix: restore test data
  • Loading branch information
duan007a authored and PeterRao committed Mar 29, 2018
1 parent 64f8d68 commit e8a78b5
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 14 deletions.
26 changes: 22 additions & 4 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ <h1>OSS <small>in</small> Browser</h1>
<div class="form-group">
<label>Store as</label>
<input type="text" class="form-control" id="object-key-content" value="object" />
</div>
<div class="form-group">
<input type="button" class="btn btn-primary" id="content-button" value="Save" />
</div>
Expand All @@ -72,6 +71,26 @@ <h1>OSS <small>in</small> Browser</h1>
</td>
</tr>
<tr>
<td>
<div class="panel panel-success">
<div class="panel-heading">Upload Blob</div>
<div class="panel-body">
<form action="" class="form-horizontal">
<div class="form-group">
<label>Content</label>
<textarea class="form-control" id="file-blob" rows="3">Hello, OSS! I am a Blob!</textarea>
</div>
<div class="form-group">
<label>Store as</label>
<input type="text" class="form-control" id="object-key-blob" value="blob" />
</div>
<div class="form-group">
<input type="button" class="btn btn-primary" id="blob-button" value="Save" />
</div>
</form>
</div>
</div>
</td>
<td>
<div class="panel panel-danger">
<div class="panel-heading">Upload with base64 img</div>
Expand Down Expand Up @@ -104,7 +123,8 @@ <h1>OSS <small>in</small> Browser</h1>
</div>
</div>
</td>

</tr>
<tr>
<td>
<div class="panel panel-warning">
<div class="panel-heading">Download file</div>
Expand All @@ -125,8 +145,6 @@ <h1>OSS <small>in</small> Browser</h1>
</div>
</div>
</td>
</tr>
<tr>
<td>
<div class="panel panel-info">
<div class="panel-heading">List files</div>
Expand Down
12 changes: 12 additions & 0 deletions example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
};
Expand Down
21 changes: 17 additions & 4 deletions lib/browser/managed_upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down
17 changes: 11 additions & 6 deletions lib/browser/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 || {};
Expand Down
55 changes: 55 additions & 0 deletions test/browser/browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand Down Expand Up @@ -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');
Expand Down

0 comments on commit e8a78b5

Please sign in to comment.