11/*!
2- * qiniu-js-sdk v1.0.16.1 -beta
2+ * qiniu-js-sdk v1.0.17 -beta
33 *
44 * Copyright 2015 by Qiniu
55 * Released under GPL V2 License.
66 *
77 * GitHub: http://github.com/qiniu/js-sdk
88 *
9- * Date: 2016-7 -12
9+ * Date: 2016-9 -12
1010*/
1111
1212/*global plupload ,mOxie*/
@@ -160,6 +160,16 @@ function QiniuJsSDK() {
160160 "http://up.qiniu.com"
161161 ] ;
162162
163+ var qiniuUpHosts = {
164+ "http" : [
165+ "http://upload.qiniu.com" ,
166+ "http://up.qiniu.com"
167+ ] ,
168+ "https" : [
169+ "https://up.qbox.me"
170+ ]
171+ } ;
172+
163173 var changeUrlTimes = 0 ;
164174
165175 /**
@@ -170,17 +180,14 @@ function QiniuJsSDK() {
170180 * it will set 'qiniuUploadUrl' value with 'qiniuUploadUrls' looply
171181 */
172182 this . resetUploadUrl = function ( ) {
173- if ( window . location . protocol === 'https:' ) {
174- qiniuUploadUrl = 'https://up.qbox.me' ;
175- } else {
176- var i = changeUrlTimes % qiniuUploadUrls . length ;
177- qiniuUploadUrl = qiniuUploadUrls [ i ] ;
178- changeUrlTimes ++ ;
179- }
180- logger . debug ( 'resetUploadUrl: ' + qiniuUploadUrl ) ;
183+ var hosts = window . location . protocol === 'https:' ? qiniuUpHosts . https : qiniuUpHosts . http ;
184+ var i = changeUrlTimes % hosts . length ;
185+ qiniuUploadUrl = hosts [ i ] ;
186+ changeUrlTimes ++ ;
187+ logger . debug ( 'resetUploadUrl: ' + qiniuUploadUrl ) ;
181188 } ;
182189
183- this . resetUploadUrl ( ) ;
190+ // this.resetUploadUrl();
184191
185192
186193 /**
@@ -286,6 +293,62 @@ function QiniuJsSDK() {
286293 return utftext ;
287294 } ;
288295
296+ this . base64_decode = function ( data ) {
297+ // http://kevin.vanzonneveld.net
298+ // + original by: Tyler Akins (http://rumkin.com)
299+ // + improved by: Thunder.m
300+ // + input by: Aman Gupta
301+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
302+ // + bugfixed by: Onno Marsman
303+ // + bugfixed by: Pellentesque Malesuada
304+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
305+ // + input by: Brett Zamir (http://brett-zamir.me)
306+ // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
307+ // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
308+ // * returns 1: 'Kevin van Zonneveld'
309+ // mozilla has this native
310+ // - but breaks in 2.0.0.12!
311+ //if (typeof this.window['atob'] == 'function') {
312+ // return atob(data);
313+ //}
314+ var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;
315+ var o1 , o2 , o3 , h1 , h2 , h3 , h4 , bits , i = 0 ,
316+ ac = 0 ,
317+ dec = "" ,
318+ tmp_arr = [ ] ;
319+
320+ if ( ! data ) {
321+ return data ;
322+ }
323+
324+ data += '' ;
325+
326+ do { // unpack four hexets into three octets using index points in b64
327+ h1 = b64 . indexOf ( data . charAt ( i ++ ) ) ;
328+ h2 = b64 . indexOf ( data . charAt ( i ++ ) ) ;
329+ h3 = b64 . indexOf ( data . charAt ( i ++ ) ) ;
330+ h4 = b64 . indexOf ( data . charAt ( i ++ ) ) ;
331+
332+ bits = h1 << 18 | h2 << 12 | h3 << 6 | h4 ;
333+
334+ o1 = bits >> 16 & 0xff ;
335+ o2 = bits >> 8 & 0xff ;
336+ o3 = bits & 0xff ;
337+
338+ if ( h3 === 64 ) {
339+ tmp_arr [ ac ++ ] = String . fromCharCode ( o1 ) ;
340+ } else if ( h4 === 64 ) {
341+ tmp_arr [ ac ++ ] = String . fromCharCode ( o1 , o2 ) ;
342+ } else {
343+ tmp_arr [ ac ++ ] = String . fromCharCode ( o1 , o2 , o3 ) ;
344+ }
345+ } while ( i < data . length ) ;
346+
347+ dec = tmp_arr . join ( '' ) ;
348+
349+ return dec ;
350+ } ;
351+
289352 /**
290353 * encode data by base64
291354 * @param {String } data to encode
@@ -359,6 +422,11 @@ function QiniuJsSDK() {
359422 return v . replace ( / \/ / g, '_' ) . replace ( / \+ / g, '-' ) ;
360423 } ;
361424
425+ this . URLSafeBase64Decode = function ( v ) {
426+ v = v . replace ( / _ / g, '/' ) . replace ( / - / g, '+' ) ;
427+ return this . base64_decode ( v ) ;
428+ } ;
429+
362430 // TODO: use mOxie
363431 /**
364432 * craete object used to AJAX
@@ -514,15 +582,58 @@ function QiniuJsSDK() {
514582 // if op.chunk_size set 0 will be cause to direct upload
515583 } ;
516584
517- // getUptoken maybe called at Init Event or BeforeUpload Event
585+ var getHosts = function ( hosts ) {
586+ var result = [ ] ;
587+ for ( var i = 0 ; i < hosts . length ; i ++ ) {
588+ var host = hosts [ i ] ;
589+ if ( host . indexOf ( '-H' ) === 0 ) {
590+ result . push ( host . split ( ' ' ) [ 2 ] ) ;
591+ } else {
592+ result . push ( host ) ;
593+ }
594+ }
595+ return result ;
596+ } ;
597+
598+ var getUpHosts = function ( uptoken ) {
599+ var segments = uptoken . split ( ":" ) ;
600+ var ak = segments [ 0 ] ;
601+ var putPolicy = that . parseJSON ( that . URLSafeBase64Decode ( segments [ 2 ] ) ) ;
602+ var uphosts_url = "https://uc.qbox.me/v1/query?ak=" + ak + "&bucket=" + putPolicy . scope ;
603+ logger . debug ( "ak: " , ak ) ;
604+ logger . debug ( "putPolicy: " , putPolicy ) ;
605+ logger . debug ( "get uphosts from: " , uphosts_url ) ;
606+ var ajax = that . createAjax ( ) ;
607+ ajax . open ( 'GET' , uphosts_url , false ) ;
608+ ajax . send ( ) ;
609+ if ( ajax . status === 200 ) {
610+ var res = that . parseJSON ( ajax . responseText ) ;
611+ qiniuUpHosts . http = getHosts ( res . http . up ) ;
612+ qiniuUpHosts . https = getHosts ( res . https . up ) ;
613+ logger . debug ( "get new uphosts: " , qiniuUpHosts ) ;
614+ that . resetUploadUrl ( ) ;
615+ } else {
616+ logger . error ( "get uphosts error: " , ajax . responseText ) ;
617+ }
618+ return ;
619+ } ;
620+
621+ var getUptoken = function ( file ) {
622+ if ( ! that . token || that . tokenInfo . isExpired ( ) ) {
623+ return getNewUpToken ( file ) ;
624+ } else {
625+ return that . token ;
626+ }
627+ } ;
628+
629+ // getNewUptoken maybe called at Init Event or BeforeUpload Event
518630 // case Init Event, the file param of getUptken will be set a null value
519631 // if op.uptoken has value, set uptoken with op.uptoken
520632 // else if op.uptoken_url has value, set uptoken from op.uptoken_url
521633 // else if op.uptoken_func has value, set uptoken by result of op.uptoken_func
522- var getUpToken = function ( file ) {
634+ var getNewUpToken = function ( file ) {
523635 if ( op . uptoken ) {
524636 that . token = op . uptoken ;
525- return ;
526637 } else if ( op . uptoken_url ) {
527638 logger . debug ( "get uptoken from: " , that . uptoken_url ) ;
528639 // TODO: use mOxie
@@ -539,19 +650,40 @@ function QiniuJsSDK() {
539650 if ( ajax . status === 200 ) {
540651 var res = that . parseJSON ( ajax . responseText ) ;
541652 that . token = res . uptoken ;
542- logger . debug ( "get new uptoken: " , res . uptoken ) ;
653+ var segments = that . token . split ( ":" ) ;
654+ var putPolicy = that . parseJSON ( that . URLSafeBase64Decode ( segments [ 2 ] ) ) ;
655+ if ( ! that . tokenMap ) {
656+ that . tokenMap = { } ;
657+ }
658+ var getTimestamp = function ( time ) {
659+ return Math . ceil ( time . getTime ( ) / 1000 ) ;
660+ } ;
661+ var serverTime = getTimestamp ( new Date ( ajax . getResponseHeader ( "date" ) ) ) ;
662+ var clientTime = getTimestamp ( new Date ( ) ) ;
663+ that . tokenInfo = {
664+ serverDelay : clientTime - serverTime ,
665+ deadline : putPolicy . deadline ,
666+ isExpired : function ( ) {
667+ var leftTime = this . deadline - getTimestamp ( new Date ( ) ) + this . serverDelay ;
668+ return leftTime < 600 ;
669+ }
670+ } ;
671+ logger . debug ( "get new uptoken: " , that . token ) ;
672+ logger . debug ( "get token info: " , that . tokenInfo ) ;
543673 } else {
544674 logger . error ( "get uptoken error: " , ajax . responseText ) ;
545675 }
546- return ;
547676 } else if ( op . uptoken_func ) {
548677 logger . debug ( "get uptoken from uptoken_func" ) ;
549678 that . token = op . uptoken_func ( file ) ;
550679 logger . debug ( "get new uptoken: " , that . token ) ;
551- return ;
552680 } else {
553681 logger . error ( "one of [uptoken, uptoken_url, uptoken_func] settings in options is required!" ) ;
554682 }
683+ if ( that . token ) {
684+ getUpHosts ( that . token ) ;
685+ }
686+ return that . token ;
555687 } ;
556688
557689 // get file key according with the user passed options
@@ -650,17 +782,17 @@ function QiniuJsSDK() {
650782
651783 logger . debug ( "new plupload.Uploader(option)" ) ;
652784
653- // bind getUpToken to 'Init' event
785+ // bind getNewUpToken to 'Init' event
654786 uploader . bind ( 'Init' , function ( up , params ) {
655787 logger . debug ( "Init event activated" ) ;
656788 // if op.get_new_uptoken is not true
657- // invoke getUptoken when uploader init
789+ // invoke getNewUptoken when uploader init
658790 // else
659- // getUptoken everytime before a new file upload
791+ // getNewUptoken everytime before a new file upload
660792 if ( ! op . get_new_uptoken ) {
661- getUpToken ( null ) ;
793+ getNewUpToken ( null ) ;
662794 }
663- //getUpToken (null);
795+ //getNewUpToken (null);
664796 } ) ;
665797
666798 logger . debug ( "bind Init event" ) ;
@@ -722,7 +854,7 @@ function QiniuJsSDK() {
722854 ctx = '' ;
723855
724856 if ( op . get_new_uptoken ) {
725- getUpToken ( file ) ;
857+ getNewUpToken ( file ) ;
726858 }
727859
728860 var directUpload = function ( up , file , func ) {
@@ -859,7 +991,7 @@ function QiniuJsSDK() {
859991 'chunk_size' : chunk_size ,
860992 'required_features' : "chunks" ,
861993 'headers' : {
862- 'Authorization' : 'UpToken ' + that . token
994+ 'Authorization' : 'UpToken ' + getUptoken ( file )
863995 } ,
864996 'multipart_params' : multipart_params_obj
865997 } ) ;
@@ -907,6 +1039,11 @@ function QiniuJsSDK() {
9071039 } ) ;
9081040 logger . debug ( "up.setOption url: " , qiniuUploadUrl + '/mkblk/' + leftSize ) ;
9091041 }
1042+ up . setOption ( {
1043+ 'headers' : {
1044+ 'Authorization' : 'UpToken ' + getUptoken ( file )
1045+ }
1046+ } ) ;
9101047 localStorage . setItem ( file . name , that . stringifyJSON ( {
9111048 ctx : ctx ,
9121049 percent : file . percent ,
0 commit comments