megar 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +11 -0
  5. data/CHANGELOG +5 -0
  6. data/Gemfile +4 -0
  7. data/Guardfile +11 -0
  8. data/LICENSE +22 -0
  9. data/README.rdoc +218 -0
  10. data/Rakefile +33 -0
  11. data/bin/megar +16 -0
  12. data/lib/extensions/math.rb +13 -0
  13. data/lib/js_ref_impl/_README +9 -0
  14. data/lib/js_ref_impl/base64_1.js +83 -0
  15. data/lib/js_ref_impl/crypto_5.js +1795 -0
  16. data/lib/js_ref_impl/download_8.js +867 -0
  17. data/lib/js_ref_impl/hex_1.js +76 -0
  18. data/lib/js_ref_impl/index_9.js +666 -0
  19. data/lib/js_ref_impl/js.manifest +115 -0
  20. data/lib/js_ref_impl/rsa_1.js +456 -0
  21. data/lib/js_ref_impl/sjcl_1.js +1 -0
  22. data/lib/js_ref_impl/upload_10.js +691 -0
  23. data/lib/megar.rb +11 -0
  24. data/lib/megar/catalog.rb +5 -0
  25. data/lib/megar/catalog/catalog_item.rb +90 -0
  26. data/lib/megar/catalog/file.rb +14 -0
  27. data/lib/megar/catalog/files.rb +13 -0
  28. data/lib/megar/catalog/folder.rb +20 -0
  29. data/lib/megar/catalog/folders.rb +28 -0
  30. data/lib/megar/connection.rb +84 -0
  31. data/lib/megar/crypto.rb +399 -0
  32. data/lib/megar/exception.rb +55 -0
  33. data/lib/megar/session.rb +157 -0
  34. data/lib/megar/shell.rb +87 -0
  35. data/lib/megar/version.rb +3 -0
  36. data/megar.gemspec +30 -0
  37. data/spec/fixtures/crypto_expectations/sample_user.json +109 -0
  38. data/spec/spec_helper.rb +24 -0
  39. data/spec/support/crypto_expectations_helper.rb +44 -0
  40. data/spec/support/mocks_helper.rb +22 -0
  41. data/spec/unit/catalog/file_spec.rb +31 -0
  42. data/spec/unit/catalog/files_spec.rb +26 -0
  43. data/spec/unit/catalog/folder_spec.rb +28 -0
  44. data/spec/unit/catalog/folders_spec.rb +49 -0
  45. data/spec/unit/connection_spec.rb +50 -0
  46. data/spec/unit/crypto_spec.rb +476 -0
  47. data/spec/unit/exception_spec.rb +35 -0
  48. data/spec/unit/extensions/math_spec.rb +21 -0
  49. data/spec/unit/session_spec.rb +146 -0
  50. data/spec/unit/shell_spec.rb +18 -0
  51. metadata +238 -0
@@ -0,0 +1 @@
1
+ var sjcl={cipher:{}};sjcl.cipher.aes=function(a){this.a[0][0][0]||this.d();var d,c,g,b,e=this.a[0][4],f=this.a[1];d=a.length;var j=1;this.c=[g=a.slice(0),b=[]];for(a=d;a<4*d+28;a++){c=g[a-1];if(a%d===0||d===8&&a%d===4){c=e[c>>>24]<<24^e[c>>16&255]<<16^e[c>>8&255]<<8^e[c&255];if(a%d===0){c=c<<8^c>>>24^j<<24;j=j<<1^(j>>7)*283}}g[a]=g[a-d]^c}for(d=0;a;d++,a--){c=g[d&3?a:a-4];b[d]=a<=4||d<4?c:f[0][e[c>>>24]]^f[1][e[c>>16&255]]^f[2][e[c>>8&255]]^f[3][e[c&255]]}};sjcl.cipher.aes.prototype={encrypt:function(a){return this.b(a,0)},decrypt:function(a){return this.b(a,1)},a:[[[],[],[],[],[]],[[],[],[],[],[]]],d:function(){var a=this.a[0],d=this.a[1],c=a[4],g=d[4],b,e,f,j=[],l=[],m,i,h,k;for(b=0;b<0x100;b++)l[(j[b]=b<<1^(b>>7)*283)^b]=b;for(e=f=0;!c[e];e^=m||1,f=l[f]||1){h=f^f<<1^f<<2^f<<3^f<<4;h=h>>8^h&255^99;c[e]=h;g[h]=e;i=j[b=j[m=j[e]]];k=i*0x1010101^b*0x10001^m*0x101^e*0x1010100;i=j[h]*0x101^h*0x1010100;for(b=0;b<4;b++){a[b][e]=i=i<<24^i>>>8;d[b][h]=k=k<<24^k>>>8}}for(b=0;b<5;b++){a[b]=a[b].slice(0);d[b]=d[b].slice(0)}},b:function(a,d){var c=this.c[d],g=a[0]^c[0],b=a[d?3:1]^c[1],e=a[2]^c[2];a=a[d?1:3]^c[3];var f,j,l,m=c.length/4-2,i,h=4,k=[0,0,0,0];f=this.a[d];var n=f[0],o=f[1],p=f[2],q=f[3],r=f[4];for(i=0;i<m;i++){f=n[g>>>24]^o[b>>16&255]^p[e>>8&255]^q[a&255]^c[h];j=n[b>>>24]^o[e>>16&255]^p[a>>8&255]^q[g&255]^c[h+1];l=n[e>>>24]^o[a>>16&255]^p[g>>8&255]^q[b&255]^c[h+2];a=n[a>>>24]^o[g>>16&255]^p[b>>8&255]^q[e&255]^c[h+3];h+=4;g=f;b=j;e=l}for(i=0;i<4;i++){k[d?3&-i:i]=r[g>>>24]<<24^r[b>>16&255]<<16^r[e>>8&255]<<8^r[a&255]^c[h++];f=g;g=b;b=e;e=a;a=f}return k}};
@@ -0,0 +1,691 @@
1
+ var ul_queue = [];
2
+ var ul_queue_num = 0;
3
+
4
+ var totalbytessent;
5
+
6
+ var use_ssl = 1;
7
+
8
+ if (localStorage.use_ssl) use_ssl = localStorage.use_ssl;
9
+
10
+ var ul_reader;
11
+
12
+ var ul_method;
13
+
14
+ if (!window.FileReader) ul_method = 1;
15
+
16
+ var ul_maxSlots = 4;
17
+ if (localStorage.ul_maxSlots) ul_maxSlots = localStorage.ul_maxSlots;
18
+
19
+ var ul_skipIdentical = 0;
20
+ if (localStorage.ul_skipIdentical) ul_skipIdentical= localStorage.ul_skipIdentical;
21
+
22
+ var ul_maxSpeed = 0;
23
+
24
+ if (localStorage.ul_maxSpeed) ul_maxSpeed=localStorage.ul_maxSpeed;
25
+
26
+ if (ul_method === 1) ul_maxSpeed=0;
27
+
28
+ var ul_xhrs;
29
+ var ul_xhrbusy;
30
+ var ul_sendbuf;
31
+
32
+ var ul_progress;
33
+
34
+ var ul_errors;
35
+ var ul_intransit;
36
+
37
+ var ul_max_workers = 4;
38
+ var ul_workers;
39
+ var ul_workerbusy;
40
+
41
+ var ul_uploadurl;
42
+
43
+ var ul_keyNonce;
44
+ var ul_key;
45
+
46
+ var ul_macs;
47
+
48
+ var ul_plainq;
49
+
50
+ var ul_sendchunks;
51
+ var ul_inflight;
52
+
53
+ var ul_readq;
54
+
55
+ var ul_lastreason = 0;
56
+
57
+ var ul_instance = 0;
58
+
59
+ var ul_uploading;
60
+
61
+ var ul_aes;
62
+
63
+ var ul_flashreaderactive = false;
64
+
65
+ var ul_flashpos = Array(ul_maxSlots);
66
+
67
+ function startupload()
68
+ {
69
+ if (ul_uploading) return;
70
+
71
+ for (;;)
72
+ {
73
+ if (ul_queue_num >= ul_queue.length)
74
+ {
75
+ if (d) console.log("No further uploads, clearing ul_queue");
76
+ ul_queue = [];
77
+ ul_queue_num = 0;
78
+ return;
79
+ }
80
+
81
+ if (ul_queue[ul_queue_num])
82
+ {
83
+ /*
84
+ loadImage(ul_queue[ul_queue_num],100,100,function(img)
85
+ {
86
+ console.log(img);
87
+ })
88
+ */
89
+
90
+ if (!ul_skipIdentical || !file_exists(ul_queue[ul_queue_num].target,ul_queue[ul_queue_num].path || ul_queue[ul_queue_num].name,ul_queue[ul_queue_num].size)) break;
91
+ onUploadSuccess(ul_queue_num);
92
+ }
93
+
94
+ ul_queue_num++;
95
+ }
96
+
97
+ ul_uploading=true;
98
+
99
+ if (ul_queue[ul_queue_num].flashid)
100
+ {
101
+ ul_maxSlots = 1;
102
+ ul_flashreaderactive = false;
103
+ }
104
+ else ul_reader = new FileReader();
105
+
106
+ if (d) console.log(ul_queue_num + ' - ' + ul_queue.length);
107
+
108
+ ul_queue[ul_queue_num].retries = ul_queue[ul_queue_num].retries+1 || 0;
109
+
110
+ if (ul_queue[ul_queue_num].posturl) initupload3();
111
+ else
112
+ {
113
+ var ctx = { callback : initupload2, reqindex : [] };
114
+ var req = [];
115
+ var maxpf = 128*1048576;
116
+
117
+ for (var i = ul_queue_num; i < ul_queue.length && i < ul_queue_num+8 && maxpf > 0; i++)
118
+ {
119
+ if (!ul_queue[ul_queue_num].posturl)
120
+ {
121
+ ctx.reqindex.push(i);
122
+ req.push({ a : 'u', ssl : use_ssl, ms : ul_maxSpeed, s : ul_queue[i].size, r : ul_queue[i].retries, e : ul_lastreason });
123
+ maxpf -= ul_queue[i].size
124
+ }
125
+ }
126
+
127
+ api_req(req,ctx);
128
+ }
129
+ }
130
+
131
+ function initupload2(res,ctx)
132
+ {
133
+ var p, pp;
134
+
135
+ if (typeof res != 'object')
136
+ {
137
+ // TODO: process upload error
138
+ return;
139
+ }
140
+
141
+ for (var i = 0; i < res.length; i++) if (typeof(res[i]) == 'object') ul_queue[ctx.reqindex[i]].posturl = res[i].p;
142
+
143
+ initupload3();
144
+ }
145
+
146
+ function initupload3()
147
+ {
148
+ ul_uploadurl = ul_queue[ul_queue_num].posturl;
149
+
150
+ if (!ul_uploadurl)
151
+ {
152
+ // TODO: upload over quota reporting
153
+ return;
154
+ }
155
+
156
+ ul_key = Array(6);
157
+
158
+ // generate ul_key and nonce
159
+ for (i = 6; i--; ) ul_key[i] = rand(0x100000000);
160
+
161
+ ul_keyNonce = JSON.stringify(ul_key);
162
+
163
+ ul_macs = [];
164
+
165
+ totalbytessent = 0;
166
+
167
+ ul_readq = {};
168
+
169
+ if (ul_queue[ul_queue_num].size)
170
+ {
171
+ p = 0;
172
+ for (i = 1; i <= 8 && p < ul_queue[ul_queue_num].size-i*131072; i++)
173
+ {
174
+ ul_readq[p] = i*131072;
175
+ pp = p;
176
+ p += ul_readq[p];
177
+ }
178
+
179
+ while (p < ul_queue[ul_queue_num].size)
180
+ {
181
+ ul_readq[p] = 1048576;
182
+ pp = p;
183
+ p += ul_readq[p];
184
+ }
185
+
186
+ if (!(ul_readq[pp] = ul_queue[ul_queue_num].size-pp) && ul_queue[ul_queue_num].size) delete ul_readq[pp];
187
+ }
188
+ else ul_readq[0] = 0;
189
+
190
+ ul_plainq = {};
191
+
192
+ ul_intransit = 0;
193
+ ul_inflight = {};
194
+ ul_sendchunks = {};
195
+
196
+ ul_lastreason = 0;
197
+ ul_errors = 0;
198
+
199
+ ul_progress = Array(ul_maxSlots);
200
+
201
+ if (use_workers)
202
+ {
203
+ ul_workers = Array(ul_max_workers);
204
+ ul_workerbusy = Array(ul_max_workers);
205
+ for (var id = ul_max_workers; id--; ) ul_workerbusy[id] = 0;
206
+ }
207
+ else ul_aes = new sjcl.cipher.aes([ul_key[0],ul_key[1],ul_key[2],ul_key[3]]);
208
+
209
+ ul_xhrs = Array(ul_maxSlots);
210
+ ul_xhrbusy = Array(ul_maxSlots);
211
+
212
+ if (chromehack) ul_sendbuf = Array(ul_maxSlots);
213
+
214
+ for (var slot = ul_maxSlots; slot--; )
215
+ {
216
+ ul_xhrbusy[slot] = 0;
217
+ ul_progress[slot] = 0;
218
+ if (chromehack) ul_sendbuf[slot] = new ArrayBuffer(1048576);
219
+ }
220
+
221
+ onUploadStart(ul_queue_num);
222
+ ul_dispatch_chain();
223
+ }
224
+
225
+ var ul_timeout;
226
+
227
+ function ul_settimeout(t,target)
228
+ {
229
+ clearTimeout(ul_timeout);
230
+ if (t >= 0) ul_timeout = setTimeout(target,t);
231
+ }
232
+
233
+ function ul_dispatch_chain()
234
+ {
235
+ ul_dispatch_read();
236
+ ul_dispatch_encryption();
237
+ ul_dispatch_send();
238
+ }
239
+
240
+ function ul_dispatch_encryption()
241
+ {
242
+ var id;
243
+
244
+ if (use_workers)
245
+ {
246
+ for (id = ul_max_workers; id--; ) if (!ul_workerbusy[id]) break;
247
+
248
+ if (id >= 0)
249
+ {
250
+ for (var p in ul_plainq)
251
+ {
252
+ ul_workerbusy[id] = 1;
253
+
254
+ if (typeof(ul_workers[id]) == 'object')
255
+ {
256
+ delete ul_workers[id].onmessage;
257
+ ul_workers[id].terminate();
258
+ ul_workers[id] = undefined;
259
+ }
260
+
261
+ ul_workers[id] = new Worker('encrypter.js');
262
+ ul_workers[id].postMessage = ul_workers[id].webkitPostMessage || ul_workers[id].postMessage;
263
+ ul_workers[id].id = id;
264
+ ul_workers[id].instance = ul_instance;
265
+
266
+ ul_workers[id].onmessage = function(e)
267
+ {
268
+ if (this.instance == ul_instance)
269
+ {
270
+ if (typeof(e.data) == 'string')
271
+ {
272
+ if (e.data[0] == '[') ul_macs[this.pos] = JSON.parse(e.data);
273
+ else if (d) console.log("WORKER" + this.id + ": '" + e.data + "'");
274
+ }
275
+ else
276
+ {
277
+ if (d) console.log("WORKER" + this.id + ": Received " + e.data.byteLength + " encrypted bytes at " + this.pos);
278
+
279
+ ul_sendchunks[this.pos] = new Uint8Array(e.data);
280
+
281
+ ul_dispatch_chain();
282
+
283
+ ul_workerbusy[this.id] = 0;
284
+ }
285
+ }
286
+ };
287
+
288
+ ul_workers[id].postMessage(ul_keyNonce);
289
+
290
+ if (d) console.log("WORKER: Queueing " + ul_plainq[p].length + " bytes at " + p);
291
+
292
+ ul_workers[id].pos = parseInt(p);
293
+ ul_workers[id].postMessage(parseInt(p)/16);
294
+ ul_workers[id].postMessage(ul_plainq[p]);
295
+
296
+ delete ul_plainq[p];
297
+ break;
298
+ }
299
+ }
300
+ }
301
+ else
302
+ {
303
+ for (var p in ul_plainq)
304
+ {
305
+ ul_macs[p] = encrypt_ab_ctr(ul_aes,ul_plainq[p],[ul_key[4],ul_key[5]],p);
306
+
307
+ ul_sendchunks[p] = ul_plainq[p];
308
+
309
+ delete ul_plainq[p];
310
+ }
311
+ }
312
+ }
313
+
314
+ function ul_dispatch_send(slot)
315
+ {
316
+ var slot;
317
+
318
+ for (slot = ul_maxSlots; slot--; )
319
+ {
320
+ if (!ul_xhrbusy[slot])
321
+ {
322
+ // dispatch lowest-pos sendchunk
323
+ var p = -1, pp;
324
+
325
+ for (pp in ul_sendchunks)
326
+ {
327
+ if (!ul_inflight[pp])
328
+ {
329
+ pp = parseInt(pp);
330
+ if (p == -1) p = pp;
331
+ else if (pp < p) p = pp;
332
+ }
333
+ }
334
+
335
+ if (p == -1) break;
336
+
337
+ if (ul_uploadurl == '' && p >= 0) break;
338
+
339
+ ul_inflight[p] = 1;
340
+ ul_xhrbusy[slot] = 1;
341
+
342
+ if (!ul_method)
343
+ {
344
+ if (typeof ul_xhrs[slot] != 'object') ul_xhrs[slot] = new XMLHttpRequest;
345
+ ul_xhrs[slot].slot = slot;
346
+
347
+ ul_xhrs[slot].onreadystatechange = function()
348
+ {
349
+ ul_settimeout(120000,ul_failed);
350
+
351
+ if (this.readyState == this.DONE && this.instance == ul_instance)
352
+ {
353
+ if (this.status == 200 && typeof this.response == 'string' && this.statusText == 'OK')
354
+ {
355
+ ul_chunkcomplete(this.slot,this.pos,this.response);
356
+ }
357
+ else
358
+ {
359
+ if (d) console.log("HTTP POST failed with " + this.status + ", error count=" + ul_errors);
360
+
361
+ ul_inflight[this.pos] = 0;
362
+ ul_xhrbusy[this.upload.slot] = 0;
363
+ ul_progress[this.upload.slot] = 0;
364
+ ul_updateprogress();
365
+
366
+ if (++ul_errors > 16) ul_failed();
367
+ else ul_settimeout(ul_errors*1000,ul_dispatch_chain);
368
+ }
369
+ }
370
+ }
371
+
372
+ ul_xhrs[slot].upload.onprogress = function(e)
373
+ {
374
+ ul_settimeout(120000,ul_failed);
375
+
376
+ if (this.instance == ul_instance)
377
+ {
378
+ if (e.lengthComputable && ul_xhrs[this.slot].pos != 1)
379
+ {
380
+ ul_progress[this.slot] = e.loaded;
381
+ ul_updateprogress();
382
+ }
383
+ }
384
+ }
385
+
386
+ ul_xhrs[slot].pos = p;
387
+ ul_xhrs[slot].instance = ul_instance;
388
+ ul_xhrs[slot].upload.slot = slot;
389
+ ul_xhrs[slot].upload.instance = ul_instance;
390
+ ul_xhrs[slot].open('POST', ul_uploadurl + '/' + p);
391
+
392
+ if (chromehack)
393
+ {
394
+ data8 = new Uint8Array(ul_sendchunks[p].buffer);
395
+ send8 = new Uint8Array(ul_sendbuf[slot],0,data8.length);
396
+
397
+ send8.set(data8);
398
+
399
+ ul_xhrs[slot].send(send8);
400
+ }
401
+ else
402
+ {
403
+ ul_xhrs[slot].send(ul_sendchunks[p].buffer);
404
+ }
405
+ }
406
+ else
407
+ {
408
+ ul_flashpos[slot] = p;
409
+ flash_uploadchunk(slot,base64urlencode(ul_sendchunks[p].buffer),ul_uploadurl + '/' + p);
410
+ }
411
+
412
+ break;
413
+ }
414
+ }
415
+ }
416
+
417
+ function ul_failed(next)
418
+ {
419
+ onUploadError(ul_queue_num,"Upload failed - " + (next ? "read error" : "retrying"));
420
+
421
+ ul_cancel();
422
+ if (next) ul_queue_num++;
423
+ ul_settimeout(1000+(next ? 0 : 1000*ul_queue[ul_queue_num].retries),startupload);
424
+ }
425
+
426
+ function ul_updateprogress()
427
+ {
428
+ if (ul_queue[ul_queue_num].size)
429
+ {
430
+ var tp = totalbytessent;
431
+
432
+ for (var slot = ul_maxSlots; slot--; ) tp += ul_progress[slot];
433
+
434
+ if (tp > ul_queue[ul_queue_num].size) tp = ul_queue[ul_queue_num].size;
435
+
436
+ onUploadProgress(ul_queue_num, tp, ul_queue[ul_queue_num].size);
437
+ }
438
+ }
439
+
440
+ var ul_completion = [];
441
+ var ul_completing;
442
+
443
+ function ul_completepending(target)
444
+ {
445
+ if (ul_completion.length)
446
+ {
447
+ var ul = ul_completion.shift();
448
+
449
+ var ctx = {
450
+ target : target,
451
+ ul_queue_num : ul[5],
452
+ callback : ul_completepending2
453
+ };
454
+
455
+ api_completeupload(ul[0],ul[1],ul[2],ul[3],ul[4],ctx);
456
+ }
457
+ else ul_completing = false;
458
+ }
459
+
460
+ function ul_completepending2(res,ctx)
461
+ {
462
+ onUploadSuccess(ctx.ul_queue_num);
463
+ ul_completepending(ctx.target);
464
+ }
465
+
466
+ function file_exists(node,path,size)
467
+ {
468
+ var p = path.split('/');
469
+ var n;
470
+
471
+ return file_exists2(node,p,size);
472
+ }
473
+
474
+ function file_exists2(node,p,size)
475
+ {
476
+ if (!p.length) return false;
477
+
478
+ var i, c = p.shift();
479
+
480
+ if (!c.length) return file_exists2(node,p,size);
481
+
482
+ n = fm_matchname(node,c);
483
+
484
+ if (!p.length)
485
+ {
486
+ for (i = n.length; i--; )
487
+ {
488
+ // TODO: check for further attributes, such as timestamp
489
+ if (n[i].size == size) return true;
490
+ }
491
+ }
492
+ else for (i = n.length; i--; ) if (n[i].size < 0) return file_exists2(n[i].id,p,size);
493
+
494
+ return false;
495
+ }
496
+
497
+ function ul_chunkcomplete(slot,pos,response)
498
+ {
499
+ ul_progress[slot] = 0;
500
+ delete ul_inflight[pos];
501
+
502
+ if (response.length > 27) response = base64urldecode(response);
503
+
504
+ if (!response.length || response.length == 27)
505
+ {
506
+ if (pos >= 0) ul_intransit--;
507
+
508
+ if (ul_sendchunks[pos])
509
+ {
510
+ totalbytessent += ul_method ? ul_sendchunks[pos].buffer.length : ul_sendchunks[pos].length;
511
+ ul_updateprogress();
512
+ delete ul_sendchunks[pos];
513
+ }
514
+
515
+ if (response.length)
516
+ {
517
+ var t = [];
518
+
519
+ for (p in ul_macs) t.push(p);
520
+
521
+ t.sort(function(a,b) { return parseInt(a)-parseInt(b) });
522
+
523
+ for (var i = 0; i < t.length; i++) t[i] = ul_macs[t[i]];
524
+
525
+ var mac = condenseMacs(t,ul_key);
526
+
527
+ ul_settimeout(-1);
528
+
529
+ var ctx = { ul_queue_num : ul_queue_num,
530
+ callback : ul_completepending2
531
+ };
532
+
533
+ var filekey = [ul_key[0]^ul_key[4],ul_key[1]^ul_key[5],ul_key[2]^mac[0]^mac[1],ul_key[3]^mac[2]^mac[3],ul_key[4],ul_key[5],mac[0]^mac[1],mac[2]^mac[3]];
534
+
535
+ // TODO: add further attributes, such as filemtime...
536
+ if (u_k_aes && !ul_completing)
537
+ {
538
+ ul_completing = true;
539
+ api_completeupload(response,ul_queue[ul_queue_num].target,ul_queue[ul_queue_num].path,ul_queue[ul_queue_num].name,filekey,ctx);
540
+ }
541
+ else ul_completion.push([response,ul_queue[ul_queue_num].target,ul_queue[ul_queue_num].path,ul_queue[ul_queue_num].name,filekey,ul_queue_num]);
542
+
543
+ ul_queue_num++;
544
+
545
+ ul_uploading = false;
546
+ return startupload();
547
+ }
548
+ else ul_settimeout(ul_method ? 200000 : 60000,ul_failed);
549
+ }
550
+ else return ul_failed()
551
+
552
+ // TODO: add processing for re-requests
553
+
554
+ ul_xhrbusy[slot] = 0;
555
+
556
+ ul_dispatch_chain();
557
+ }
558
+
559
+ function ul_flash_uploaddone(slot,response)
560
+ {
561
+ ul_chunkcomplete(slot,ul_flashpos[slot],response);
562
+ }
563
+
564
+ var xhr_supports_typed_arrays = false;
565
+
566
+ function ul_dispatch_read()
567
+ {
568
+ var rpos;
569
+ var p;
570
+
571
+ if (ul_intransit > 8) return;
572
+
573
+ if (!ul_method)
574
+ {
575
+ if (ul_reader.readyState != ul_reader.LOADING)
576
+ {
577
+ for (p in ul_readq)
578
+ {
579
+ p = parseInt(p);
580
+
581
+ var blob;
582
+
583
+ if ((ul = ul_queue[ul_queue_num].slice) || (ul_queue[ul_queue_num].mozSlice))
584
+ {
585
+ if (ul_queue[ul_queue_num].mozSlice) blob = ul_queue[ul_queue_num].mozSlice(p,p+ul_readq[p]);
586
+ else blob = ul_queue[ul_queue_num].slice(p,p+ul_readq[p]);
587
+ xhr_supports_typed_arrays = true;
588
+ }
589
+ else blob = ul_queue[ul_queue_num].webkitSlice(p,p+ul_readq[p]);
590
+
591
+ ul_reader.pos = p;
592
+ ul_reader.readAsArrayBuffer(blob);
593
+ ul_reader.instance = ul_instance;
594
+
595
+ ul_reader.onloadend = function(evt)
596
+ {
597
+ if (this.instance == ul_instance)
598
+ {
599
+ if (evt.target.readyState == FileReader.DONE)
600
+ {
601
+ delete ul_readq[this.pos];
602
+
603
+ ul_plainq[this.pos] = new Uint8Array(evt.target.result);
604
+
605
+ ul_intransit++;
606
+
607
+ ul_dispatch_chain();
608
+ }
609
+ }
610
+ }
611
+
612
+ ul_reader.onerror = function(evt)
613
+ {
614
+ if (this.instance == ul_instance)
615
+ {
616
+ console.log("File Read error");
617
+ ul_failed(1);
618
+ }
619
+ }
620
+
621
+ break;
622
+ }
623
+ }
624
+ }
625
+ else
626
+ {
627
+ if (!ul_flashreaderactive)
628
+ {
629
+ ul_flashreaderactive = true;
630
+
631
+ for (p in ul_readq)
632
+ {
633
+ p = parseInt(p);
634
+
635
+ flash_requestchunk(ul_queue[ul_queue_num].flashid,ul_readq[p],p);
636
+ break;
637
+ }
638
+ }
639
+ }
640
+ }
641
+
642
+ function ul_flash_chunk(id,data,p)
643
+ {
644
+ if (ul_flashreaderactive)
645
+ {
646
+ ul_flashreaderactive = false;
647
+
648
+ if (id != ul_queue[ul_queue_num].flashid)
649
+ {
650
+ if (d) console.log("INVALID ID on Flash response");
651
+ }
652
+ else
653
+ {
654
+ ul_plainq[p] = { buffer : base64urldecode(data) };
655
+
656
+ if (ul_plainq[p].buffer.length != ul_readq[p])
657
+ {
658
+ if (d) console.log("SHORT READ in flashreader: " + ul_plainq[p].buffer.length + " != " + ul_readq[p] + " at " + p);
659
+ delete ul_plainq[p];
660
+ }
661
+ else
662
+ {
663
+ delete ul_readq[p];
664
+ ul_intransit++;
665
+ ul_dispatch_chain();
666
+ }
667
+ }
668
+ }
669
+ }
670
+
671
+ function ul_cancel()
672
+ {
673
+ if (ul_xhrs)
674
+ {
675
+ for (var i = ul_maxSlots; i--; ) if (typeof ul_xhrs[i] == 'object')
676
+ {
677
+ ul_xhrs[i].abort();
678
+ ul_xhrs[i] = undefined;
679
+ }
680
+ }
681
+
682
+ // TODO: properly abort active Flash components
683
+ ul_instance++;
684
+ ul_settimeout(-1);
685
+ ul_workers = ul_plainq = ul_reader = ul_xhrs = ul_workers = ul_sendchunks = ul_inflight = ul_readq = undefined;
686
+ ul_uploading = ul_flashreaderactive = false;
687
+
688
+ delete ul_queue[ul_queue_num].posturl;
689
+
690
+ api_req([{ a : 'u', t : ul_uploadurl }]);
691
+ }