Skip to content

Instantly share code, notes, and snippets.

@honzabrecka
Last active August 29, 2015 14:17
Show Gist options
  • Save honzabrecka/6a0d435fbe9bc843ae25 to your computer and use it in GitHub Desktop.
Save honzabrecka/6a0d435fbe9bc843ae25 to your computer and use it in GitHub Desktop.
chunked file upload with MD5 checksum
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript">
(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},cmn=function(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<<s|a>>>32-s,b)},ff=function(a,b,c,d,x,s,t){return cmn(b&c|~b&d,a,b,x,s,t)},gg=function(a,b,c,d,x,s,t){return cmn(b&d|c&~d,a,b,x,s,t)},hh=function(a,b,c,d,x,s,t){return cmn(b^c^d,a,b,x,s,t)},ii=function(a,b,c,d,x,s,t){return cmn(c^(b|~d),a,b,x,s,t)},md5cycle=function(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a=ff(a,b,c,d,k[0],7,-680876936);d=ff(d,a,b,c,k[1],12,-389564586);c=ff(c,d,a,b,k[2],17,606105819);b=ff(b,c,d,a,k[3],22,-1044525330);a=ff(a,b,c,d,k[4],7,-176418897);d=ff(d,a,b,c,k[5],12,1200080426);c=ff(c,d,a,b,k[6],17,-1473231341);b=ff(b,c,d,a,k[7],22,-45705983);a=ff(a,b,c,d,k[8],7,1770035416);d=ff(d,a,b,c,k[9],12,-1958414417);c=ff(c,d,a,b,k[10],17,-42063);b=ff(b,c,d,a,k[11],22,-1990404162);a=ff(a,b,c,d,k[12],7,1804603682);d=ff(d,a,b,c,k[13],12,-40341101);c=ff(c,d,a,b,k[14],17,-1502002290);b=ff(b,c,d,a,k[15],22,1236535329);a=gg(a,b,c,d,k[1],5,-165796510);d=gg(d,a,b,c,k[6],9,-1069501632);c=gg(c,d,a,b,k[11],14,643717713);b=gg(b,c,d,a,k[0],20,-373897302);a=gg(a,b,c,d,k[5],5,-701558691);d=gg(d,a,b,c,k[10],9,38016083);c=gg(c,d,a,b,k[15],14,-660478335);b=gg(b,c,d,a,k[4],20,-405537848);a=gg(a,b,c,d,k[9],5,568446438);d=gg(d,a,b,c,k[14],9,-1019803690);c=gg(c,d,a,b,k[3],14,-187363961);b=gg(b,c,d,a,k[8],20,1163531501);a=gg(a,b,c,d,k[13],5,-1444681467);d=gg(d,a,b,c,k[2],9,-51403784);c=gg(c,d,a,b,k[7],14,1735328473);b=gg(b,c,d,a,k[12],20,-1926607734);a=hh(a,b,c,d,k[5],4,-378558);d=hh(d,a,b,c,k[8],11,-2022574463);c=hh(c,d,a,b,k[11],16,1839030562);b=hh(b,c,d,a,k[14],23,-35309556);a=hh(a,b,c,d,k[1],4,-1530992060);d=hh(d,a,b,c,k[4],11,1272893353);c=hh(c,d,a,b,k[7],16,-155497632);b=hh(b,c,d,a,k[10],23,-1094730640);a=hh(a,b,c,d,k[13],4,681279174);d=hh(d,a,b,c,k[0],11,-358537222);c=hh(c,d,a,b,k[3],16,-722521979);b=hh(b,c,d,a,k[6],23,76029189);a=hh(a,b,c,d,k[9],4,-640364487);d=hh(d,a,b,c,k[12],11,-421815835);c=hh(c,d,a,b,k[15],16,530742520);b=hh(b,c,d,a,k[2],23,-995338651);a=ii(a,b,c,d,k[0],6,-198630844);d=ii(d,a,b,c,k[7],10,1126891415);c=ii(c,d,a,b,k[14],15,-1416354905);b=ii(b,c,d,a,k[5],21,-57434055);a=ii(a,b,c,d,k[12],6,1700485571);d=ii(d,a,b,c,k[3],10,-1894986606);c=ii(c,d,a,b,k[10],15,-1051523);b=ii(b,c,d,a,k[1],21,-2054922799);a=ii(a,b,c,d,k[8],6,1873313359);d=ii(d,a,b,c,k[15],10,-30611744);c=ii(c,d,a,b,k[6],15,-1560198380);b=ii(b,c,d,a,k[13],21,1309151649);a=ii(a,b,c,d,k[4],6,-145523070);d=ii(d,a,b,c,k[11],10,-1120210379);c=ii(c,d,a,b,k[2],15,718787259);b=ii(b,c,d,a,k[9],21,-343485551);x[0]=add32(a,x[0]);x[1]=add32(b,x[1]);x[2]=add32(c,x[2]);x[3]=add32(d,x[3])},md5blk=function(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks},md5blk_array=function(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks},md51=function(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state},md51_array=function(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64<n?a.subarray(i-64):new Uint8Array(0);length=a.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"],rhex=function(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s},hex=function(x){var i;for(i=0;i<x.length;i+=1){x[i]=rhex(x[i])}return x.join("")},md5=function(s){return hex(md51(s))},SparkMD5=function(){this.reset()};if(md5("hello")!=="5d41402abc4b2a76b9719d911017c592"){add32=function(x,y){var lsw=(x&65535)+(y&65535),msw=(x>>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}SparkMD5.prototype.append=function(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}this.appendBinary(str);return this};SparkMD5.prototype.appendBinary=function(contents){this._buff+=contents;this._length+=contents.length;var length=this._buff.length,i;for(i=64;i<=length;i+=64){md5cycle(this._state,md5blk(this._buff.substring(i-64,i)))}this._buff=this._buff.substr(i-64);return this};SparkMD5.prototype.end=function(raw){var buff=this._buff,length=buff.length,i,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=!!raw?this._state:hex(this._state);this.reset();return ret};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._state,tail)};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._state=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.destroy=function(){delete this._state;delete this._buff;delete this._length};SparkMD5.hash=function(str,raw){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}var hash=md51(str);return!!raw?hash:hex(hash)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content);return!!raw?hash:hex(hash)};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=this._concatArrayBuffer(this._buff,arr),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._state,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64<length?buff.subarray(i-64):new Uint8Array(0);return this};SparkMD5.ArrayBuffer.prototype.end=function(raw){var buff=this._buff,length=buff.length,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],i,ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=!!raw?this._state:hex(this._state);this.reset();return ret};SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._state=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._concatArrayBuffer=function(first,second){var firstLength=first.length,result=new Uint8Array(firstLength+second.byteLength);result.set(first);result.set(new Uint8Array(second),firstLength);return result};SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr));return!!raw?hash:hex(hash)};return SparkMD5});
</script>
<style type="text/css">
body {
font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
}
label {
float: left;
width: 200px;
}
input {
float: left;
}
ul, li {
list-style: none;
list-style-type: none;
}
.cleaner {
clear: both;
}
</style>
</head>
<body>
<form>
<ul>
<li>
<label for="url">url</label>
<input id="url" type="text" value="http://127.0.0.1:4000/upload?hash=%hash%">
<br class="cleaner">
</li>
<li>
<label for="chunkSize">chunk size</label>
<input id="chunkSize" type="text" value="100000">
<br class="cleaner">
</li>
<li>
<label for="file">url</label>
<input id="file" type="file">
<br class="cleaner">
</li>
</ul>
</form>
<script type="text/javascript">
function toArray(listLike) {
return Array.prototype.slice.call(listLike);
}
function range(from, to) {
for (res = []; from < to; from++) res.push(from);
return res;
}
function ranges(total, slice) {
return range(0, Math.ceil(total / slice)).map(function(i) {
return {
start: i * slice,
end: Math.min((i + 1) * slice, total) - 1
};
});
}
function getValue(id) {
return document.getElementById(id).value;
}
function upload(file) {
var reader = new FileReader();
reader.onload = function(event) {
uploadChunk(
file,
ranges(file.size, parseInt(getValue('chunkSize'))),
0,
getValue('url').replace('%hash%', SparkMD5.hashBinary(event.target.result))
);
};
reader.readAsBinaryString(file);
}
function uploadChunk(file, ranges, index, url) {
function retry() {
setTimeout(function() {
uploadChunk(file, ranges, index, url);
}, 5000);
}
var range = ranges[index];
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.overrideMimeType('application/octet-stream');
xhr.setRequestHeader('Content-Range', 'bytes ' + range.start + '-' + range.end + '/' + file.size);
xhr.onload = function(event) {
if (event.target.status < 200 || event.target.status >= 400) retry();
else if (index + 1 === ranges.length) done(event.target.response);
else uploadChunk(file, ranges, index + 1, url);
};
xhr.onerror = function(event) {
retry();
};
xhr.send(file.slice(range.start, range.end + 1));
}
function done(response) {
console.log(response);
}
document.getElementById('file').onchange = function(event) {
toArray(event.target.files).map(upload);
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment