base.js 154 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782
  1. var REQUEST = require('../lib/request');
  2. var util = require('./util');
  3. // Bucket 相关
  4. /**
  5. * 获取用户的 bucket 列表
  6. * @param {Object} params 回调函数,必须,下面为参数列表
  7. * 无特殊参数
  8. * @param {Function} callback 回调函数,必须
  9. */
  10. function getService(params, callback) {
  11. if (typeof params === 'function') {
  12. callback = params;
  13. params = {};
  14. }
  15. var protocol = this.options.Protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:');
  16. var domain = this.options.ServiceDomain;
  17. var appId = params.AppId || this.options.appId;
  18. var region = params.Region;
  19. if (domain) {
  20. domain = domain.replace(/\{\{AppId\}\}/ig, appId || '')
  21. .replace(/\{\{Region\}\}/ig, region || '').replace(/\{\{.*?\}\}/ig, '');
  22. if (!/^[a-zA-Z]+:\/\//.test(domain)) {
  23. domain = protocol + '//' + domain;
  24. }
  25. if (domain.slice(-1) === '/') {
  26. domain = domain.slice(0, -1);
  27. }
  28. } else if (region) {
  29. domain = protocol + '//cos.' + region + '.myqcloud.com';
  30. } else {
  31. domain = protocol + '//service.cos.myqcloud.com';
  32. }
  33. var SignHost = '';
  34. var standardHost = region ? 'cos.' + region + '.myqcloud.com' : 'service.cos.myqcloud.com';
  35. var urlHost = domain.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1');
  36. if (standardHost === urlHost) SignHost = standardHost;
  37. submitRequest.call(this, {
  38. Action: 'name/cos:GetService',
  39. url: domain,
  40. method: 'GET',
  41. headers: params.Headers,
  42. SignHost: SignHost,
  43. }, function (err, data) {
  44. if (err) return callback(err);
  45. var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets
  46. && data.ListAllMyBucketsResult.Buckets.Bucket) || [];
  47. buckets = util.isArray(buckets) ? buckets : [buckets];
  48. var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {};
  49. callback(null, {
  50. Buckets: buckets,
  51. Owner: owner,
  52. statusCode: data.statusCode,
  53. headers: data.headers,
  54. });
  55. });
  56. }
  57. /**
  58. * 创建 Bucket,并初始化访问权限
  59. * @param {Object} params 参数对象,必须
  60. * @param {String} params.Bucket Bucket名称,必须
  61. * @param {String} params.Region 地域名称,必须
  62. * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须
  63. * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须
  64. * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须
  65. * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须
  66. * @param {Function} callback 回调函数,必须
  67. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  68. * @return {Object} data 返回的数据
  69. * @return {String} data.Location 操作地址
  70. */
  71. function putBucket(params, callback) {
  72. var self = this;
  73. var xml = '';
  74. if(params['BucketAZConfig']){
  75. var CreateBucketConfiguration = {
  76. BucketAZConfig: params.BucketAZConfig
  77. };
  78. xml = util.json2xml({CreateBucketConfiguration: CreateBucketConfiguration});
  79. }
  80. submitRequest.call(this, {
  81. Action: 'name/cos:PutBucket',
  82. method: 'PUT',
  83. Bucket: params.Bucket,
  84. Region: params.Region,
  85. headers: params.Headers,
  86. body: xml,
  87. }, function (err, data) {
  88. if (err) return callback(err);
  89. var url = getUrl({
  90. protocol: self.options.Protocol,
  91. domain: self.options.Domain,
  92. bucket: params.Bucket,
  93. region: params.Region,
  94. isLocation: true,
  95. });
  96. callback(null, {
  97. Location: url,
  98. statusCode: data.statusCode,
  99. headers: data.headers,
  100. });
  101. });
  102. }
  103. /**
  104. * 查看是否存在该Bucket,是否有权限访问
  105. * @param {Object} params 参数对象,必须
  106. * @param {String} params.Bucket Bucket名称,必须
  107. * @param {String} params.Region 地域名称,必须
  108. * @param {Function} callback 回调函数,必须
  109. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  110. * @return {Object} data 返回的数据
  111. * @return {Boolean} data.BucketExist Bucket是否存在
  112. * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限
  113. */
  114. function headBucket(params, callback) {
  115. submitRequest.call(this, {
  116. Action: 'name/cos:HeadBucket',
  117. Bucket: params.Bucket,
  118. Region: params.Region,
  119. headers: params.Headers,
  120. method: 'HEAD',
  121. }, callback);
  122. }
  123. /**
  124. * 获取 Bucket 下的 object 列表
  125. * @param {Object} params 参数对象,必须
  126. * @param {String} params.Bucket Bucket名称,必须
  127. * @param {String} params.Region 地域名称,必须
  128. * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须
  129. * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,非必须
  130. * @param {String} params.Marker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须
  131. * @param {String} params.MaxKeys 单次返回最大的条目数量,默认1000,非必须
  132. * @param {String} params.EncodingType 规定返回值的编码方式,非必须
  133. * @param {Function} callback 回调函数,必须
  134. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  135. * @return {Object} data 返回的数据
  136. * @return {Object} data.ListBucketResult 返回的 object 列表信息
  137. */
  138. function getBucket(params, callback) {
  139. var reqParams = {};
  140. reqParams['prefix'] = params['Prefix'] || '';
  141. reqParams['delimiter'] = params['Delimiter'];
  142. reqParams['marker'] = params['Marker'];
  143. reqParams['max-keys'] = params['MaxKeys'];
  144. reqParams['encoding-type'] = params['EncodingType'];
  145. submitRequest.call(this, {
  146. Action: 'name/cos:GetBucket',
  147. ResourceKey: reqParams['prefix'],
  148. method: 'GET',
  149. Bucket: params.Bucket,
  150. Region: params.Region,
  151. headers: params.Headers,
  152. qs: reqParams,
  153. }, function (err, data) {
  154. if (err) return callback(err);
  155. var ListBucketResult = data.ListBucketResult || {};
  156. var Contents = ListBucketResult.Contents || [];
  157. var CommonPrefixes = ListBucketResult.CommonPrefixes || [];
  158. Contents = util.isArray(Contents) ? Contents : [Contents];
  159. CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes];
  160. var result = util.clone(ListBucketResult);
  161. util.extend(result, {
  162. Contents: Contents,
  163. CommonPrefixes: CommonPrefixes,
  164. statusCode: data.statusCode,
  165. headers: data.headers,
  166. });
  167. callback(null, result);
  168. });
  169. }
  170. /**
  171. * 删除 Bucket
  172. * @param {Object} params 参数对象,必须
  173. * @param {String} params.Bucket Bucket名称,必须
  174. * @param {String} params.Region 地域名称,必须
  175. * @param {Function} callback 回调函数,必须
  176. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  177. * @return {Object} data 返回的数据
  178. * @return {String} data.Location 操作地址
  179. */
  180. function deleteBucket(params, callback) {
  181. submitRequest.call(this, {
  182. Action: 'name/cos:DeleteBucket',
  183. Bucket: params.Bucket,
  184. Region: params.Region,
  185. headers: params.Headers,
  186. method: 'DELETE',
  187. }, function (err, data) {
  188. if (err && err.statusCode === 204) {
  189. return callback(null, {statusCode: err.statusCode});
  190. } else if (err) {
  191. return callback(err);
  192. }
  193. callback(null, {
  194. statusCode: data.statusCode,
  195. headers: data.headers,
  196. });
  197. });
  198. }
  199. /**
  200. * 设置 Bucket 的 权限列表
  201. * @param {Object} params 参数对象,必须
  202. * @param {String} params.Bucket Bucket名称,必须
  203. * @param {String} params.Region 地域名称,必须
  204. * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须
  205. * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须
  206. * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须
  207. * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须
  208. * @param {Function} callback 回调函数,必须
  209. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  210. * @return {Object} data 返回的数据
  211. */
  212. function putBucketAcl(params, callback) {
  213. var headers = params.Headers;
  214. var xml = '';
  215. if (params['AccessControlPolicy']) {
  216. var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {});
  217. var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant;
  218. Grants = util.isArray(Grants) ? Grants : [Grants];
  219. delete AccessControlPolicy.Grant;
  220. delete AccessControlPolicy.Grants;
  221. AccessControlPolicy.AccessControlList = {Grant: Grants};
  222. xml = util.json2xml({AccessControlPolicy: AccessControlPolicy});
  223. headers['Content-Type'] = 'application/xml';
  224. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  225. }
  226. // Grant Header 去重
  227. util.each(headers, function (val, key) {
  228. if (key.indexOf('x-cos-grant-') === 0) {
  229. headers[key] = uniqGrant(headers[key]);
  230. }
  231. });
  232. submitRequest.call(this, {
  233. Action: 'name/cos:PutBucketACL',
  234. method: 'PUT',
  235. Bucket: params.Bucket,
  236. Region: params.Region,
  237. headers: headers,
  238. action: 'acl',
  239. body: xml,
  240. }, function (err, data) {
  241. if (err) return callback(err);
  242. callback(null, {
  243. statusCode: data.statusCode,
  244. headers: data.headers,
  245. });
  246. });
  247. }
  248. /**
  249. * 获取 Bucket 的 权限列表
  250. * @param {Object} params 参数对象,必须
  251. * @param {String} params.Bucket Bucket名称,必须
  252. * @param {String} params.Region 地域名称,必须
  253. * @param {Function} callback 回调函数,必须
  254. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  255. * @return {Object} data 返回的数据
  256. * @return {Object} data.AccessControlPolicy 访问权限信息
  257. */
  258. function getBucketAcl(params, callback) {
  259. submitRequest.call(this, {
  260. Action: 'name/cos:GetBucketACL',
  261. method: 'GET',
  262. Bucket: params.Bucket,
  263. Region: params.Region,
  264. headers: params.Headers,
  265. action: 'acl',
  266. }, function (err, data) {
  267. if (err) return callback(err);
  268. var AccessControlPolicy = data.AccessControlPolicy || {};
  269. var Owner = AccessControlPolicy.Owner || {};
  270. var Grant = AccessControlPolicy.AccessControlList.Grant || [];
  271. Grant = util.isArray(Grant) ? Grant : [Grant];
  272. var result = decodeAcl(AccessControlPolicy);
  273. if (data.headers && data.headers['x-cos-acl']) {
  274. result.ACL = data.headers['x-cos-acl'];
  275. }
  276. result = util.extend(result, {
  277. Owner: Owner,
  278. Grants: Grant,
  279. statusCode: data.statusCode,
  280. headers: data.headers,
  281. });
  282. callback(null, result);
  283. });
  284. }
  285. /**
  286. * 设置 Bucket 的 跨域设置
  287. * @param {Object} params 参数对象,必须
  288. * @param {String} params.Bucket Bucket名称,必须
  289. * @param {String} params.Region 地域名称,必须
  290. * @param {Object} params.CORSConfiguration 相关的跨域设置,必须
  291. * @param {Array} params.CORSConfiguration.CORSRules 对应的跨域规则
  292. * @param {Function} callback 回调函数,必须
  293. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  294. * @return {Object} data 返回的数据
  295. */
  296. function putBucketCors(params, callback) {
  297. var CORSConfiguration = params['CORSConfiguration'] || {};
  298. var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || [];
  299. CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]);
  300. util.each(CORSRules, function (rule) {
  301. util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) {
  302. var sKey = key + 's';
  303. var val = rule[sKey] || rule[key] || [];
  304. delete rule[sKey];
  305. rule[key] = util.isArray(val) ? val : [val];
  306. });
  307. });
  308. var Conf = {CORSRule: CORSRules};
  309. if (params.ResponseVary) Conf.ResponseVary = params.ResponseVary;
  310. var xml = util.json2xml({CORSConfiguration: Conf});
  311. var headers = params.Headers;
  312. headers['Content-Type'] = 'application/xml';
  313. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  314. submitRequest.call(this, {
  315. Action: 'name/cos:PutBucketCORS',
  316. method: 'PUT',
  317. Bucket: params.Bucket,
  318. Region: params.Region,
  319. body: xml,
  320. action: 'cors',
  321. headers: headers,
  322. }, function (err, data) {
  323. if (err) return callback(err);
  324. callback(null, {
  325. statusCode: data.statusCode,
  326. headers: data.headers,
  327. });
  328. });
  329. }
  330. /**
  331. * 获取 Bucket 的 跨域设置
  332. * @param {Object} params 参数对象,必须
  333. * @param {String} params.Bucket Bucket名称,必须
  334. * @param {String} params.Region 地域名称,必须
  335. * @param {Function} callback 回调函数,必须
  336. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  337. * @return {Object} data 返回的数据
  338. * @return {Object} data.CORSRules Bucket的跨域设置
  339. */
  340. function getBucketCors(params, callback) {
  341. submitRequest.call(this, {
  342. Action: 'name/cos:GetBucketCORS',
  343. method: 'GET',
  344. Bucket: params.Bucket,
  345. Region: params.Region,
  346. headers: params.Headers,
  347. action: 'cors',
  348. }, function (err, data) {
  349. if (err) {
  350. if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') {
  351. var result = {
  352. CORSRules: [],
  353. statusCode: err.statusCode,
  354. };
  355. err.headers && (result.headers = err.headers);
  356. callback(null, result);
  357. } else {
  358. callback(err);
  359. }
  360. return;
  361. }
  362. var CORSConfiguration = data.CORSConfiguration || {};
  363. var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || [];
  364. CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]);
  365. var ResponseVary = CORSConfiguration.ResponseVary;
  366. util.each(CORSRules, function (rule) {
  367. util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) {
  368. var sKey = key + 's';
  369. var val = rule[sKey] || rule[key] || [];
  370. delete rule[key];
  371. rule[sKey] = util.isArray(val) ? val : [val];
  372. });
  373. });
  374. callback(null, {
  375. CORSRules: CORSRules,
  376. ResponseVary: ResponseVary,
  377. statusCode: data.statusCode,
  378. headers: data.headers,
  379. });
  380. });
  381. }
  382. /**
  383. * 删除 Bucket 的 跨域设置
  384. * @param {Object} params 参数对象,必须
  385. * @param {String} params.Bucket Bucket名称,必须
  386. * @param {String} params.Region 地域名称,必须
  387. * @param {Function} callback 回调函数,必须
  388. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  389. * @return {Object} data 返回的数据
  390. */
  391. function deleteBucketCors(params, callback) {
  392. submitRequest.call(this, {
  393. Action: 'name/cos:DeleteBucketCORS',
  394. method: 'DELETE',
  395. Bucket: params.Bucket,
  396. Region: params.Region,
  397. headers: params.Headers,
  398. action: 'cors',
  399. }, function (err, data) {
  400. if (err && err.statusCode === 204) {
  401. return callback(null, {statusCode: err.statusCode});
  402. } else if (err) {
  403. return callback(err);
  404. }
  405. callback(null, {
  406. statusCode: data.statusCode || err.statusCode,
  407. headers: data.headers,
  408. });
  409. });
  410. }
  411. /**
  412. * 获取 Bucket 的 地域信息
  413. * @param {Object} params 参数对象,必须
  414. * @param {String} params.Bucket Bucket名称,必须
  415. * @param {String} params.Region 地域名称,必须
  416. * @param {Function} callback 回调函数,必须
  417. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  418. * @return {Object} data 返回数据,包含地域信息 LocationConstraint
  419. */
  420. function getBucketLocation(params, callback) {
  421. submitRequest.call(this, {
  422. Action: 'name/cos:GetBucketLocation',
  423. method: 'GET',
  424. Bucket: params.Bucket,
  425. Region: params.Region,
  426. headers: params.Headers,
  427. action: 'location',
  428. }, callback);
  429. }
  430. function putBucketPolicy(params, callback) {
  431. var Policy = params['Policy'];
  432. try {
  433. if (typeof Policy === 'string') Policy = JSON.parse(Policy);
  434. } catch (e) {
  435. }
  436. if (!Policy || typeof Policy === 'string') return callback(util.error(new Error('Policy format error')));
  437. var PolicyStr = JSON.stringify(Policy);
  438. if (!Policy.version) Policy.version = '2.0';
  439. var headers = params.Headers;
  440. headers['Content-Type'] = 'application/json';
  441. headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr));
  442. submitRequest.call(this, {
  443. Action: 'name/cos:PutBucketPolicy',
  444. method: 'PUT',
  445. Bucket: params.Bucket,
  446. Region: params.Region,
  447. action: 'policy',
  448. body: PolicyStr,
  449. headers: headers,
  450. }, function (err, data) {
  451. if (err && err.statusCode === 204) {
  452. return callback(null, {statusCode: err.statusCode});
  453. } else if (err) {
  454. return callback(err);
  455. }
  456. callback(null, {
  457. statusCode: data.statusCode,
  458. headers: data.headers,
  459. });
  460. });
  461. }
  462. /**
  463. * 获取 Bucket 的读取权限策略
  464. * @param {Object} params 参数对象,必须
  465. * @param {String} params.Bucket Bucket名称,必须
  466. * @param {String} params.Region 地域名称,必须
  467. * @param {Function} callback 回调函数,必须
  468. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  469. * @return {Object} data 返回数据
  470. */
  471. function getBucketPolicy(params, callback) {
  472. submitRequest.call(this, {
  473. Action: 'name/cos:GetBucketPolicy',
  474. method: 'GET',
  475. Bucket: params.Bucket,
  476. Region: params.Region,
  477. headers: params.Headers,
  478. action: 'policy',
  479. rawBody: true,
  480. }, function (err, data) {
  481. if (err) {
  482. if (err.statusCode && err.statusCode === 403) {
  483. return callback(util.error(err, {ErrorStatus: 'Access Denied'}));
  484. }
  485. if (err.statusCode && err.statusCode === 405) {
  486. return callback(util.error(err, {ErrorStatus: 'Method Not Allowed'}));
  487. }
  488. if (err.statusCode && err.statusCode === 404) {
  489. return callback(util.error(err, {ErrorStatus: 'Policy Not Found'}));
  490. }
  491. return callback(err);
  492. }
  493. var Policy = {};
  494. try {
  495. Policy = JSON.parse(data.body);
  496. } catch (e) {
  497. }
  498. callback(null, {
  499. Policy: Policy,
  500. statusCode: data.statusCode,
  501. headers: data.headers,
  502. });
  503. });
  504. }
  505. /**
  506. * 删除 Bucket 的 跨域设置
  507. * @param {Object} params 参数对象,必须
  508. * @param {String} params.Bucket Bucket名称,必须
  509. * @param {String} params.Region 地域名称,必须
  510. * @param {Function} callback 回调函数,必须
  511. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  512. * @return {Object} data 返回的数据
  513. */
  514. function deleteBucketPolicy(params, callback) {
  515. submitRequest.call(this, {
  516. Action: 'name/cos:DeleteBucketPolicy',
  517. method: 'DELETE',
  518. Bucket: params.Bucket,
  519. Region: params.Region,
  520. headers: params.Headers,
  521. action: 'policy',
  522. }, function (err, data) {
  523. if (err && err.statusCode === 204) {
  524. return callback(null, {statusCode: err.statusCode});
  525. } else if (err) {
  526. return callback(err);
  527. }
  528. callback(null, {
  529. statusCode: data.statusCode || err.statusCode,
  530. headers: data.headers,
  531. });
  532. });
  533. }
  534. /**
  535. * 设置 Bucket 的标签
  536. * @param {Object} params 参数对象,必须
  537. * @param {String} params.Bucket Bucket名称,必须
  538. * @param {String} params.Region 地域名称,必须
  539. * @param {Array} params.TagSet 标签设置,必须
  540. * @param {Function} callback 回调函数,必须
  541. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  542. * @return {Object} data 返回数据
  543. */
  544. function putBucketTagging(params, callback) {
  545. var Tagging = params['Tagging'] || {};
  546. var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || [];
  547. Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
  548. var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}});
  549. var headers = params.Headers;
  550. headers['Content-Type'] = 'application/xml';
  551. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  552. submitRequest.call(this, {
  553. Action: 'name/cos:PutBucketTagging',
  554. method: 'PUT',
  555. Bucket: params.Bucket,
  556. Region: params.Region,
  557. body: xml,
  558. action: 'tagging',
  559. headers: headers,
  560. }, function (err, data) {
  561. if (err && err.statusCode === 204) {
  562. return callback(null, {statusCode: err.statusCode});
  563. } else if (err) {
  564. return callback(err);
  565. }
  566. callback(null, {
  567. statusCode: data.statusCode,
  568. headers: data.headers,
  569. });
  570. });
  571. }
  572. /**
  573. * 获取 Bucket 的标签设置
  574. * @param {Object} params 参数对象,必须
  575. * @param {String} params.Bucket Bucket名称,必须
  576. * @param {String} params.Region 地域名称,必须
  577. * @param {Function} callback 回调函数,必须
  578. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  579. * @return {Object} data 返回数据
  580. */
  581. function getBucketTagging(params, callback) {
  582. submitRequest.call(this, {
  583. Action: 'name/cos:GetBucketTagging',
  584. method: 'GET',
  585. Bucket: params.Bucket,
  586. Region: params.Region,
  587. headers: params.Headers,
  588. action: 'tagging',
  589. }, function (err, data) {
  590. if (err) {
  591. if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) {
  592. var result = {
  593. Tags: [],
  594. statusCode: err.statusCode,
  595. };
  596. err.headers && (result.headers = err.headers);
  597. callback(null, result);
  598. } else {
  599. callback(err);
  600. }
  601. return;
  602. }
  603. var Tags = [];
  604. try {
  605. Tags = data.Tagging.TagSet.Tag || [];
  606. } catch (e) {
  607. }
  608. Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
  609. callback(null, {
  610. Tags: Tags,
  611. statusCode: data.statusCode,
  612. headers: data.headers,
  613. });
  614. });
  615. }
  616. /**
  617. * 删除 Bucket 的 标签设置
  618. * @param {Object} params 参数对象,必须
  619. * @param {String} params.Bucket Bucket名称,必须
  620. * @param {String} params.Region 地域名称,必须
  621. * @param {Function} callback 回调函数,必须
  622. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  623. * @return {Object} data 返回的数据
  624. */
  625. function deleteBucketTagging(params, callback) {
  626. submitRequest.call(this, {
  627. Action: 'name/cos:DeleteBucketTagging',
  628. method: 'DELETE',
  629. Bucket: params.Bucket,
  630. Region: params.Region,
  631. headers: params.Headers,
  632. action: 'tagging',
  633. }, function (err, data) {
  634. if (err && err.statusCode === 204) {
  635. return callback(null, {statusCode: err.statusCode});
  636. } else if (err) {
  637. return callback(err);
  638. }
  639. callback(null, {
  640. statusCode: data.statusCode,
  641. headers: data.headers,
  642. });
  643. });
  644. }
  645. function putBucketLifecycle(params, callback) {
  646. var LifecycleConfiguration = params['LifecycleConfiguration'] || {};
  647. var Rules = LifecycleConfiguration.Rules || params.Rules || [];
  648. Rules = util.clone(Rules);
  649. var xml = util.json2xml({LifecycleConfiguration: {Rule: Rules}});
  650. var headers = params.Headers;
  651. headers['Content-Type'] = 'application/xml';
  652. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  653. submitRequest.call(this, {
  654. Action: 'name/cos:PutBucketLifecycle',
  655. method: 'PUT',
  656. Bucket: params.Bucket,
  657. Region: params.Region,
  658. body: xml,
  659. action: 'lifecycle',
  660. headers: headers,
  661. }, function (err, data) {
  662. if (err && err.statusCode === 204) {
  663. return callback(null, {statusCode: err.statusCode});
  664. } else if (err) {
  665. return callback(err);
  666. }
  667. callback(null, {
  668. statusCode: data.statusCode,
  669. headers: data.headers,
  670. });
  671. });
  672. }
  673. function getBucketLifecycle(params, callback) {
  674. submitRequest.call(this, {
  675. Action: 'name/cos:GetBucketLifecycle',
  676. method: 'GET',
  677. Bucket: params.Bucket,
  678. Region: params.Region,
  679. headers: params.Headers,
  680. action: 'lifecycle',
  681. }, function (err, data) {
  682. if (err) {
  683. if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') {
  684. var result = {
  685. Rules: [],
  686. statusCode: err.statusCode,
  687. };
  688. err.headers && (result.headers = err.headers);
  689. callback(null, result);
  690. } else {
  691. callback(err);
  692. }
  693. return;
  694. }
  695. var Rules = [];
  696. try {
  697. Rules = data.LifecycleConfiguration.Rule || [];
  698. } catch (e) {
  699. }
  700. Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]);
  701. callback(null, {
  702. Rules: Rules,
  703. statusCode: data.statusCode,
  704. headers: data.headers,
  705. });
  706. });
  707. }
  708. function deleteBucketLifecycle(params, callback) {
  709. submitRequest.call(this, {
  710. Action: 'name/cos:DeleteBucketLifecycle',
  711. method: 'DELETE',
  712. Bucket: params.Bucket,
  713. Region: params.Region,
  714. headers: params.Headers,
  715. action: 'lifecycle',
  716. }, function (err, data) {
  717. if (err && err.statusCode === 204) {
  718. return callback(null, {statusCode: err.statusCode});
  719. } else if (err) {
  720. return callback(err);
  721. }
  722. callback(null, {
  723. statusCode: data.statusCode,
  724. headers: data.headers,
  725. });
  726. });
  727. }
  728. function putBucketVersioning(params, callback) {
  729. if (!params['VersioningConfiguration']) {
  730. callback(util.error(new Error('missing param VersioningConfiguration')));
  731. return;
  732. }
  733. var VersioningConfiguration = params['VersioningConfiguration'] || {};
  734. var xml = util.json2xml({VersioningConfiguration: VersioningConfiguration});
  735. var headers = params.Headers;
  736. headers['Content-Type'] = 'application/xml';
  737. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  738. submitRequest.call(this, {
  739. Action: 'name/cos:PutBucketVersioning',
  740. method: 'PUT',
  741. Bucket: params.Bucket,
  742. Region: params.Region,
  743. body: xml,
  744. action: 'versioning',
  745. headers: headers,
  746. }, function (err, data) {
  747. if (err && err.statusCode === 204) {
  748. return callback(null, {statusCode: err.statusCode});
  749. } else if (err) {
  750. return callback(err);
  751. }
  752. callback(null, {
  753. statusCode: data.statusCode,
  754. headers: data.headers,
  755. });
  756. });
  757. }
  758. function getBucketVersioning(params, callback) {
  759. submitRequest.call(this, {
  760. Action: 'name/cos:GetBucketVersioning',
  761. method: 'GET',
  762. Bucket: params.Bucket,
  763. Region: params.Region,
  764. headers: params.Headers,
  765. action: 'versioning',
  766. }, function (err, data) {
  767. if (!err) {
  768. !data.VersioningConfiguration && (data.VersioningConfiguration = {});
  769. }
  770. callback(err, data);
  771. });
  772. }
  773. function putBucketReplication(params, callback) {
  774. var ReplicationConfiguration = util.clone(params.ReplicationConfiguration);
  775. var xml = util.json2xml({ReplicationConfiguration: ReplicationConfiguration});
  776. xml = xml.replace(/<(\/?)Rules>/ig, '<$1Rule>');
  777. xml = xml.replace(/<(\/?)Tags>/ig, '<$1Tag>');
  778. var headers = params.Headers;
  779. headers['Content-Type'] = 'application/xml';
  780. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  781. submitRequest.call(this, {
  782. Action: 'name/cos:PutBucketReplication',
  783. method: 'PUT',
  784. Bucket: params.Bucket,
  785. Region: params.Region,
  786. body: xml,
  787. action: 'replication',
  788. headers: headers,
  789. }, function (err, data) {
  790. if (err && err.statusCode === 204) {
  791. return callback(null, {statusCode: err.statusCode});
  792. } else if (err) {
  793. return callback(err);
  794. }
  795. callback(null, {
  796. statusCode: data.statusCode,
  797. headers: data.headers,
  798. });
  799. });
  800. }
  801. function getBucketReplication(params, callback) {
  802. submitRequest.call(this, {
  803. Action: 'name/cos:GetBucketReplication',
  804. method: 'GET',
  805. Bucket: params.Bucket,
  806. Region: params.Region,
  807. headers: params.Headers,
  808. action: 'replication',
  809. }, function (err, data) {
  810. if (err) {
  811. if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')) {
  812. var result = {
  813. ReplicationConfiguration: {Rules: []},
  814. statusCode: err.statusCode,
  815. };
  816. err.headers && (result.headers = err.headers);
  817. callback(null, result);
  818. } else {
  819. callback(err);
  820. }
  821. return;
  822. }
  823. !data.ReplicationConfiguration && (data.ReplicationConfiguration = {});
  824. if (data.ReplicationConfiguration.Rule) {
  825. data.ReplicationConfiguration.Rules = util.makeArray(data.ReplicationConfiguration.Rule);
  826. delete data.ReplicationConfiguration.Rule;
  827. }
  828. callback(err, data);
  829. });
  830. }
  831. function deleteBucketReplication(params, callback) {
  832. submitRequest.call(this, {
  833. Action: 'name/cos:DeleteBucketReplication',
  834. method: 'DELETE',
  835. Bucket: params.Bucket,
  836. Region: params.Region,
  837. headers: params.Headers,
  838. action: 'replication',
  839. }, function (err, data) {
  840. if (err && err.statusCode === 204) {
  841. return callback(null, {statusCode: err.statusCode});
  842. } else if (err) {
  843. return callback(err);
  844. }
  845. callback(null, {
  846. statusCode: data.statusCode,
  847. headers: data.headers,
  848. });
  849. });
  850. }
  851. /**
  852. * 设置 Bucket 静态网站配置信息
  853. * @param {Object} params 参数对象,必须
  854. * @param {String} params.Bucket Bucket名称,必须
  855. * @param {String} params.Region 地域名称,必须
  856. * @param {Object} params.WebsiteConfiguration 地域名称,必须
  857. * @param {Object} WebsiteConfiguration.IndexDocument 索引文档,必须
  858. * @param {Object} WebsiteConfiguration.ErrorDocument 错误文档,非必须
  859. * @param {Object} WebsiteConfiguration.RedirectAllRequestsTo 重定向所有请求,非必须
  860. * @param {Array} params.RoutingRules 重定向规则,非必须
  861. * @param {Function} callback 回调函数,必须
  862. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  863. * @return {Object} data 返回数据
  864. */
  865. function putBucketWebsite(params, callback) {
  866. if (!params['WebsiteConfiguration']) {
  867. callback(util.error(new Error('missing param WebsiteConfiguration')));
  868. return;
  869. }
  870. var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {});
  871. var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || [];
  872. RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules];
  873. delete WebsiteConfiguration.RoutingRule;
  874. delete WebsiteConfiguration.RoutingRules;
  875. if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules };
  876. var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration });
  877. var headers = params.Headers;
  878. headers['Content-Type'] = 'application/xml';
  879. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  880. submitRequest.call(this, {
  881. Action: 'name/cos:PutBucketWebsite',
  882. method: 'PUT',
  883. Bucket: params.Bucket,
  884. Region: params.Region,
  885. body: xml,
  886. action: 'website',
  887. headers: headers,
  888. }, function (err, data) {
  889. if (err && err.statusCode === 204) {
  890. return callback(null, {statusCode: err.statusCode});
  891. } else if (err) {
  892. return callback(err);
  893. }
  894. callback(null, {
  895. statusCode: data.statusCode,
  896. headers: data.headers,
  897. });
  898. });
  899. }
  900. /**
  901. * 获取 Bucket 的静态网站配置信息
  902. * @param {Object} params 参数对象,必须
  903. * @param {String} params.Bucket Bucket名称,必须
  904. * @param {String} params.Region 地域名称,必须
  905. * @param {Function} callback 回调函数,必须
  906. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  907. * @return {Object} data 返回数据
  908. */
  909. function getBucketWebsite(params, callback) {
  910. submitRequest.call(this, {
  911. Action: 'name/cos:GetBucketWebsite',
  912. method: 'GET',
  913. Bucket: params.Bucket,
  914. Region: params.Region,
  915. Key: params.Key,
  916. headers: params.Headers,
  917. action: 'website',
  918. }, function (err, data) {
  919. if (err) {
  920. if(err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration'){
  921. var result = {
  922. WebsiteConfiguration: {},
  923. statusCode: err.statusCode,
  924. };
  925. err.headers && (result.headers = err.headers);
  926. callback(null, result);
  927. } else {
  928. callback(err);
  929. }
  930. return;
  931. }
  932. var WebsiteConfiguration = data.WebsiteConfiguration || {};
  933. if (WebsiteConfiguration['RoutingRules']) {
  934. var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []);
  935. RoutingRules = util.makeArray(RoutingRules);
  936. WebsiteConfiguration.RoutingRules = RoutingRules;
  937. }
  938. callback(null, {
  939. WebsiteConfiguration: WebsiteConfiguration,
  940. statusCode: data.statusCode,
  941. headers: data.headers,
  942. });
  943. });
  944. }
  945. /**
  946. * 删除 Bucket 的静态网站配置
  947. * @param {Object} params 参数对象,必须
  948. * @param {String} params.Bucket Bucket名称,必须
  949. * @param {String} params.Region 地域名称,必须
  950. * @param {Function} callback 回调函数,必须
  951. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  952. * @return {Object} data 返回数据
  953. */
  954. function deleteBucketWebsite(params, callback) {
  955. submitRequest.call(this, {
  956. Action: 'name/cos:DeleteBucketWebsite',
  957. method: 'DELETE',
  958. Bucket: params.Bucket,
  959. Region: params.Region,
  960. headers: params.Headers,
  961. action: 'website',
  962. }, function (err, data) {
  963. if (err && err.statusCode === 204) {
  964. return callback(null, {statusCode: err.statusCode});
  965. } else if (err) {
  966. return callback(err);
  967. }
  968. callback(null, {
  969. statusCode: data.statusCode,
  970. headers: data.headers,
  971. });
  972. });
  973. }
  974. /**
  975. * 设置 Bucket 的防盗链白名单或者黑名单
  976. * @param {Object} params 参数对象,必须
  977. * @param {String} params.Bucket Bucket名称,必须
  978. * @param {String} params.Region 地域名称,必须
  979. * @param {Object} params.RefererConfiguration 地域名称,必须
  980. * @param {String} RefererConfiguration.Status 是否开启防盗链,枚举值:Enabled、Disabled
  981. * @param {String} RefererConfiguration.RefererType 防盗链类型,枚举值:Black-List、White-List,必须
  982. * @param {Array} RefererConfiguration.DomianList.Domain 生效域名,必须
  983. * @param {String} RefererConfiguration.EmptyReferConfiguration ,非必须
  984. * @param {Function} callback 回调函数,必须
  985. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  986. * @return {Object} data 返回数据
  987. */
  988. function putBucketReferer(params, callback) {
  989. if (!params['RefererConfiguration']) {
  990. callback(util.error(new Error('missing param RefererConfiguration')));
  991. return;
  992. }
  993. var RefererConfiguration = util.clone(params['RefererConfiguration'] || {});
  994. var DomainList = RefererConfiguration['DomainList'] || {};
  995. var Domains = DomainList['Domains'] || DomainList['Domain'] || [];
  996. Domains = util.isArray(Domains) ? Domains : [Domains];
  997. if (Domains.length) RefererConfiguration.DomainList = {Domain: Domains};
  998. var xml = util.json2xml({ RefererConfiguration: RefererConfiguration });
  999. var headers = params.Headers;
  1000. headers['Content-Type'] = 'application/xml';
  1001. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1002. submitRequest.call(this, {
  1003. Action: 'name/cos:PutBucketReferer',
  1004. method: 'PUT',
  1005. Bucket: params.Bucket,
  1006. Region: params.Region,
  1007. body: xml,
  1008. action: 'referer',
  1009. headers: headers,
  1010. }, function (err, data) {
  1011. if (err && err.statusCode === 204) {
  1012. return callback(null, {statusCode: err.statusCode});
  1013. } else if (err) {
  1014. return callback(err);
  1015. }
  1016. callback(null, {
  1017. statusCode: data.statusCode,
  1018. headers: data.headers,
  1019. });
  1020. });
  1021. }
  1022. /**
  1023. * 获取 Bucket 的防盗链白名单或者黑名单
  1024. * @param {Object} params 参数对象,必须
  1025. * @param {String} params.Bucket Bucket名称,必须
  1026. * @param {String} params.Region 地域名称,必须
  1027. * @param {Function} callback 回调函数,必须
  1028. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1029. * @return {Object} data 返回数据
  1030. */
  1031. function getBucketReferer(params, callback) {
  1032. submitRequest.call(this, {
  1033. Action: 'name/cos:GetBucketReferer',
  1034. method: 'GET',
  1035. Bucket: params.Bucket,
  1036. Region: params.Region,
  1037. Key: params.Key,
  1038. headers: params.Headers,
  1039. action: 'referer',
  1040. }, function (err, data) {
  1041. if (err) {
  1042. if(err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration'){
  1043. var result = {
  1044. WebsiteConfiguration: {},
  1045. statusCode: err.statusCode,
  1046. };
  1047. err.headers && (result.headers = err.headers);
  1048. callback(null, result);
  1049. } else {
  1050. callback(err);
  1051. }
  1052. return;
  1053. }
  1054. var RefererConfiguration = data.RefererConfiguration || {};
  1055. if (RefererConfiguration['DomainList']) {
  1056. var Domains = util.makeArray(RefererConfiguration['DomainList'].Domain || []);
  1057. RefererConfiguration.DomainList = {Domains: Domains};
  1058. }
  1059. callback(null, {
  1060. RefererConfiguration: RefererConfiguration,
  1061. statusCode: data.statusCode,
  1062. headers: data.headers,
  1063. });
  1064. });
  1065. }
  1066. /**
  1067. * 设置 Bucket 自定义域名
  1068. * @param {Object} params 参数对象,必须
  1069. * @param {String} params.Bucket Bucket名称,必须
  1070. * @param {String} params.Region 地域名称,必须
  1071. * @param {Function} callback 回调函数,必须
  1072. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1073. * @return {Object} data 返回数据
  1074. */
  1075. function putBucketDomain(params, callback) {
  1076. var DomainConfiguration = params['DomainConfiguration'] || {};
  1077. var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || [];
  1078. DomainRule = util.clone(DomainRule);
  1079. var xml = util.json2xml({DomainConfiguration: {DomainRule: DomainRule}});
  1080. var headers = params.Headers;
  1081. headers['Content-Type'] = 'application/xml';
  1082. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1083. submitRequest.call(this, {
  1084. Action: 'name/cos:PutBucketDomain',
  1085. method: 'PUT',
  1086. Bucket: params.Bucket,
  1087. Region: params.Region,
  1088. body: xml,
  1089. action: 'domain',
  1090. headers: headers,
  1091. }, function (err, data) {
  1092. if (err && err.statusCode === 204) {
  1093. return callback(null, {statusCode: err.statusCode});
  1094. } else if (err) {
  1095. return callback(err);
  1096. }
  1097. callback(null, {
  1098. statusCode: data.statusCode,
  1099. headers: data.headers,
  1100. });
  1101. });
  1102. }
  1103. /**
  1104. * 获取 Bucket 的自定义域名
  1105. * @param {Object} params 参数对象,必须
  1106. * @param {String} params.Bucket Bucket名称,必须
  1107. * @param {String} params.Region 地域名称,必须
  1108. * @param {Function} callback 回调函数,必须
  1109. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1110. * @return {Object} data 返回数据
  1111. */
  1112. function getBucketDomain(params, callback) {
  1113. submitRequest.call(this, {
  1114. Action: 'name/cos:GetBucketDomain',
  1115. method: 'GET',
  1116. Bucket: params.Bucket,
  1117. Region: params.Region,
  1118. headers: params.Headers,
  1119. action: 'domain',
  1120. }, function (err, data) {
  1121. if (err) return callback(err);
  1122. var DomainRule = [];
  1123. try {
  1124. DomainRule = data.DomainConfiguration.DomainRule || [];
  1125. } catch (e) {
  1126. }
  1127. DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]);
  1128. callback(null, {
  1129. DomainRule: DomainRule,
  1130. statusCode: data.statusCode,
  1131. headers: data.headers,
  1132. });
  1133. });
  1134. }
  1135. /**
  1136. * 删除 Bucket 自定义域名
  1137. * @param {Object} params 参数对象,必须
  1138. * @param {String} params.Bucket Bucket名称,必须
  1139. * @param {String} params.Region 地域名称,必须
  1140. * @param {Function} callback 回调函数,必须
  1141. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1142. * @return {Object} data 返回数据
  1143. */
  1144. function deleteBucketDomain(params, callback) {
  1145. submitRequest.call(this, {
  1146. Action: 'name/cos:DeleteBucketDomain',
  1147. method: 'DELETE',
  1148. Bucket: params.Bucket,
  1149. Region: params.Region,
  1150. headers: params.Headers,
  1151. action: 'domain',
  1152. }, function (err, data) {
  1153. if (err && err.statusCode === 204) {
  1154. return callback(null, {statusCode: err.statusCode});
  1155. } else if (err) {
  1156. return callback(err);
  1157. }
  1158. callback(null, {
  1159. statusCode: data.statusCode,
  1160. headers: data.headers,
  1161. });
  1162. });
  1163. }
  1164. /**
  1165. * 设置 Bucket 的回源
  1166. * @param {Object} params 参数对象,必须
  1167. * @param {String} params.Bucket Bucket名称,必须
  1168. * @param {String} params.Region 地域名称,必须
  1169. * @param {Function} callback 回调函数,必须
  1170. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1171. * @return {Object} data 返回数据
  1172. */
  1173. function putBucketOrigin(params, callback){
  1174. var OriginConfiguration = params['OriginConfiguration'] || {};
  1175. var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || [];
  1176. OriginRule = util.clone(OriginRule);
  1177. var xml = util.json2xml({OriginConfiguration: {OriginRule: OriginRule}});
  1178. var headers = params.Headers;
  1179. headers['Content-Type'] = 'application/xml';
  1180. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1181. submitRequest.call(this, {
  1182. Action: 'name/cos:PutBucketOrigin',
  1183. method: 'PUT',
  1184. Bucket: params.Bucket,
  1185. Region: params.Region,
  1186. body: xml,
  1187. action: 'origin',
  1188. headers: headers,
  1189. }, function (err, data) {
  1190. if (err && err.statusCode === 204) {
  1191. return callback(null, {statusCode: err.statusCode});
  1192. } else if (err) {
  1193. return callback(err);
  1194. }
  1195. callback(null, {
  1196. statusCode: data.statusCode,
  1197. headers: data.headers,
  1198. });
  1199. });
  1200. }
  1201. /**
  1202. * 获取 Bucket 的回源
  1203. * @param {Object} params 参数对象,必须
  1204. * @param {String} params.Bucket Bucket名称,必须
  1205. * @param {String} params.Region 地域名称,必须
  1206. * @param {Function} callback 回调函数,必须
  1207. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1208. * @return {Object} data 返回数据
  1209. */
  1210. function getBucketOrigin(params, callback) {
  1211. submitRequest.call(this, {
  1212. Action: 'name/cos:GetBucketOrigin',
  1213. method: 'GET',
  1214. Bucket: params.Bucket,
  1215. Region: params.Region,
  1216. headers: params.Headers,
  1217. action: 'origin',
  1218. }, function (err, data) {
  1219. if (err) return callback(err);
  1220. var OriginRule = [];
  1221. try {
  1222. OriginRule = data.OriginConfiguration.OriginRule || [];
  1223. } catch (e) {
  1224. }
  1225. OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]);
  1226. callback(null, {
  1227. OriginRule: OriginRule,
  1228. statusCode: data.statusCode,
  1229. headers: data.headers,
  1230. });
  1231. });
  1232. }
  1233. /**
  1234. * 删除 Bucket 的回源
  1235. * @param {Object} params 参数对象,必须
  1236. * @param {String} params.Bucket Bucket名称,必须
  1237. * @param {String} params.Region 地域名称,必须
  1238. * @param {Function} callback 回调函数,必须
  1239. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1240. * @return {Object} data 返回数据
  1241. */
  1242. function deleteBucketOrigin(params, callback) {
  1243. submitRequest.call(this, {
  1244. Action: 'name/cos:DeleteBucketOrigin',
  1245. method: 'DELETE',
  1246. Bucket: params.Bucket,
  1247. Region: params.Region,
  1248. headers: params.Headers,
  1249. action: 'origin',
  1250. }, function (err, data) {
  1251. if (err && err.statusCode === 204) {
  1252. return callback(null, {statusCode: err.statusCode});
  1253. } else if (err) {
  1254. return callback(err);
  1255. }
  1256. callback(null, {
  1257. statusCode: data.statusCode,
  1258. headers: data.headers,
  1259. });
  1260. });
  1261. }
  1262. /**
  1263. * 设置 Bucket 的日志记录
  1264. * @param {Object} params 参数对象,必须
  1265. * @param {String} params.Bucket Bucket名称,必须
  1266. * @param {String} params.Region 地域名称,必须
  1267. * @param {(Object|String)} params.BucketLoggingStatus 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录,必须
  1268. * @param {Function} callback 回调函数,必须
  1269. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1270. * @return {Object} data 返回数据
  1271. */
  1272. function putBucketLogging(params, callback) {
  1273. var xml = util.json2xml({
  1274. BucketLoggingStatus: params['BucketLoggingStatus'] || ''
  1275. });
  1276. var headers = params.Headers;
  1277. headers['Content-Type'] = 'application/xml';
  1278. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1279. submitRequest.call(this, {
  1280. Action: 'name/cos:PutBucketLogging',
  1281. method: 'PUT',
  1282. Bucket: params.Bucket,
  1283. Region: params.Region,
  1284. body: xml,
  1285. action: 'logging',
  1286. headers: headers,
  1287. }, function (err, data) {
  1288. if (err && err.statusCode === 204) {
  1289. return callback(null, {statusCode: err.statusCode});
  1290. } else if (err) {
  1291. return callback(err);
  1292. }
  1293. callback(null, {
  1294. statusCode: data.statusCode,
  1295. headers: data.headers,
  1296. });
  1297. });
  1298. }
  1299. /**
  1300. * 获取 Bucket 的日志记录
  1301. * @param {Object} params 参数对象,必须
  1302. * @param {String} params.Bucket Bucket名称,必须
  1303. * @param {String} params.Region 地域名称,必须
  1304. * @param {Function} callback 回调函数,必须
  1305. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1306. * @return {Object} data 返回数据
  1307. */
  1308. function getBucketLogging(params, callback) {
  1309. submitRequest.call(this, {
  1310. Action: 'name/cos:GetBucketLogging',
  1311. method: 'GET',
  1312. Bucket: params.Bucket,
  1313. Region: params.Region,
  1314. headers: params.Headers,
  1315. action: 'logging',
  1316. }, function (err, data) {
  1317. if (err) return callback(err);
  1318. callback(null, {
  1319. BucketLoggingStatus: data.BucketLoggingStatus,
  1320. statusCode: data.statusCode,
  1321. headers: data.headers,
  1322. });
  1323. });
  1324. }
  1325. /**
  1326. * 创建/编辑 Bucket 的清单任务
  1327. * @param {Object} params 参数对象,必须
  1328. * @param {String} params.Bucket Bucket名称,必须
  1329. * @param {String} params.Region 地域名称,必须
  1330. * @param {String} params.Id 清单任务的名称,必须
  1331. * @param {Object} params.InventoryConfiguration 包含清单的配置参数,必须
  1332. * @param {Function} callback 回调函数,必须
  1333. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1334. * @return {Object} data 返回数据
  1335. */
  1336. function putBucketInventory(params, callback) {
  1337. var InventoryConfiguration = util.clone(params['InventoryConfiguration']);
  1338. if (InventoryConfiguration.OptionalFields) {
  1339. var Field = InventoryConfiguration.OptionalFields || [];
  1340. InventoryConfiguration.OptionalFields = {
  1341. Field: Field
  1342. };
  1343. }
  1344. if (InventoryConfiguration.Destination
  1345. && InventoryConfiguration.Destination.COSBucketDestination
  1346. && InventoryConfiguration.Destination.COSBucketDestination.Encryption
  1347. ) {
  1348. var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption;
  1349. if (Object.keys(Encryption).indexOf('SSECOS') > -1) {
  1350. Encryption['SSE-COS'] = Encryption['SSECOS'];
  1351. delete Encryption['SSECOS'];
  1352. }
  1353. }
  1354. var xml = util.json2xml({
  1355. InventoryConfiguration: InventoryConfiguration
  1356. });
  1357. var headers = params.Headers;
  1358. headers['Content-Type'] = 'application/xml';
  1359. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1360. submitRequest.call(this, {
  1361. Action: 'name/cos:PutBucketInventory',
  1362. method: 'PUT',
  1363. Bucket: params.Bucket,
  1364. Region: params.Region,
  1365. body: xml,
  1366. action: 'inventory',
  1367. qs: {
  1368. id: params['Id']
  1369. },
  1370. headers: headers,
  1371. }, function (err, data) {
  1372. if (err && err.statusCode === 204) {
  1373. return callback(null, {statusCode: err.statusCode});
  1374. } else if (err) {
  1375. return callback(err);
  1376. }
  1377. callback(null, {
  1378. statusCode: data.statusCode,
  1379. headers: data.headers,
  1380. });
  1381. });
  1382. }
  1383. /**
  1384. * 获取 Bucket 的清单任务信息
  1385. * @param {Object} params 参数对象,必须
  1386. * @param {String} params.Bucket Bucket名称,必须
  1387. * @param {String} params.Region 地域名称,必须
  1388. * @param {String} params.Id 清单任务的名称,必须
  1389. * @param {Function} callback 回调函数,必须
  1390. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1391. * @return {Object} data 返回数据
  1392. */
  1393. function getBucketInventory(params, callback) {
  1394. submitRequest.call(this, {
  1395. Action: 'name/cos:GetBucketInventory',
  1396. method: 'GET',
  1397. Bucket: params.Bucket,
  1398. Region: params.Region,
  1399. headers: params.Headers,
  1400. action: 'inventory',
  1401. qs: {
  1402. id: params['Id']
  1403. }
  1404. }, function (err, data) {
  1405. if (err) return callback(err);
  1406. var InventoryConfiguration = data['InventoryConfiguration'];
  1407. if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) {
  1408. var Field = InventoryConfiguration.OptionalFields.Field;
  1409. if (!util.isArray(Field)) {
  1410. Field = [Field];
  1411. }
  1412. InventoryConfiguration.OptionalFields = Field;
  1413. }
  1414. if (InventoryConfiguration.Destination
  1415. && InventoryConfiguration.Destination.COSBucketDestination
  1416. && InventoryConfiguration.Destination.COSBucketDestination.Encryption
  1417. ) {
  1418. var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption;
  1419. if (Object.keys(Encryption).indexOf('SSE-COS') > -1) {
  1420. Encryption['SSECOS'] = Encryption['SSE-COS'];
  1421. delete Encryption['SSE-COS'];
  1422. }
  1423. }
  1424. callback(null, {
  1425. InventoryConfiguration: InventoryConfiguration,
  1426. statusCode: data.statusCode,
  1427. headers: data.headers,
  1428. });
  1429. });
  1430. }
  1431. /**
  1432. * 获取 Bucket 的清单任务信息
  1433. * @param {Object} params 参数对象,必须
  1434. * @param {String} params.Bucket Bucket名称,必须
  1435. * @param {String} params.Region 地域名称,必须
  1436. * @param {String} params.ContinuationToken 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息,非必须
  1437. * @param {Function} callback 回调函数,必须
  1438. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1439. * @return {Object} data 返回数据
  1440. */
  1441. function listBucketInventory(params, callback) {
  1442. submitRequest.call(this, {
  1443. Action: 'name/cos:ListBucketInventory',
  1444. method: 'GET',
  1445. Bucket: params.Bucket,
  1446. Region: params.Region,
  1447. headers: params.Headers,
  1448. action: 'inventory',
  1449. qs: {
  1450. 'continuation-token': params['ContinuationToken']
  1451. }
  1452. }, function (err, data) {
  1453. if (err) return callback(err);
  1454. var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult'];
  1455. var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || [];
  1456. InventoryConfigurations = util.isArray(InventoryConfigurations) ? InventoryConfigurations : [InventoryConfigurations];
  1457. delete ListInventoryConfigurationResult['InventoryConfiguration'];
  1458. util.each(InventoryConfigurations, function (InventoryConfiguration) {
  1459. if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) {
  1460. var Field = InventoryConfiguration.OptionalFields.Field;
  1461. if (!util.isArray(Field)) {
  1462. Field = [Field];
  1463. }
  1464. InventoryConfiguration.OptionalFields = Field;
  1465. }
  1466. if (InventoryConfiguration.Destination
  1467. && InventoryConfiguration.Destination.COSBucketDestination
  1468. && InventoryConfiguration.Destination.COSBucketDestination.Encryption
  1469. ) {
  1470. var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption;
  1471. if (Object.keys(Encryption).indexOf('SSE-COS') > -1) {
  1472. Encryption['SSECOS'] = Encryption['SSE-COS'];
  1473. delete Encryption['SSE-COS'];
  1474. }
  1475. }
  1476. });
  1477. ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations;
  1478. util.extend(ListInventoryConfigurationResult, {
  1479. statusCode: data.statusCode,
  1480. headers: data.headers,
  1481. });
  1482. callback(null, ListInventoryConfigurationResult);
  1483. });
  1484. }
  1485. /**
  1486. * 删除 Bucket 的清单任务
  1487. * @param {Object} params 参数对象,必须
  1488. * @param {String} params.Bucket Bucket名称,必须
  1489. * @param {String} params.Region 地域名称,必须
  1490. * @param {String} params.Id 清单任务的名称,必须
  1491. * @param {Function} callback 回调函数,必须
  1492. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1493. * @return {Object} data 返回数据
  1494. */
  1495. function deleteBucketInventory(params, callback) {
  1496. submitRequest.call(this, {
  1497. Action: 'name/cos:DeleteBucketInventory',
  1498. method: 'DELETE',
  1499. Bucket: params.Bucket,
  1500. Region: params.Region,
  1501. headers: params.Headers,
  1502. action: 'inventory',
  1503. qs: {
  1504. id: params['Id']
  1505. }
  1506. }, function (err, data) {
  1507. if (err && err.statusCode === 204) {
  1508. return callback(null, {statusCode: err.statusCode});
  1509. } else if (err) {
  1510. return callback(err);
  1511. }
  1512. callback(null, {
  1513. statusCode: data.statusCode,
  1514. headers: data.headers,
  1515. });
  1516. });
  1517. }
  1518. /* 全球加速 */
  1519. function putBucketAccelerate(params, callback) {
  1520. if (!params['AccelerateConfiguration']) {
  1521. callback(util.error(new Error('missing param AccelerateConfiguration')));
  1522. return;
  1523. }
  1524. var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} };
  1525. var xml = util.json2xml(configuration);
  1526. var headers = {};
  1527. headers['Content-Type'] = 'application/xml';
  1528. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1529. submitRequest.call(this, {
  1530. Action: 'name/cos:PutBucketAccelerate',
  1531. method: 'PUT',
  1532. Bucket: params.Bucket,
  1533. Region: params.Region,
  1534. body: xml,
  1535. action: 'accelerate',
  1536. headers: headers,
  1537. }, function (err, data) {
  1538. if (err) return callback(err);
  1539. callback(null, {
  1540. statusCode: data.statusCode,
  1541. headers: data.headers,
  1542. });
  1543. });
  1544. }
  1545. function getBucketAccelerate(params, callback) {
  1546. submitRequest.call(this, {
  1547. Action: 'name/cos:GetBucketAccelerate',
  1548. method: 'GET',
  1549. Bucket: params.Bucket,
  1550. Region: params.Region,
  1551. action: 'accelerate',
  1552. }, function (err, data) {
  1553. if (!err) {
  1554. !data.AccelerateConfiguration && (data.AccelerateConfiguration = {});
  1555. }
  1556. callback(err, data);
  1557. });
  1558. }
  1559. function putBucketEncryption(params, callback) {
  1560. var conf = params.ServerSideEncryptionConfiguration || {};
  1561. var Rules = conf.Rule || conf.Rules || [];
  1562. var xml = util.json2xml({ServerSideEncryptionConfiguration: {Rule:Rules}});
  1563. var headers = params.Headers;
  1564. headers['Content-Type'] = 'application/xml';
  1565. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1566. submitRequest.call(this, {
  1567. Action: 'name/cos:PutBucketEncryption',
  1568. method: 'PUT',
  1569. Bucket: params.Bucket,
  1570. Region: params.Region,
  1571. body: xml,
  1572. action: 'encryption',
  1573. headers: headers,
  1574. }, function (err, data) {
  1575. if (err && err.statusCode === 204) {
  1576. return callback(null, {statusCode: err.statusCode});
  1577. } else if (err) {
  1578. return callback(err);
  1579. }
  1580. callback(null, {
  1581. statusCode: data.statusCode,
  1582. headers: data.headers,
  1583. });
  1584. });
  1585. }
  1586. function getBucketEncryption(params, callback) {
  1587. submitRequest.call(this, {
  1588. Action: 'name/cos:GetBucketEncryption',
  1589. method: 'GET',
  1590. Bucket: params.Bucket,
  1591. Region: params.Region,
  1592. headers: params.Headers,
  1593. action: 'encryption',
  1594. }, function (err, data) {
  1595. if (err) {
  1596. if (err.statusCode === 404 && err.code === 'NoSuchEncryptionConfiguration') {
  1597. var result = {
  1598. EncryptionConfiguration: {Rules: []},
  1599. statusCode: err.statusCode,
  1600. };
  1601. err.headers && (result.headers = err.headers);
  1602. callback(null, result);
  1603. } else {
  1604. callback(err);
  1605. }
  1606. return;
  1607. }
  1608. var Rules = util.makeArray(data.EncryptionConfiguration && data.EncryptionConfiguration.Rule || []);
  1609. data.EncryptionConfiguration = {Rules: Rules};
  1610. callback(err, data);
  1611. });
  1612. }
  1613. function deleteBucketEncryption(params, callback) {
  1614. submitRequest.call(this, {
  1615. Action: 'name/cos:DeleteBucketReplication',
  1616. method: 'DELETE',
  1617. Bucket: params.Bucket,
  1618. Region: params.Region,
  1619. headers: params.Headers,
  1620. action: 'encryption',
  1621. }, function (err, data) {
  1622. if (err && err.statusCode === 204) {
  1623. return callback(null, {statusCode: err.statusCode});
  1624. } else if (err) {
  1625. return callback(err);
  1626. }
  1627. callback(null, {
  1628. statusCode: data.statusCode,
  1629. headers: data.headers,
  1630. });
  1631. });
  1632. }
  1633. // Object 相关
  1634. /**
  1635. * 取回对应Object的元数据,Head的权限与Get的权限一致
  1636. * @param {Object} params 参数对象,必须
  1637. * @param {String} params.Bucket Bucket名称,必须
  1638. * @param {String} params.Region 地域名称,必须
  1639. * @param {String} params.Key 文件名称,必须
  1640. * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须
  1641. * @param {Function} callback 回调函数,必须
  1642. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1643. * @return {Object} data 为指定 object 的元数据,如果设置了 IfModifiedSince ,且文件未修改,则返回一个对象,NotModified 属性为 true
  1644. * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true
  1645. */
  1646. function headObject(params, callback) {
  1647. submitRequest.call(this, {
  1648. Action: 'name/cos:HeadObject',
  1649. method: 'HEAD',
  1650. Bucket: params.Bucket,
  1651. Region: params.Region,
  1652. Key: params.Key,
  1653. VersionId: params.VersionId,
  1654. headers: params.Headers,
  1655. }, function (err, data) {
  1656. if (err) {
  1657. var statusCode = err.statusCode;
  1658. if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) {
  1659. return callback(null, {
  1660. NotModified: true,
  1661. statusCode: statusCode,
  1662. });
  1663. }
  1664. return callback(err);
  1665. }
  1666. data.ETag = util.attr(data.headers, 'etag', '');
  1667. callback(null, data);
  1668. });
  1669. }
  1670. function listObjectVersions(params, callback) {
  1671. var reqParams = {};
  1672. reqParams['prefix'] = params['Prefix'] || '';
  1673. reqParams['delimiter'] = params['Delimiter'];
  1674. reqParams['key-marker'] = params['KeyMarker'];
  1675. reqParams['version-id-marker'] = params['VersionIdMarker'];
  1676. reqParams['max-keys'] = params['MaxKeys'];
  1677. reqParams['encoding-type'] = params['EncodingType'];
  1678. submitRequest.call(this, {
  1679. Action: 'name/cos:GetBucketObjectVersions',
  1680. ResourceKey: reqParams['prefix'],
  1681. method: 'GET',
  1682. Bucket: params.Bucket,
  1683. Region: params.Region,
  1684. headers: params.Headers,
  1685. qs: reqParams,
  1686. action: 'versions',
  1687. }, function (err, data) {
  1688. if (err) return callback(err);
  1689. var ListVersionsResult = data.ListVersionsResult || {};
  1690. var DeleteMarkers = ListVersionsResult.DeleteMarker || [];
  1691. DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers];
  1692. var Versions = ListVersionsResult.Version || [];
  1693. Versions = util.isArray(Versions) ? Versions : [Versions];
  1694. var result = util.clone(ListVersionsResult);
  1695. delete result.DeleteMarker;
  1696. delete result.Version;
  1697. util.extend(result, {
  1698. DeleteMarkers: DeleteMarkers,
  1699. Versions: Versions,
  1700. statusCode: data.statusCode,
  1701. headers: data.headers,
  1702. });
  1703. callback(null, result);
  1704. });
  1705. }
  1706. /**
  1707. * 下载 object
  1708. * @param {Object} params 参数对象,必须
  1709. * @param {String} params.Bucket Bucket名称,必须
  1710. * @param {String} params.Region 地域名称,必须
  1711. * @param {String} params.Key 文件名称,必须
  1712. * @param {WriteStream} params.Output 文件写入流,非必须
  1713. * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须
  1714. * @param {String} params.IfUnmodifiedSince 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed),非必须
  1715. * @param {String} params.IfMatch 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed),非必须
  1716. * @param {String} params.IfNoneMatch 当 ETag 与指定的内容不一致,才返回文件。否则返回304 (not modified),非必须
  1717. * @param {String} params.ResponseContentType 设置返回头部中的 Content-Type 参数,非必须
  1718. * @param {String} params.ResponseContentLanguage 设置返回头部中的 Content-Language 参数,非必须
  1719. * @param {String} params.ResponseExpires 设置返回头部中的 Content-Expires 参数,非必须
  1720. * @param {String} params.ResponseCacheControl 设置返回头部中的 Cache-Control 参数,非必须
  1721. * @param {String} params.ResponseContentDisposition 设置返回头部中的 Content-Disposition 参数,非必须
  1722. * @param {String} params.ResponseContentEncoding 设置返回头部中的 Content-Encoding 参数,非必须
  1723. * @param {Function} callback 回调函数,必须
  1724. * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1725. * @param {Object} data 为对应的 object 数据,包括 body 和 headers
  1726. */
  1727. function getObject(params, callback) {
  1728. var reqParams = params.Query || {};
  1729. var reqParamsStr = params.QueryString || '';
  1730. var onProgress = util.throttleOnProgress.call(this, 0, params.onProgress);
  1731. reqParams['response-content-type'] = params['ResponseContentType'];
  1732. reqParams['response-content-language'] = params['ResponseContentLanguage'];
  1733. reqParams['response-expires'] = params['ResponseExpires'];
  1734. reqParams['response-cache-control'] = params['ResponseCacheControl'];
  1735. reqParams['response-content-disposition'] = params['ResponseContentDisposition'];
  1736. reqParams['response-content-encoding'] = params['ResponseContentEncoding'];
  1737. // 如果用户自己传入了 output
  1738. submitRequest.call(this, {
  1739. Action: 'name/cos:GetObject',
  1740. method: 'GET',
  1741. Bucket: params.Bucket,
  1742. Region: params.Region,
  1743. Key: params.Key,
  1744. VersionId: params.VersionId,
  1745. DataType: params.DataType,
  1746. headers: params.Headers,
  1747. qs: reqParams,
  1748. qsStr: reqParamsStr,
  1749. rawBody: true,
  1750. onDownloadProgress: onProgress,
  1751. }, function (err, data) {
  1752. onProgress(null, true);
  1753. if (err) {
  1754. var statusCode = err.statusCode;
  1755. if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) {
  1756. return callback(null, {
  1757. NotModified: true
  1758. });
  1759. }
  1760. return callback(err);
  1761. }
  1762. callback(null, {
  1763. Body: data.body,
  1764. ETag: util.attr(data.headers, 'etag', ''),
  1765. statusCode: data.statusCode,
  1766. headers: data.headers,
  1767. });
  1768. });
  1769. }
  1770. /**
  1771. * 上传 object
  1772. * @param {Object} params 参数对象,必须
  1773. * @param {String} params.Bucket Bucket名称,必须
  1774. * @param {String} params.Region 地域名称,必须
  1775. * @param {String} params.Key 文件名称,必须
  1776. * @param {File || Blob || String} params.Body 上传文件对象或字符串,必须
  1777. * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须
  1778. * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须
  1779. * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须
  1780. * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须
  1781. * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须
  1782. * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须
  1783. * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须
  1784. * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须
  1785. * @param {String} params.GrantRead 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  1786. * @param {String} params.GrantReadAcp 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  1787. * @param {String} params.GrantWriteAcp 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  1788. * @param {String} params.GrantFullControl 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  1789. * @param {String} params.StorageClass 设置对象的存储级别,枚举值:STANDARD、STANDARD_IA、ARCHIVE,默认值:STANDARD,非必须
  1790. * @param {String} params.x-cos-meta-* 允许用户自定义的头部信息,将作为对象的元数据保存。大小限制2KB,非必须
  1791. * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须
  1792. * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
  1793. * @param {Function} params.onProgress 上传进度回调函数
  1794. * @param {Function} callback 回调函数,必须
  1795. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1796. * @return {Object} data 为对应的 object 数据
  1797. * @return {String} data.ETag 为对应上传文件的 ETag 值
  1798. */
  1799. function putObject(params, callback) {
  1800. var self = this;
  1801. var FileSize = params.ContentLength;
  1802. var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress);
  1803. // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里
  1804. var headers = params.Headers;
  1805. if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
  1806. if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = params.Body && params.Body.type || '';
  1807. var needCalcMd5 = params.UploadAddMetaMd5 || self.options.UploadAddMetaMd5 || self.options.UploadCheckContentMd5;
  1808. util.getBodyMd5(needCalcMd5, params.Body, function (md5) {
  1809. if (md5) {
  1810. if (self.options.UploadCheckContentMd5) headers['Content-MD5'] = util.binaryBase64(md5);
  1811. if (params.UploadAddMetaMd5 || self.options.UploadAddMetaMd5) headers['x-cos-meta-md5'] = md5;
  1812. }
  1813. if (params.ContentLength !== undefined) headers['Content-Length'] = params.ContentLength;
  1814. onProgress(null, true); // 任务状态开始 uploading
  1815. submitRequest.call(self, {
  1816. Action: 'name/cos:PutObject',
  1817. TaskId: params.TaskId,
  1818. method: 'PUT',
  1819. Bucket: params.Bucket,
  1820. Region: params.Region,
  1821. Key: params.Key,
  1822. headers: params.Headers,
  1823. qs: params.Query,
  1824. body: params.Body,
  1825. onProgress: onProgress,
  1826. }, function (err, data) {
  1827. if (err) {
  1828. onProgress(null, true);
  1829. return callback(err);
  1830. }
  1831. onProgress({loaded: FileSize, total: FileSize}, true);
  1832. var url = getUrl({
  1833. ForcePathStyle: self.options.ForcePathStyle,
  1834. protocol: self.options.Protocol,
  1835. domain: self.options.Domain,
  1836. bucket: params.Bucket,
  1837. region: !self.options.UseAccelerate ? params.Region : 'accelerate',
  1838. object: params.Key,
  1839. });
  1840. url = url.substr(url.indexOf('://') + 3);
  1841. data.Location = url;
  1842. data.ETag = util.attr(data.headers, 'etag', '');
  1843. callback(null, data);
  1844. });
  1845. }, params.onHashProgress);
  1846. }
  1847. /**
  1848. * 删除 object
  1849. * @param {Object} params 参数对象,必须
  1850. * @param {String} params.Bucket Bucket名称,必须
  1851. * @param {String} params.Region 地域名称,必须
  1852. * @param {String} params.Key object名称,必须
  1853. * @param {Function} callback 回调函数,必须
  1854. * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1855. * @param {Object} data 删除操作成功之后返回的数据
  1856. */
  1857. function deleteObject(params, callback) {
  1858. submitRequest.call(this, {
  1859. Action: 'name/cos:DeleteObject',
  1860. method: 'DELETE',
  1861. Bucket: params.Bucket,
  1862. Region: params.Region,
  1863. Key: params.Key,
  1864. headers: params.Headers,
  1865. VersionId: params.VersionId,
  1866. action: params.Recursive ? 'recursive' : '',
  1867. }, function (err, data) {
  1868. if (err) {
  1869. var statusCode = err.statusCode;
  1870. if (statusCode && statusCode === 404) {
  1871. return callback(null, {BucketNotFound: true, statusCode: statusCode,});
  1872. } else {
  1873. return callback(err);
  1874. }
  1875. }
  1876. callback(null, {
  1877. statusCode: data.statusCode,
  1878. headers: data.headers,
  1879. });
  1880. });
  1881. }
  1882. /**
  1883. * 获取 object 的 权限列表
  1884. * @param {Object} params 参数对象,必须
  1885. * @param {String} params.Bucket Bucket名称,必须
  1886. * @param {String} params.Region 地域名称,必须
  1887. * @param {String} params.Key object名称,必须
  1888. * @param {Function} callback 回调函数,必须
  1889. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1890. * @return {Object} data 返回的数据
  1891. * @return {Object} data.AccessControlPolicy 权限列表
  1892. */
  1893. function getObjectAcl(params, callback) {
  1894. submitRequest.call(this, {
  1895. Action: 'name/cos:GetObjectACL',
  1896. method: 'GET',
  1897. Bucket: params.Bucket,
  1898. Region: params.Region,
  1899. Key: params.Key,
  1900. headers: params.Headers,
  1901. action: 'acl',
  1902. }, function (err, data) {
  1903. if (err) return callback(err);
  1904. var AccessControlPolicy = data.AccessControlPolicy || {};
  1905. var Owner = AccessControlPolicy.Owner || {};
  1906. var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || [];
  1907. Grant = util.isArray(Grant) ? Grant : [Grant];
  1908. var result = decodeAcl(AccessControlPolicy);
  1909. delete result.GrantWrite;
  1910. if (data.headers && data.headers['x-cos-acl']) {
  1911. result.ACL = data.headers['x-cos-acl'];
  1912. }
  1913. result = util.extend(result, {
  1914. Owner: Owner,
  1915. Grants: Grant,
  1916. statusCode: data.statusCode,
  1917. headers: data.headers,
  1918. });
  1919. callback(null, result);
  1920. });
  1921. }
  1922. /**
  1923. * 设置 object 的 权限列表
  1924. * @param {Object} params 参数对象,必须
  1925. * @param {String} params.Bucket Bucket名称,必须
  1926. * @param {String} params.Region 地域名称,必须
  1927. * @param {String} params.Key object名称,必须
  1928. * @param {Function} callback 回调函数,必须
  1929. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1930. * @return {Object} data 返回的数据
  1931. */
  1932. function putObjectAcl(params, callback) {
  1933. var headers = params.Headers;
  1934. var xml = '';
  1935. if (params['AccessControlPolicy']) {
  1936. var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {});
  1937. var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant;
  1938. Grants = util.isArray(Grants) ? Grants : [Grants];
  1939. delete AccessControlPolicy.Grant;
  1940. delete AccessControlPolicy.Grants;
  1941. AccessControlPolicy.AccessControlList = {Grant: Grants};
  1942. xml = util.json2xml({AccessControlPolicy: AccessControlPolicy});
  1943. headers['Content-Type'] = 'application/xml';
  1944. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  1945. }
  1946. // Grant Header 去重
  1947. util.each(headers, function (val, key) {
  1948. if (key.indexOf('x-cos-grant-') === 0) {
  1949. headers[key] = uniqGrant(headers[key]);
  1950. }
  1951. });
  1952. submitRequest.call(this, {
  1953. Action: 'name/cos:PutObjectACL',
  1954. method: 'PUT',
  1955. Bucket: params.Bucket,
  1956. Region: params.Region,
  1957. Key: params.Key,
  1958. action: 'acl',
  1959. headers: headers,
  1960. body: xml,
  1961. }, function (err, data) {
  1962. if (err) return callback(err);
  1963. callback(null, {
  1964. statusCode: data.statusCode,
  1965. headers: data.headers,
  1966. });
  1967. });
  1968. }
  1969. /**
  1970. * Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。
  1971. * @param {Object} params 参数对象,必须
  1972. * @param {String} params.Bucket Bucket名称,必须
  1973. * @param {String} params.Region 地域名称,必须
  1974. * @param {String} params.Key object名称,必须
  1975. * @param {Function} callback 回调函数,必须
  1976. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  1977. * @return {Object} data 返回的数据
  1978. */
  1979. function optionsObject(params, callback) {
  1980. var headers = params.Headers;
  1981. headers['Origin'] = params['Origin'];
  1982. headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod'];
  1983. headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders'];
  1984. submitRequest.call(this, {
  1985. Action: 'name/cos:OptionsObject',
  1986. method: 'OPTIONS',
  1987. Bucket: params.Bucket,
  1988. Region: params.Region,
  1989. Key: params.Key,
  1990. headers: headers,
  1991. }, function (err, data) {
  1992. if (err) {
  1993. if (err.statusCode && err.statusCode === 403) {
  1994. return callback(null, {
  1995. OptionsForbidden: true,
  1996. statusCode: err.statusCode
  1997. });
  1998. }
  1999. return callback(err);
  2000. }
  2001. var headers = data.headers || {};
  2002. callback(null, {
  2003. AccessControlAllowOrigin: headers['access-control-allow-origin'],
  2004. AccessControlAllowMethods: headers['access-control-allow-methods'],
  2005. AccessControlAllowHeaders: headers['access-control-allow-headers'],
  2006. AccessControlExposeHeaders: headers['access-control-expose-headers'],
  2007. AccessControlMaxAge: headers['access-control-max-age'],
  2008. statusCode: data.statusCode,
  2009. headers: data.headers,
  2010. });
  2011. });
  2012. }
  2013. /**
  2014. * @param {Object} 参数列表
  2015. * @param {String} Bucket Bucket 名称
  2016. * @param {String} Region 地域名称
  2017. * @param {String} Key 文件名称
  2018. * @param {String} CopySource 源文件URL绝对路径,可以通过versionid子资源指定历史版本
  2019. * @param {String} ACL 允许用户自定义文件权限。有效值:private,public-read默认值:private。
  2020. * @param {String} GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。
  2021. * @param {String} GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。
  2022. * @param {String} GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。
  2023. * @param {String} MetadataDirective 是否拷贝元数据,枚举值:Copy, Replaced,默认值Copy。假如标记为Copy,忽略Header中的用户元数据信息直接复制;假如标记为Replaced,按Header信息修改元数据。当目标路径和原路径一致,即用户试图修改元数据时,必须为Replaced
  2024. * @param {String} CopySourceIfModifiedSince 当Object在指定时间后被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-None-Match一起使用,与其他条件联合使用返回冲突。
  2025. * @param {String} CopySourceIfUnmodifiedSince 当Object在指定时间后未被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-Match一起使用,与其他条件联合使用返回冲突。
  2026. * @param {String} CopySourceIfMatch 当Object的ETag和给定一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Unmodified-Since一起使用,与其他条件联合使用返回冲突。
  2027. * @param {String} CopySourceIfNoneMatch 当Object的ETag和给定不一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Modified-Since一起使用,与其他条件联合使用返回冲突。
  2028. * @param {String} StorageClass 存储级别,枚举值:存储级别,枚举值:Standard, Standard_IA,Archive;默认值:Standard
  2029. * @param {String} CacheControl 指定所有缓存机制在整个请求/响应链中必须服从的指令。
  2030. * @param {String} ContentDisposition MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件
  2031. * @param {String} ContentEncoding HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段
  2032. * @param {String} ContentLength 设置响应消息的实体内容的大小,单位为字节
  2033. * @param {String} ContentType RFC 2616 中定义的 HTTP 请求内容类型(MIME),例如text/plain
  2034. * @param {String} Expect 请求的特定的服务器行为
  2035. * @param {String} Expires 响应过期的日期和时间
  2036. * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
  2037. * @param {String} ContentLanguage 指定内容语言
  2038. * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。
  2039. */
  2040. function putObjectCopy(params, callback) {
  2041. // 特殊处理 Cache-Control
  2042. var self = this;
  2043. var headers = params.Headers;
  2044. if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
  2045. var CopySource = params.CopySource || '';
  2046. var m = util.getSourceParams.call(this, CopySource);
  2047. if (!m) {
  2048. callback(util.error(new Error('CopySource format error')));
  2049. return;
  2050. }
  2051. var SourceBucket = m[1];
  2052. var SourceRegion = m[3];
  2053. var SourceKey = decodeURIComponent(m[4]);
  2054. submitRequest.call(this, {
  2055. Scope: [{
  2056. action: 'name/cos:GetObject',
  2057. bucket: SourceBucket,
  2058. region: SourceRegion,
  2059. prefix: SourceKey,
  2060. }, {
  2061. action: 'name/cos:PutObject',
  2062. bucket: params.Bucket,
  2063. region: params.Region,
  2064. prefix: params.Key,
  2065. }],
  2066. method: 'PUT',
  2067. Bucket: params.Bucket,
  2068. Region: params.Region,
  2069. Key: params.Key,
  2070. VersionId: params.VersionId,
  2071. headers: params.Headers,
  2072. }, function (err, data) {
  2073. if (err) return callback(err);
  2074. var result = util.clone(data.CopyObjectResult || {});
  2075. var url = getUrl({
  2076. ForcePathStyle: self.options.ForcePathStyle,
  2077. protocol: self.options.Protocol,
  2078. domain: self.options.Domain,
  2079. bucket: params.Bucket,
  2080. region: params.Region,
  2081. object: params.Key,
  2082. isLocation: true,
  2083. });
  2084. util.extend(result, {
  2085. Location: url,
  2086. statusCode: data.statusCode,
  2087. headers: data.headers,
  2088. });
  2089. callback(null, result);
  2090. });
  2091. }
  2092. function uploadPartCopy(params, callback) {
  2093. var CopySource = params.CopySource || '';
  2094. var m = util.getSourceParams.call(this, CopySource);
  2095. if (!m) {
  2096. callback(util.error(new Error('CopySource format error')));
  2097. return;
  2098. }
  2099. var SourceBucket = m[1];
  2100. var SourceRegion = m[3];
  2101. var SourceKey = decodeURIComponent(m[4]);
  2102. submitRequest.call(this, {
  2103. Scope: [{
  2104. action: 'name/cos:GetObject',
  2105. bucket: SourceBucket,
  2106. region: SourceRegion,
  2107. prefix: SourceKey,
  2108. }, {
  2109. action: 'name/cos:PutObject',
  2110. bucket: params.Bucket,
  2111. region: params.Region,
  2112. prefix: params.Key,
  2113. }],
  2114. method: 'PUT',
  2115. Bucket: params.Bucket,
  2116. Region: params.Region,
  2117. Key: params.Key,
  2118. VersionId: params.VersionId,
  2119. qs: {
  2120. partNumber: params['PartNumber'],
  2121. uploadId: params['UploadId'],
  2122. },
  2123. headers: params.Headers,
  2124. }, function (err, data) {
  2125. if (err) return callback(err);
  2126. var result = util.clone(data.CopyPartResult || {});
  2127. util.extend(result, {
  2128. statusCode: data.statusCode,
  2129. headers: data.headers,
  2130. });
  2131. callback(null, result);
  2132. });
  2133. }
  2134. function deleteMultipleObject(params, callback) {
  2135. var Objects = params.Objects || [];
  2136. var Quiet = params.Quiet;
  2137. Objects = util.isArray(Objects) ? Objects : [Objects];
  2138. var xml = util.json2xml({Delete: {Object: Objects, Quiet: Quiet || false}});
  2139. var headers = params.Headers;
  2140. headers['Content-Type'] = 'application/xml';
  2141. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  2142. var Scope = util.map(Objects, function (v) {
  2143. return {
  2144. action: 'name/cos:DeleteObject',
  2145. bucket: params.Bucket,
  2146. region: params.Region,
  2147. prefix: v.Key,
  2148. };
  2149. });
  2150. submitRequest.call(this, {
  2151. Scope: Scope,
  2152. method: 'POST',
  2153. Bucket: params.Bucket,
  2154. Region: params.Region,
  2155. body: xml,
  2156. action: 'delete',
  2157. headers: headers,
  2158. }, function (err, data) {
  2159. if (err) return callback(err);
  2160. var DeleteResult = data.DeleteResult || {};
  2161. var Deleted = DeleteResult.Deleted || [];
  2162. var Errors = DeleteResult.Error || [];
  2163. Deleted = util.isArray(Deleted) ? Deleted : [Deleted];
  2164. Errors = util.isArray(Errors) ? Errors : [Errors];
  2165. var result = util.clone(DeleteResult);
  2166. util.extend(result, {
  2167. Error: Errors,
  2168. Deleted: Deleted,
  2169. statusCode: data.statusCode,
  2170. headers: data.headers,
  2171. });
  2172. callback(null, result);
  2173. });
  2174. }
  2175. function restoreObject(params, callback) {
  2176. var headers = params.Headers;
  2177. if (!params['RestoreRequest']) {
  2178. callback(util.error(new Error('missing param RestoreRequest')));
  2179. return;
  2180. }
  2181. var RestoreRequest = params.RestoreRequest || {};
  2182. var xml = util.json2xml({RestoreRequest: RestoreRequest});
  2183. headers['Content-Type'] = 'application/xml';
  2184. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  2185. submitRequest.call(this, {
  2186. Action: 'name/cos:RestoreObject',
  2187. method: 'POST',
  2188. Bucket: params.Bucket,
  2189. Region: params.Region,
  2190. Key: params.Key,
  2191. VersionId: params.VersionId,
  2192. body: xml,
  2193. action: 'restore',
  2194. headers: headers,
  2195. }, callback);
  2196. }
  2197. /**
  2198. * 设置 Object 的标签
  2199. * @param {Object} params 参数对象,必须
  2200. * @param {String} params.Bucket Object名称,必须
  2201. * @param {String} params.Region 地域名称,必须
  2202. * @param {Array} params.TagSet 标签设置,必须
  2203. * @param {Function} callback 回调函数,必须
  2204. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
  2205. * @return {Object} data 返回数据
  2206. */
  2207. function putObjectTagging(params, callback) {
  2208. var Tagging = params['Tagging'] || {};
  2209. var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || [];
  2210. Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
  2211. var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}});
  2212. var headers = params.Headers;
  2213. headers['Content-Type'] = 'application/xml';
  2214. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  2215. submitRequest.call(this, {
  2216. Action: 'name/cos:PutObjectTagging',
  2217. method: 'PUT',
  2218. Bucket: params.Bucket,
  2219. Key: params.Key,
  2220. Region: params.Region,
  2221. body: xml,
  2222. action: 'tagging',
  2223. headers: headers,
  2224. VersionId: params.VersionId,
  2225. }, function (err, data) {
  2226. if (err && err.statusCode === 204) {
  2227. return callback(null, {statusCode: err.statusCode});
  2228. } else if (err) {
  2229. return callback(err);
  2230. }
  2231. callback(null, {
  2232. statusCode: data.statusCode,
  2233. headers: data.headers,
  2234. });
  2235. });
  2236. }
  2237. /**
  2238. * 获取 Object 的标签设置
  2239. * @param {Object} params 参数对象,必须
  2240. * @param {String} params.Bucket Bucket名称,必须
  2241. * @param {String} params.Region 地域名称,必须
  2242. * @param {Function} callback 回调函数,必须
  2243. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
  2244. * @return {Object} data 返回数据
  2245. */
  2246. function getObjectTagging(params, callback) {
  2247. submitRequest.call(this, {
  2248. Action: 'name/cos:GetObjectTagging',
  2249. method: 'GET',
  2250. Key: params.Key,
  2251. Bucket: params.Bucket,
  2252. Region: params.Region,
  2253. headers: params.Headers,
  2254. action: 'tagging',
  2255. VersionId: params.VersionId,
  2256. }, function (err, data) {
  2257. if (err) {
  2258. if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) {
  2259. var result = {
  2260. Tags: [],
  2261. statusCode: err.statusCode,
  2262. };
  2263. err.headers && (result.headers = err.headers);
  2264. callback(null, result);
  2265. } else {
  2266. callback(err);
  2267. }
  2268. return;
  2269. }
  2270. var Tags = [];
  2271. try {
  2272. Tags = data.Tagging.TagSet.Tag || [];
  2273. } catch (e) {
  2274. }
  2275. Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
  2276. callback(null, {
  2277. Tags: Tags,
  2278. statusCode: data.statusCode,
  2279. headers: data.headers,
  2280. });
  2281. });
  2282. }
  2283. /**
  2284. * 删除 Object 的 标签设置
  2285. * @param {Object} params 参数对象,必须
  2286. * @param {String} params.Bucket Object名称,必须
  2287. * @param {String} params.Region 地域名称,必须
  2288. * @param {Function} callback 回调函数,必须
  2289. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
  2290. * @return {Object} data 返回的数据
  2291. */
  2292. function deleteObjectTagging(params, callback) {
  2293. submitRequest.call(this, {
  2294. Action: 'name/cos:DeleteObjectTagging',
  2295. method: 'DELETE',
  2296. Bucket: params.Bucket,
  2297. Region: params.Region,
  2298. Key: params.Key,
  2299. headers: params.Headers,
  2300. action: 'tagging',
  2301. VersionId: params.VersionId,
  2302. }, function (err, data) {
  2303. if (err && err.statusCode === 204) {
  2304. return callback(null, {statusCode: err.statusCode});
  2305. } else if (err) {
  2306. return callback(err);
  2307. }
  2308. callback(null, {
  2309. statusCode: data.statusCode,
  2310. headers: data.headers,
  2311. });
  2312. });
  2313. }
  2314. /**
  2315. * 使用 SQL 语句从指定对象(CSV 格式或者 JSON 格式)中检索内容
  2316. * @param {Object} params 参数对象,必须
  2317. * @param {String} params.Bucket Object名称,必须
  2318. * @param {String} params.Region 地域名称,必须
  2319. * @param {Object} params.SelectRequest 地域名称,必须
  2320. * @param {Function} callback 回调函数,必须
  2321. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
  2322. * @return {Object} data 返回的数据
  2323. */
  2324. function selectObjectContent(params, callback) {
  2325. var SelectType = params['SelectType'];
  2326. if (!SelectType) return callback(util.error(new Error('missing param SelectType')));
  2327. var SelectRequest = params['SelectRequest'] || {};
  2328. var xml = util.json2xml({SelectRequest: SelectRequest});
  2329. var headers = params.Headers;
  2330. headers['Content-Type'] = 'application/xml';
  2331. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  2332. submitRequest.call(this, {
  2333. Action: 'name/cos:GetObject',
  2334. method: 'POST',
  2335. Bucket: params.Bucket,
  2336. Region: params.Region,
  2337. Key: params.Key,
  2338. headers: params.Headers,
  2339. action: 'select',
  2340. qs: {
  2341. 'select-type': params['SelectType'],
  2342. },
  2343. VersionId: params.VersionId,
  2344. body: xml,
  2345. DataType: 'arraybuffer',
  2346. rawBody: true,
  2347. }, function (err, data) {
  2348. if (err && err.statusCode === 204) {
  2349. return callback(null, {statusCode: err.statusCode});
  2350. } else if (err) {
  2351. return callback(err);
  2352. }
  2353. var result = util.parseSelectPayload(data.body);
  2354. callback(null, {
  2355. statusCode: data.statusCode,
  2356. headers: data.headers,
  2357. Body: result.body,
  2358. Payload: result.payload,
  2359. });
  2360. });
  2361. }
  2362. // 分块上传
  2363. /**
  2364. * 初始化分块上传
  2365. * @param {Object} params 参数对象,必须
  2366. * @param {String} params.Bucket Bucket名称,必须
  2367. * @param {String} params.Region 地域名称,必须
  2368. * @param {String} params.Key object名称,必须
  2369. * @param {String} params.UploadId object名称,必须
  2370. * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须
  2371. * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存 ,非必须
  2372. * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须
  2373. * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须
  2374. * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须
  2375. * @param {String} params.ACL 允许用户自定义文件权限,非必须
  2376. * @param {String} params.GrantRead 赋予被授权者读的权限 ,非必须
  2377. * @param {String} params.GrantWrite 赋予被授权者写的权限 ,非必须
  2378. * @param {String} params.GrantFullControl 赋予被授权者读写权限 ,非必须
  2379. * @param {String} params.StorageClass 设置Object的存储级别,枚举值:Standard,Standard_IA,Archive,非必须
  2380. * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
  2381. * @param {Function} callback 回调函数,必须
  2382. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2383. * @return {Object} data 返回的数据
  2384. */
  2385. function multipartInit(params, callback) {
  2386. var self = this;
  2387. // 特殊处理 Cache-Control
  2388. var headers = params.Headers;
  2389. // 特殊处理 Cache-Control、Content-Type
  2390. if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
  2391. if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = params.Body && params.Body.type || '';
  2392. util.getBodyMd5(params.Body && (params.UploadAddMetaMd5 || self.options.UploadAddMetaMd5), params.Body, function (md5) {
  2393. if (md5) params.Headers['x-cos-meta-md5'] = md5;
  2394. submitRequest.call(self, {
  2395. Action: 'name/cos:InitiateMultipartUpload',
  2396. method: 'POST',
  2397. Bucket: params.Bucket,
  2398. Region: params.Region,
  2399. Key: params.Key,
  2400. action: 'uploads',
  2401. headers: params.Headers,
  2402. qs: params.Query,
  2403. }, function (err, data) {
  2404. if (err) return callback(err);
  2405. data = util.clone(data || {});
  2406. if (data && data.InitiateMultipartUploadResult) {
  2407. return callback(null, util.extend(data.InitiateMultipartUploadResult, {
  2408. statusCode: data.statusCode,
  2409. headers: data.headers,
  2410. }));
  2411. }
  2412. callback(null, data);
  2413. });
  2414. }, params.onHashProgress);
  2415. }
  2416. /**
  2417. * 分块上传
  2418. * @param {Object} params 参数对象,必须
  2419. * @param {String} params.Bucket Bucket名称,必须
  2420. * @param {String} params.Region 地域名称,必须
  2421. * @param {String} params.Key object名称,必须
  2422. * @param {File || Blob || String} params.Body 上传文件对象或字符串
  2423. * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),非必须
  2424. * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须
  2425. * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
  2426. * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验值,非必须
  2427. * @param {Function} callback 回调函数,必须
  2428. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2429. * @return {Object} data 返回的数据
  2430. * @return {Object} data.ETag 返回的文件分块 sha1 值
  2431. */
  2432. function multipartUpload(params, callback) {
  2433. var self = this;
  2434. util.getFileSize('multipartUpload', params, function () {
  2435. util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) {
  2436. if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5);
  2437. submitRequest.call(self, {
  2438. Action: 'name/cos:UploadPart',
  2439. TaskId: params.TaskId,
  2440. method: 'PUT',
  2441. Bucket: params.Bucket,
  2442. Region: params.Region,
  2443. Key: params.Key,
  2444. qs: {
  2445. partNumber: params['PartNumber'],
  2446. uploadId: params['UploadId'],
  2447. },
  2448. headers: params.Headers,
  2449. onProgress: params.onProgress,
  2450. body: params.Body || null
  2451. }, function (err, data) {
  2452. if (err) return callback(err);
  2453. callback(null, {
  2454. ETag: util.attr(data.headers, 'etag', ''),
  2455. statusCode: data.statusCode,
  2456. headers: data.headers,
  2457. });
  2458. });
  2459. });
  2460. });
  2461. }
  2462. /**
  2463. * 完成分块上传
  2464. * @param {Object} params 参数对象,必须
  2465. * @param {String} params.Bucket Bucket名称,必须
  2466. * @param {String} params.Region 地域名称,必须
  2467. * @param {String} params.Key object名称,必须
  2468. * @param {Array} params.Parts 分块信息列表,必须
  2469. * @param {String} params.Parts[i].PartNumber 块编号,必须
  2470. * @param {String} params.Parts[i].ETag 分块的 sha1 校验值
  2471. * @param {Function} callback 回调函数,必须
  2472. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2473. * @return {Object} data 返回的数据
  2474. * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag
  2475. */
  2476. function multipartComplete(params, callback) {
  2477. var self = this;
  2478. var UploadId = params.UploadId;
  2479. var Parts = params['Parts'];
  2480. for (var i = 0, len = Parts.length; i < len; i++) {
  2481. if (Parts[i]['ETag'] && Parts[i]['ETag'].indexOf('"') === 0) {
  2482. continue;
  2483. }
  2484. Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"';
  2485. }
  2486. var xml = util.json2xml({CompleteMultipartUpload: {Part: Parts}});
  2487. // CSP/ceph CompleteMultipartUpload 接口 body 写死了限制 1MB,这里醉倒 10000 片时,xml 字符串去掉空格853KB
  2488. xml = xml.replace(/\n\s*/g, '');
  2489. var headers = params.Headers;
  2490. headers['Content-Type'] = 'application/xml';
  2491. headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
  2492. submitRequest.call(this, {
  2493. Action: 'name/cos:CompleteMultipartUpload',
  2494. method: 'POST',
  2495. Bucket: params.Bucket,
  2496. Region: params.Region,
  2497. Key: params.Key,
  2498. qs: {
  2499. uploadId: UploadId
  2500. },
  2501. body: xml,
  2502. headers: headers,
  2503. }, function (err, data) {
  2504. if (err) return callback(err);
  2505. var url = getUrl({
  2506. ForcePathStyle: self.options.ForcePathStyle,
  2507. protocol: self.options.Protocol,
  2508. domain: self.options.Domain,
  2509. bucket: params.Bucket,
  2510. region: params.Region,
  2511. object: params.Key,
  2512. isLocation: true,
  2513. });
  2514. var res = data.CompleteMultipartUploadResult || {};
  2515. if (res.ProcessResults) {
  2516. if (res && res.ProcessResults) {
  2517. res.UploadResult = {
  2518. OriginalInfo: {
  2519. Key: res.Key,
  2520. Location: url,
  2521. ETag: res.ETag,
  2522. ImageInfo: res.ImageInfo,
  2523. },
  2524. ProcessResults: res.ProcessResults,
  2525. };
  2526. delete res.ImageInfo;
  2527. delete res.ProcessResults;
  2528. }
  2529. }
  2530. var result = util.extend(res, {
  2531. Location: url,
  2532. statusCode: data.statusCode,
  2533. headers: data.headers,
  2534. });
  2535. callback(null, result);
  2536. });
  2537. }
  2538. /**
  2539. * 分块上传任务列表查询
  2540. * @param {Object} params 参数对象,必须
  2541. * @param {String} params.Bucket Bucket名称,必须
  2542. * @param {String} params.Region 地域名称,必须
  2543. * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,定义为Common Prefix,然后列出所有Common Prefix。如果没有Prefix,则从路径起点开始,非必须
  2544. * @param {String} params.EncodingType 规定返回值的编码方式,非必须
  2545. * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须
  2546. * @param {String} params.MaxUploads 单次返回最大的条目数量,默认1000,非必须
  2547. * @param {String} params.KeyMarker 与upload-id-marker一起使用 </Br>当upload-id-marker未被指定时,ObjectName字母顺序大于key-marker的条目将被列出 </Br>当upload-id-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须
  2548. * @param {String} params.UploadIdMarker 与key-marker一起使用 </Br>当key-marker未被指定时,upload-id-marker将被忽略 </Br>当key-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须
  2549. * @param {Function} callback 回调函数,必须
  2550. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2551. * @return {Object} data 返回的数据
  2552. * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息
  2553. */
  2554. function multipartList(params, callback) {
  2555. var reqParams = {};
  2556. reqParams['delimiter'] = params['Delimiter'];
  2557. reqParams['encoding-type'] = params['EncodingType'];
  2558. reqParams['prefix'] = params['Prefix'] || '';
  2559. reqParams['max-uploads'] = params['MaxUploads'];
  2560. reqParams['key-marker'] = params['KeyMarker'];
  2561. reqParams['upload-id-marker'] = params['UploadIdMarker'];
  2562. reqParams = util.clearKey(reqParams);
  2563. submitRequest.call(this, {
  2564. Action: 'name/cos:ListMultipartUploads',
  2565. ResourceKey: reqParams['prefix'],
  2566. method: 'GET',
  2567. Bucket: params.Bucket,
  2568. Region: params.Region,
  2569. headers: params.Headers,
  2570. qs: reqParams,
  2571. action: 'uploads',
  2572. }, function (err, data) {
  2573. if (err) return callback(err);
  2574. if (data && data.ListMultipartUploadsResult) {
  2575. var Upload = data.ListMultipartUploadsResult.Upload || [];
  2576. Upload = util.isArray(Upload) ? Upload : [Upload];
  2577. data.ListMultipartUploadsResult.Upload = Upload;
  2578. }
  2579. var result = util.clone(data.ListMultipartUploadsResult || {});
  2580. util.extend(result, {
  2581. statusCode: data.statusCode,
  2582. headers: data.headers,
  2583. });
  2584. callback(null, result);
  2585. });
  2586. }
  2587. /**
  2588. * 上传的分块列表查询
  2589. * @param {Object} params 参数对象,必须
  2590. * @param {String} params.Bucket Bucket名称,必须
  2591. * @param {String} params.Region 地域名称,必须
  2592. * @param {String} params.Key object名称,必须
  2593. * @param {String} params.UploadId 标示本次分块上传的ID,必须
  2594. * @param {String} params.EncodingType 规定返回值的编码方式,非必须
  2595. * @param {String} params.MaxParts 单次返回最大的条目数量,默认1000,非必须
  2596. * @param {String} params.PartNumberMarker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须
  2597. * @param {Function} callback 回调函数,必须
  2598. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2599. * @return {Object} data 返回的数据
  2600. * @return {Object} data.ListMultipartUploadsResult 分块信息
  2601. */
  2602. function multipartListPart(params, callback) {
  2603. var reqParams = {};
  2604. reqParams['uploadId'] = params['UploadId'];
  2605. reqParams['encoding-type'] = params['EncodingType'];
  2606. reqParams['max-parts'] = params['MaxParts'];
  2607. reqParams['part-number-marker'] = params['PartNumberMarker'];
  2608. submitRequest.call(this, {
  2609. Action: 'name/cos:ListParts',
  2610. method: 'GET',
  2611. Bucket: params.Bucket,
  2612. Region: params.Region,
  2613. Key: params.Key,
  2614. headers: params.Headers,
  2615. qs: reqParams,
  2616. }, function (err, data) {
  2617. if (err) return callback(err);
  2618. var ListPartsResult = data.ListPartsResult || {};
  2619. var Part = ListPartsResult.Part || [];
  2620. Part = util.isArray(Part) ? Part : [Part];
  2621. ListPartsResult.Part = Part;
  2622. var result = util.clone(ListPartsResult);
  2623. util.extend(result, {
  2624. statusCode: data.statusCode,
  2625. headers: data.headers,
  2626. });
  2627. callback(null, result);
  2628. });
  2629. }
  2630. /**
  2631. * 抛弃分块上传
  2632. * @param {Object} params 参数对象,必须
  2633. * @param {String} params.Bucket Bucket名称,必须
  2634. * @param {String} params.Region 地域名称,必须
  2635. * @param {String} params.Key object名称,必须
  2636. * @param {String} params.UploadId 标示本次分块上传的ID,必须
  2637. * @param {Function} callback 回调函数,必须
  2638. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2639. * @return {Object} data 返回的数据
  2640. */
  2641. function multipartAbort(params, callback) {
  2642. var reqParams = {};
  2643. reqParams['uploadId'] = params['UploadId'];
  2644. submitRequest.call(this, {
  2645. Action: 'name/cos:AbortMultipartUpload',
  2646. method: 'DELETE',
  2647. Bucket: params.Bucket,
  2648. Region: params.Region,
  2649. Key: params.Key,
  2650. headers: params.Headers,
  2651. qs: reqParams,
  2652. }, function (err, data) {
  2653. if (err) return callback(err);
  2654. callback(null, {
  2655. statusCode: data.statusCode,
  2656. headers: data.headers,
  2657. });
  2658. });
  2659. }
  2660. /**
  2661. * 抛弃分块上传
  2662. * @param {Object} params 参数对象,必须
  2663. * @param {String} params.Bucket Bucket名称,必须
  2664. * @param {String} params.Region 地域名称,必须
  2665. * @param {String} params.Key object名称,必须
  2666. * @param {String} params.UploadId 标示本次分块上传的ID,必须
  2667. * @param {Function} callback 回调函数,必须
  2668. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2669. * @return {Object} data 返回的数据
  2670. */
  2671. function request(params, callback) {
  2672. submitRequest.call(this, {
  2673. method: params.Method,
  2674. Bucket: params.Bucket,
  2675. Region: params.Region,
  2676. Key: params.Key,
  2677. action: params.Action,
  2678. headers: params.Headers,
  2679. qs: params.Query,
  2680. body: params.Body,
  2681. Url: params.Url,
  2682. rawBody: params.RawBody,
  2683. DataType: params.DataType,
  2684. }, function (err, data) {
  2685. if (err) return callback(err);
  2686. if (data && data.body) {
  2687. data.Body = data.body;
  2688. delete data.body;
  2689. }
  2690. callback(err, data);
  2691. });
  2692. }
  2693. /**
  2694. * 追加上传
  2695. * @param {Object} params 参数对象,必须
  2696. * @param {String} params.Bucket Bucket名称,必须
  2697. * @param {String} params.Region 地域名称,必须
  2698. * @param {String} params.Key object名称,必须
  2699. * @param {File || Blob || String} params.Body 上传文件对象或字符串
  2700. * @param {Number} params.Position 追加操作的起始点,单位为字节,必须
  2701. * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须
  2702. * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须
  2703. * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须
  2704. * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须
  2705. * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须
  2706. * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须
  2707. * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须
  2708. * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须
  2709. * @param {String} params.GrantRead 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  2710. * @param {String} params.GrantReadAcp 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  2711. * @param {String} params.GrantWriteAcp 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  2712. * @param {String} params.GrantFullControl 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
  2713. * @param {String} params.StorageClass 设置对象的存储级别,枚举值:STANDARD、STANDARD_IA、ARCHIVE,默认值:STANDARD,非必须
  2714. * @param {String} params.x-cos-meta-* 允许用户自定义的头部信息,将作为对象的元数据保存。大小限制2KB,非必须
  2715. * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须
  2716. * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
  2717. * @param {Function} callback 回调函数,必须
  2718. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2719. * @return {Object} data 返回的数据
  2720. */
  2721. function appendObject(params, callback) {
  2722. // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里
  2723. var headers = params.Headers;
  2724. if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
  2725. if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = params.Body && params.Body.type || '';
  2726. submitRequest.call(this, {
  2727. Action: 'name/cos:AppendObject',
  2728. method: 'POST',
  2729. Bucket: params.Bucket,
  2730. Region: params.Region,
  2731. action: 'append',
  2732. Key: params.Key,
  2733. body: params.Body,
  2734. qs: {
  2735. position: params.Position
  2736. },
  2737. headers: params.Headers,
  2738. }, function (err, data) {
  2739. if (err) return callback(err);
  2740. callback(null, data);
  2741. });
  2742. }
  2743. /**
  2744. * 获取签名
  2745. * @param {Object} params 参数对象,必须
  2746. * @param {String} params.Method 请求方法,必须
  2747. * @param {String} params.Key object名称,必须
  2748. * @param {String} params.Expires 名超时时间,单位秒,可选
  2749. * @return {String} data 返回签名字符串
  2750. */
  2751. function getAuth(params) {
  2752. var self = this;
  2753. return util.getAuth({
  2754. SecretId: params.SecretId || this.options.SecretId || '',
  2755. SecretKey: params.SecretKey || this.options.SecretKey || '',
  2756. Bucket: params.Bucket,
  2757. Region: params.Region,
  2758. Method: params.Method,
  2759. Key: params.Key,
  2760. Query: params.Query,
  2761. Headers: params.Headers,
  2762. Expires: params.Expires,
  2763. UseRawKey: self.options.UseRawKey,
  2764. SystemClockOffset: self.options.SystemClockOffset,
  2765. });
  2766. }
  2767. /**
  2768. * 获取文件下载链接
  2769. * @param {Object} params 参数对象,必须
  2770. * @param {String} params.Bucket Bucket名称,必须
  2771. * @param {String} params.Region 地域名称,必须
  2772. * @param {String} params.Key object名称,必须
  2773. * @param {String} params.Method 请求的方法,可选
  2774. * @param {String} params.Expires 签名超时时间,单位秒,可选
  2775. * @param {Function} callback 回调函数,必须
  2776. * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
  2777. * @return {Object} data 返回的数据
  2778. */
  2779. function getObjectUrl(params, callback) {
  2780. var self = this;
  2781. var useAccelerate = params.UseAccelerate === undefined ? self.options.UseAccelerate : params.UseAccelerate;
  2782. var url = getUrl({
  2783. ForcePathStyle: self.options.ForcePathStyle,
  2784. protocol: params.Protocol || self.options.Protocol,
  2785. domain: params.Domain || self.options.Domain,
  2786. bucket: params.Bucket,
  2787. region: useAccelerate ? 'accelerate' : params.Region,
  2788. object: params.Key,
  2789. });
  2790. var queryParamsStr = '';
  2791. if(params.Query){
  2792. queryParamsStr += util.obj2str(params.Query);
  2793. }
  2794. if(params.QueryString){
  2795. queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString;
  2796. }
  2797. var syncUrl = url;
  2798. if (params.Sign !== undefined && !params.Sign) {
  2799. queryParamsStr && (syncUrl += '?' + queryParamsStr);
  2800. callback(null, {Url: syncUrl});
  2801. return syncUrl;
  2802. }
  2803. // 签名加上 Host,避免跨桶访问
  2804. var SignHost = getSignHost.call(this, {Bucket: params.Bucket, Region: params.Region, UseAccelerate: params.UseAccelerate, Url: url});
  2805. var AuthData = getAuthorizationAsync.call(this, {
  2806. Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'),
  2807. Bucket: params.Bucket || '',
  2808. Region: params.Region || '',
  2809. Method: params.Method || 'get',
  2810. Key: params.Key,
  2811. Expires: params.Expires,
  2812. Headers: params.Headers,
  2813. Query: params.Query,
  2814. SignHost: SignHost,
  2815. ForceSignHost: params.ForceSignHost === false ? false : self.options.ForceSignHost, // getObjectUrl支持传参ForceSignHost
  2816. }, function (err, AuthData) {
  2817. if (!callback) return;
  2818. if (err) {
  2819. callback(err);
  2820. return;
  2821. }
  2822. // 兼容万象url qUrlParamList需要再encode一次
  2823. var replaceUrlParamList = function(url) {
  2824. var urlParams = url.match(/q-url-param-list.*?(?=&)/g)[0];
  2825. var encodedParams = 'q-url-param-list=' + encodeURIComponent(urlParams.replace(/q-url-param-list=/, '')).toLowerCase();
  2826. var reg = new RegExp(urlParams, 'g');
  2827. var replacedUrl = url.replace(reg, encodedParams);
  2828. return replacedUrl;
  2829. }
  2830. var signUrl = url;
  2831. signUrl += '?' + (AuthData.Authorization.indexOf('q-signature') > -1 ?
  2832. replaceUrlParamList(AuthData.Authorization) : 'sign=' + encodeURIComponent(AuthData.Authorization));
  2833. AuthData.SecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.SecurityToken);
  2834. AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP);
  2835. AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA);
  2836. AuthData.Token && (signUrl += '&token=' + AuthData.Token);
  2837. queryParamsStr && (signUrl += '&' + queryParamsStr);
  2838. setTimeout(function () {
  2839. callback(null, {Url: signUrl});
  2840. });
  2841. });
  2842. if (AuthData) {
  2843. syncUrl += '?' + AuthData.Authorization +
  2844. (AuthData.SecurityToken ? '&x-cos-security-token=' + AuthData.SecurityToken : '');
  2845. queryParamsStr && (syncUrl += '&' + queryParamsStr);
  2846. } else{
  2847. queryParamsStr && (syncUrl += '?' + queryParamsStr);
  2848. }
  2849. return syncUrl;
  2850. }
  2851. /**
  2852. * 私有方法
  2853. */
  2854. function decodeAcl(AccessControlPolicy) {
  2855. var result = {
  2856. GrantFullControl: [],
  2857. GrantWrite: [],
  2858. GrantRead: [],
  2859. GrantReadAcp: [],
  2860. GrantWriteAcp: [],
  2861. ACL: '',
  2862. };
  2863. var GrantMap = {
  2864. 'FULL_CONTROL': 'GrantFullControl',
  2865. 'WRITE': 'GrantWrite',
  2866. 'READ': 'GrantRead',
  2867. 'READ_ACP': 'GrantReadAcp',
  2868. 'WRITE_ACP': 'GrantWriteAcp',
  2869. };
  2870. var AccessControlList = AccessControlPolicy && AccessControlPolicy.AccessControlList || {};
  2871. var Grant = AccessControlList.Grant;
  2872. if (Grant) {
  2873. Grant = util.isArray(Grant) ? Grant : [Grant];
  2874. }
  2875. var PublicAcl = {READ: 0, WRITE: 0, FULL_CONTROL: 0};
  2876. Grant && Grant.length && util.each(Grant, function (item) {
  2877. if (item.Grantee.ID === 'qcs::cam::anyone:anyone' || item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers') {
  2878. PublicAcl[item.Permission] = 1;
  2879. } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) {
  2880. result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"');
  2881. }
  2882. });
  2883. if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) {
  2884. result.ACL = 'public-read-write';
  2885. } else if (PublicAcl.READ) {
  2886. result.ACL = 'public-read';
  2887. } else {
  2888. result.ACL = 'private';
  2889. }
  2890. util.each(GrantMap, function (item) {
  2891. result[item] = uniqGrant(result[item].join(','));
  2892. });
  2893. return result;
  2894. }
  2895. // Grant 去重
  2896. function uniqGrant(str) {
  2897. var arr = str.split(',');
  2898. var exist = {};
  2899. var i, item;
  2900. for (i = 0; i < arr.length; ) {
  2901. item = arr[i].trim();
  2902. if (exist[item]) {
  2903. arr.splice(i, 1);
  2904. } else {
  2905. exist[item] = true;
  2906. arr[i] = item;
  2907. i++;
  2908. }
  2909. }
  2910. return arr.join(',');
  2911. }
  2912. // 生成操作 url
  2913. function getUrl(params) {
  2914. var region = params.region || '';
  2915. var longBucket = params.bucket || '';
  2916. var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-'));
  2917. var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1);
  2918. var domain = params.domain;
  2919. var object = params.object;
  2920. if (typeof domain === 'function') {
  2921. domain = domain({Bucket: longBucket, Region: region});
  2922. }
  2923. var protocol = params.protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:');
  2924. if (!domain) {
  2925. if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) {
  2926. domain = '{Region}.myqcloud.com';
  2927. } else {
  2928. domain = 'cos.{Region}.myqcloud.com';
  2929. }
  2930. if (!params.ForcePathStyle) {
  2931. domain = '{Bucket}.' + domain;
  2932. }
  2933. }
  2934. domain = domain.replace(/\{\{AppId\}\}/ig, appId)
  2935. .replace(/\{\{Bucket\}\}/ig, shortBucket)
  2936. .replace(/\{\{Region\}\}/ig, region)
  2937. .replace(/\{\{.*?\}\}/ig, '');
  2938. domain = domain.replace(/\{AppId\}/ig, appId)
  2939. .replace(/\{BucketName\}/ig, shortBucket)
  2940. .replace(/\{Bucket\}/ig, longBucket)
  2941. .replace(/\{Region\}/ig, region)
  2942. .replace(/\{.*?\}/ig, '');
  2943. if (!/^[a-zA-Z]+:\/\//.test(domain)) {
  2944. domain = protocol + '//' + domain;
  2945. }
  2946. // 去掉域名最后的斜杆
  2947. if (domain.slice(-1) === '/') {
  2948. domain = domain.slice(0, -1);
  2949. }
  2950. var url = domain;
  2951. if (params.ForcePathStyle) {
  2952. url += '/' + longBucket;
  2953. }
  2954. url += '/';
  2955. if (object) {
  2956. url += util.camSafeUrlEncode(object).replace(/%2F/g, '/');
  2957. }
  2958. if (params.isLocation) {
  2959. url = url.replace(/^https?:\/\//, '');
  2960. }
  2961. return url;
  2962. }
  2963. var getSignHost = function (opt) {
  2964. if (!opt.Bucket || !opt.Region) return '';
  2965. var useAccelerate = opt.UseAccelerate === undefined ? this.options.UseAccelerate : opt.UseAccelerate;
  2966. var url = opt.Url || getUrl({
  2967. ForcePathStyle: this.options.ForcePathStyle,
  2968. protocol: this.options.Protocol,
  2969. domain: this.options.Domain,
  2970. bucket: opt.Bucket,
  2971. region: useAccelerate ? 'accelerate' : opt.Region,
  2972. });
  2973. var urlHost = url.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1');
  2974. var standardHostReg = new RegExp('^([a-z\\d-]+-\\d+\\.)?(cos|cosv6|ci|pic)\\.([a-z\\d-]+)\\.myqcloud\\.com$');
  2975. if (standardHostReg.test(urlHost)) return urlHost;
  2976. return '';
  2977. }
  2978. // 异步获取签名
  2979. function getAuthorizationAsync(params, callback) {
  2980. var headers = util.clone(params.Headers);
  2981. var headerHost = '';
  2982. util.each(headers, function (v, k) {
  2983. (v === '' || ['content-type', 'cache-control', 'expires'].indexOf(k.toLowerCase()) > -1) && delete headers[k];
  2984. if (k.toLowerCase() === 'host') headerHost = v;
  2985. });
  2986. // ForceSignHost明确传入false才不加入host签名
  2987. var forceSignHost = params.ForceSignHost === false ? false : true;
  2988. // Host 加入签名计算
  2989. if (!headerHost && params.SignHost && forceSignHost) headers.Host = params.SignHost;
  2990. // 获取凭证的回调,避免用户 callback 多次
  2991. var cbDone = false;
  2992. var cb = function (err, AuthData) {
  2993. if (cbDone) return;
  2994. cbDone = true;
  2995. if (AuthData && AuthData.XCosSecurityToken && !AuthData.SecurityToken) {
  2996. AuthData = util.clone(AuthData);
  2997. AuthData.SecurityToken = AuthData.XCosSecurityToken;
  2998. delete AuthData.XCosSecurityToken;
  2999. }
  3000. callback && callback(err, AuthData);
  3001. };
  3002. var self = this;
  3003. var Bucket = params.Bucket || '';
  3004. var Region = params.Region || '';
  3005. // PathName
  3006. var KeyName = params.Key || '';
  3007. if (self.options.ForcePathStyle && Bucket) {
  3008. KeyName = Bucket + '/' + KeyName;
  3009. }
  3010. var Pathname = '/' + KeyName;
  3011. // Action、ResourceKey
  3012. var StsData = {};
  3013. var Scope = params.Scope;
  3014. if (!Scope) {
  3015. var Action = params.Action || '';
  3016. var ResourceKey = params.ResourceKey || params.Key || '';
  3017. Scope = params.Scope || [{
  3018. action: Action,
  3019. bucket: Bucket,
  3020. region: Region,
  3021. prefix: ResourceKey,
  3022. }];
  3023. }
  3024. var ScopeKey = util.md5(JSON.stringify(Scope));
  3025. // STS
  3026. self._StsCache = self._StsCache ||[];
  3027. (function () {
  3028. var i, AuthData;
  3029. for (i = self._StsCache.length - 1; i >= 0; i--) {
  3030. AuthData = self._StsCache[i];
  3031. var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30;
  3032. if (AuthData.StartTime && compareTime < AuthData.StartTime || compareTime >= AuthData.ExpiredTime) {
  3033. self._StsCache.splice(i, 1);
  3034. continue;
  3035. }
  3036. if (!AuthData.ScopeLimit || AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey) {
  3037. StsData = AuthData;
  3038. break;
  3039. }
  3040. }
  3041. })();
  3042. var calcAuthByTmpKey = function () {
  3043. var KeyTime = '';
  3044. if (StsData.StartTime && params.Expires) KeyTime = StsData.StartTime + ';' + (StsData.StartTime + params.Expires * 1);
  3045. else if (StsData.StartTime && StsData.ExpiredTime) KeyTime = StsData.StartTime + ';' + StsData.ExpiredTime;
  3046. var Authorization = util.getAuth({
  3047. SecretId: StsData.TmpSecretId,
  3048. SecretKey: StsData.TmpSecretKey,
  3049. Method: params.Method,
  3050. Pathname: Pathname,
  3051. Query: params.Query,
  3052. Headers: headers,
  3053. Expires: params.Expires,
  3054. UseRawKey: self.options.UseRawKey,
  3055. SystemClockOffset: self.options.SystemClockOffset,
  3056. KeyTime: KeyTime,
  3057. ForceSignHost: forceSignHost,
  3058. });
  3059. var AuthData = {
  3060. Authorization: Authorization,
  3061. SecurityToken: StsData.SecurityToken || StsData.XCosSecurityToken || '',
  3062. Token: StsData.Token || '',
  3063. ClientIP: StsData.ClientIP || '',
  3064. ClientUA: StsData.ClientUA || '',
  3065. };
  3066. cb(null, AuthData);
  3067. };
  3068. var checkAuthError = function (AuthData) {
  3069. if (AuthData.Authorization) {
  3070. // 检查签名格式
  3071. var formatAllow = false;
  3072. var auth = AuthData.Authorization;
  3073. if (auth) {
  3074. if (auth.indexOf(' ') > -1) {
  3075. formatAllow = false;
  3076. } else if (auth.indexOf('q-sign-algorithm=') > -1 &&
  3077. auth.indexOf('q-ak=') > -1 &&
  3078. auth.indexOf('q-sign-time=') > -1 &&
  3079. auth.indexOf('q-key-time=') > -1 &&
  3080. auth.indexOf('q-url-param-list=') > -1) {
  3081. formatAllow = true;
  3082. } else {
  3083. try {
  3084. auth = atob(auth);
  3085. if (auth.indexOf('a=') > -1 &&
  3086. auth.indexOf('k=') > -1 &&
  3087. auth.indexOf('t=') > -1 &&
  3088. auth.indexOf('r=') > -1 &&
  3089. auth.indexOf('b=') > -1) {
  3090. formatAllow = true;
  3091. }
  3092. } catch (e) {}
  3093. }
  3094. }
  3095. if (!formatAllow) return util.error(new Error('getAuthorization callback params format error'));
  3096. } else {
  3097. if (!AuthData.TmpSecretId) return util.error(new Error('getAuthorization callback params missing "TmpSecretId"'));
  3098. if (!AuthData.TmpSecretKey) return util.error(new Error('getAuthorization callback params missing "TmpSecretKey"'));
  3099. if (!AuthData.SecurityToken && !AuthData.XCosSecurityToken) return util.error(new Error('getAuthorization callback params missing "SecurityToken"'));
  3100. if (!AuthData.ExpiredTime) return util.error(new Error('getAuthorization callback params missing "ExpiredTime"'));
  3101. if (AuthData.ExpiredTime && AuthData.ExpiredTime.toString().length !== 10) return util.error(new Error('getAuthorization callback params "ExpiredTime" should be 10 digits'));
  3102. if (AuthData.StartTime && AuthData.StartTime.toString().length !== 10) return util.error(new Error('getAuthorization callback params "StartTime" should be 10 StartTime'));
  3103. }
  3104. return false;
  3105. };
  3106. // 先判断是否有临时密钥
  3107. if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用
  3108. calcAuthByTmpKey();
  3109. } else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥
  3110. self.options.getAuthorization.call(self, {
  3111. Bucket: Bucket,
  3112. Region: Region,
  3113. Method: params.Method,
  3114. Key: KeyName,
  3115. Pathname: Pathname,
  3116. Query: params.Query,
  3117. Headers: headers,
  3118. Scope: Scope,
  3119. SystemClockOffset: self.options.SystemClockOffset,
  3120. ForceSignHost: forceSignHost,
  3121. }, function (AuthData) {
  3122. if (typeof AuthData === 'string') AuthData = {Authorization: AuthData};
  3123. var AuthError = checkAuthError(AuthData);
  3124. if (AuthError) return cb(AuthError);
  3125. if (AuthData.Authorization) {
  3126. cb(null, AuthData);
  3127. } else {
  3128. StsData = AuthData || {};
  3129. StsData.Scope = Scope;
  3130. StsData.ScopeKey = ScopeKey;
  3131. self._StsCache.push(StsData);
  3132. calcAuthByTmpKey();
  3133. }
  3134. });
  3135. } else if (self.options.getSTS) { // 外部获取临时密钥
  3136. self.options.getSTS.call(self, {
  3137. Bucket: Bucket,
  3138. Region: Region,
  3139. }, function (data) {
  3140. StsData = data || {};
  3141. StsData.Scope = Scope;
  3142. StsData.ScopeKey = ScopeKey;
  3143. if (!StsData.TmpSecretId) StsData.TmpSecretId = StsData.SecretId;
  3144. if (!StsData.TmpSecretKey) StsData.TmpSecretKey = StsData.SecretKey;
  3145. var AuthError = checkAuthError(StsData);
  3146. if (AuthError) return cb(AuthError);
  3147. self._StsCache.push(StsData);
  3148. calcAuthByTmpKey();
  3149. });
  3150. } else { // 内部计算获取签名
  3151. return (function () {
  3152. var Authorization = util.getAuth({
  3153. SecretId: params.SecretId || self.options.SecretId,
  3154. SecretKey: params.SecretKey || self.options.SecretKey,
  3155. Method: params.Method,
  3156. Pathname: Pathname,
  3157. Query: params.Query,
  3158. Headers: headers,
  3159. Expires: params.Expires,
  3160. UseRawKey: self.options.UseRawKey,
  3161. SystemClockOffset: self.options.SystemClockOffset,
  3162. ForceSignHost: forceSignHost,
  3163. });
  3164. var AuthData = {
  3165. Authorization: Authorization,
  3166. SecurityToken: self.options.SecurityToken || self.options.XCosSecurityToken,
  3167. };
  3168. cb(null, AuthData);
  3169. return AuthData;
  3170. })();
  3171. }
  3172. return '';
  3173. }
  3174. // 调整时间偏差
  3175. function allowRetry(err) {
  3176. var allowRetry = false;
  3177. var isTimeError = false;
  3178. var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime);
  3179. try {
  3180. var errorCode = err.error.Code;
  3181. var errorMessage = err.error.Message;
  3182. if (errorCode === 'RequestTimeTooSkewed' ||
  3183. (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) {
  3184. isTimeError = true;
  3185. }
  3186. } catch (e) {
  3187. }
  3188. if (err) {
  3189. if (isTimeError && serverDate) {
  3190. var serverTime = Date.parse(serverDate);
  3191. if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) {
  3192. console.error('error: Local time is too skewed.');
  3193. this.options.SystemClockOffset = serverTime - Date.now();
  3194. allowRetry = true;
  3195. }
  3196. } else if (Math.floor(err.statusCode / 100) === 5) {
  3197. allowRetry = true;
  3198. }
  3199. }
  3200. return allowRetry;
  3201. }
  3202. // 获取签名并发起请求
  3203. function submitRequest(params, callback) {
  3204. var self = this;
  3205. // 处理 headers
  3206. !params.headers && (params.headers = {});
  3207. // 处理 query
  3208. !params.qs && (params.qs = {});
  3209. params.VersionId && (params.qs.versionId = params.VersionId);
  3210. params.qs = util.clearKey(params.qs);
  3211. // 清理 undefined 和 null 字段
  3212. params.headers && (params.headers = util.clearKey(params.headers));
  3213. params.qs && (params.qs = util.clearKey(params.qs));
  3214. var Query = util.clone(params.qs);
  3215. params.action && (Query[params.action] = '');
  3216. var paramsUrl = params.url || params.Url;
  3217. var SignHost = params.SignHost || getSignHost.call(this, {Bucket: params.Bucket, Region: params.Region, Url: paramsUrl});
  3218. var next = function (tryTimes) {
  3219. var oldClockOffset = self.options.SystemClockOffset;
  3220. getAuthorizationAsync.call(self, {
  3221. Bucket: params.Bucket || '',
  3222. Region: params.Region || '',
  3223. Method: params.method,
  3224. Key: params.Key,
  3225. Query: Query,
  3226. Headers: params.headers,
  3227. SignHost: SignHost,
  3228. Action: params.Action,
  3229. ResourceKey: params.ResourceKey,
  3230. Scope: params.Scope,
  3231. ForceSignHost: self.options.ForceSignHost,
  3232. }, function (err, AuthData) {
  3233. if (err) {
  3234. callback(err);
  3235. return;
  3236. }
  3237. params.AuthData = AuthData;
  3238. _submitRequest.call(self, params, function (err, data) {
  3239. if (err && tryTimes < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) {
  3240. if (params.headers) {
  3241. delete params.headers.Authorization;
  3242. delete params.headers['token'];
  3243. delete params.headers['clientIP'];
  3244. delete params.headers['clientUA'];
  3245. params.headers['x-cos-security-token'] && (delete params.headers['x-cos-security-token']);
  3246. params.headers['x-ci-security-token'] && (delete params.headers['x-ci-security-token']);
  3247. }
  3248. next(tryTimes + 1);
  3249. } else {
  3250. callback(err, data);
  3251. }
  3252. });
  3253. });
  3254. };
  3255. next(1);
  3256. }
  3257. // 发起请求
  3258. function _submitRequest(params, callback) {
  3259. var self = this;
  3260. var TaskId = params.TaskId;
  3261. if (TaskId && !self._isRunningTask(TaskId)) return;
  3262. var bucket = params.Bucket;
  3263. var region = params.Region;
  3264. var object = params.Key;
  3265. var method = params.method || 'GET';
  3266. var url = params.Url || params.url;
  3267. var body = params.body;
  3268. var rawBody = params.rawBody;
  3269. // url
  3270. if (self.options.UseAccelerate) {
  3271. region = 'accelerate';
  3272. }
  3273. url = url || getUrl({
  3274. ForcePathStyle: self.options.ForcePathStyle,
  3275. protocol: self.options.Protocol,
  3276. domain: self.options.Domain,
  3277. bucket: bucket,
  3278. region: region,
  3279. object: object,
  3280. });
  3281. if (params.action) {
  3282. url = url + '?' + params.action;
  3283. }
  3284. if (params.qsStr) {
  3285. if(url.indexOf('?') > -1){
  3286. url = url + '&' + params.qsStr;
  3287. }else{
  3288. url = url + '?' + params.qsStr;
  3289. }
  3290. }
  3291. var opt = {
  3292. method: method,
  3293. url: url,
  3294. headers: params.headers,
  3295. qs: params.qs,
  3296. body: body,
  3297. };
  3298. // 兼容ci接口
  3299. var token = 'x-cos-security-token';
  3300. if (util.isCIHost(url)) {
  3301. token = 'x-ci-security-token';
  3302. }
  3303. // 获取签名
  3304. opt.headers.Authorization = params.AuthData.Authorization;
  3305. params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token);
  3306. params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP);
  3307. params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA);
  3308. params.AuthData.SecurityToken && (opt.headers[token] = params.AuthData.SecurityToken);
  3309. // 清理 undefined 和 null 字段
  3310. opt.headers && (opt.headers = util.clearKey(opt.headers));
  3311. opt = util.clearKey(opt);
  3312. // progress
  3313. if (params.onProgress && typeof params.onProgress === 'function') {
  3314. var contentLength = body && (body.size || body.length) || 0;
  3315. opt.onProgress = function (e) {
  3316. if (TaskId && !self._isRunningTask(TaskId)) return;
  3317. var loaded = e ? e.loaded : 0;
  3318. params.onProgress({loaded: loaded, total: contentLength});
  3319. };
  3320. }
  3321. if (params.onDownloadProgress) {
  3322. opt.onDownloadProgress = params.onDownloadProgress;
  3323. }
  3324. if (params.DataType) {
  3325. opt.dataType = params.DataType;
  3326. }
  3327. if (this.options.Timeout) {
  3328. opt.timeout = this.options.Timeout;
  3329. }
  3330. self.options.ForcePathStyle && (opt.pathStyle = self.options.ForcePathStyle);
  3331. self.emit('before-send', opt);
  3332. var sender = (self.options.Request || REQUEST)(opt, function (r) {
  3333. if (r.error === 'abort') return;
  3334. var receive = {
  3335. options: opt,
  3336. error: err,
  3337. statusCode: response && response.statusCode || 0,
  3338. headers: response && response.headers || {},
  3339. body: body,
  3340. };
  3341. self.emit('after-receive', receive);
  3342. err = receive.error;
  3343. body = receive.body;
  3344. response = {
  3345. statusCode: receive.statusCode,
  3346. headers: receive.headers,
  3347. };
  3348. // 抛出事件,允许修改返回值的 error、statusCode、statusMessage、body
  3349. self.emit('after-receive', r);
  3350. var response = {statusCode: r.statusCode, statusMessage: r.statusMessage, headers: r.headers};
  3351. var err = r.error;
  3352. var body = r.body;
  3353. // 返回内容添加 状态码 和 headers
  3354. var hasReturned;
  3355. var cb = function (err, data) {
  3356. TaskId && self.off('inner-kill-task', killTask);
  3357. if (hasReturned) return;
  3358. hasReturned = true;
  3359. var attrs = {};
  3360. response && response.statusCode && (attrs.statusCode = response.statusCode);
  3361. response && response.headers && (attrs.headers = response.headers);
  3362. if (err) {
  3363. err = util.extend(err || {}, attrs)
  3364. callback(err, null);
  3365. } else {
  3366. data = util.extend(data || {}, attrs);
  3367. callback(null, data);
  3368. }
  3369. sender = null;
  3370. };
  3371. // 请求错误,发生网络错误
  3372. if (err) return cb(util.error(err));
  3373. // 请求返回码不为 200
  3374. var statusCode = response.statusCode;
  3375. var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206
  3376. // 不对 body 进行转换,body 直接挂载返回
  3377. if (rawBody && statusSuccess) return cb(null, {body: body});
  3378. // 解析 xml body
  3379. var json;
  3380. try {
  3381. json = body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body) || {};
  3382. } catch (e) {
  3383. json = {};
  3384. }
  3385. // 处理返回值
  3386. var xmlError = json && json.Error;
  3387. if (statusSuccess) { // 正确返回,状态码 2xx 时,body 不会有 Error
  3388. cb(null, json);
  3389. } else if (xmlError) { // 正常返回了 xml body,且有 Error 节点
  3390. cb(util.error(new Error(xmlError.Message), {code: xmlError.Code, error: xmlError}));
  3391. } else if (statusCode) { // 有错误的状态码
  3392. cb(util.error(new Error(response.statusMessage), {code: '' + statusCode}));
  3393. } else if (statusCode) { // 无状态码,或者获取不到状态码
  3394. cb(util.error(new Error('statusCode error')));
  3395. }
  3396. });
  3397. // kill task
  3398. var killTask = function (data) {
  3399. if (data.TaskId === TaskId) {
  3400. sender && sender.abort && sender.abort();
  3401. self.off('inner-kill-task', killTask);
  3402. }
  3403. };
  3404. TaskId && self.on('inner-kill-task', killTask);
  3405. }
  3406. var API_MAP = {
  3407. // Bucket 相关方法
  3408. getService: getService, // Bucket
  3409. putBucket: putBucket,
  3410. headBucket: headBucket, // Bucket
  3411. getBucket: getBucket,
  3412. deleteBucket: deleteBucket,
  3413. putBucketAcl: putBucketAcl, // BucketACL
  3414. getBucketAcl: getBucketAcl,
  3415. putBucketCors: putBucketCors, // BucketCors
  3416. getBucketCors: getBucketCors,
  3417. deleteBucketCors: deleteBucketCors,
  3418. getBucketLocation: getBucketLocation, // BucketLocation
  3419. getBucketPolicy: getBucketPolicy, // BucketPolicy
  3420. putBucketPolicy: putBucketPolicy,
  3421. deleteBucketPolicy: deleteBucketPolicy,
  3422. putBucketTagging: putBucketTagging, // BucketTagging
  3423. getBucketTagging: getBucketTagging,
  3424. deleteBucketTagging: deleteBucketTagging,
  3425. putBucketLifecycle: putBucketLifecycle, // BucketLifecycle
  3426. getBucketLifecycle: getBucketLifecycle,
  3427. deleteBucketLifecycle: deleteBucketLifecycle,
  3428. putBucketVersioning: putBucketVersioning, // BucketVersioning
  3429. getBucketVersioning: getBucketVersioning,
  3430. putBucketReplication: putBucketReplication, // BucketReplication
  3431. getBucketReplication: getBucketReplication,
  3432. deleteBucketReplication: deleteBucketReplication,
  3433. putBucketWebsite: putBucketWebsite, // BucketWebsite
  3434. getBucketWebsite: getBucketWebsite,
  3435. deleteBucketWebsite: deleteBucketWebsite,
  3436. putBucketReferer: putBucketReferer, // BucketReferer
  3437. getBucketReferer: getBucketReferer,
  3438. putBucketDomain: putBucketDomain, // BucketDomain
  3439. getBucketDomain: getBucketDomain,
  3440. deleteBucketDomain: deleteBucketDomain,
  3441. putBucketOrigin: putBucketOrigin, // BucketOrigin
  3442. getBucketOrigin: getBucketOrigin,
  3443. deleteBucketOrigin: deleteBucketOrigin,
  3444. putBucketLogging: putBucketLogging, // BucketLogging
  3445. getBucketLogging: getBucketLogging,
  3446. putBucketInventory: putBucketInventory, // BucketInventory
  3447. getBucketInventory: getBucketInventory,
  3448. listBucketInventory: listBucketInventory,
  3449. deleteBucketInventory: deleteBucketInventory,
  3450. putBucketAccelerate: putBucketAccelerate,
  3451. getBucketAccelerate: getBucketAccelerate,
  3452. putBucketEncryption: putBucketEncryption,
  3453. getBucketEncryption: getBucketEncryption,
  3454. deleteBucketEncryption: deleteBucketEncryption,
  3455. // Object 相关方法
  3456. getObject: getObject,
  3457. headObject: headObject,
  3458. listObjectVersions: listObjectVersions,
  3459. putObject: putObject,
  3460. deleteObject: deleteObject,
  3461. getObjectAcl: getObjectAcl,
  3462. putObjectAcl: putObjectAcl,
  3463. optionsObject: optionsObject,
  3464. putObjectCopy: putObjectCopy,
  3465. deleteMultipleObject: deleteMultipleObject,
  3466. restoreObject: restoreObject,
  3467. putObjectTagging: putObjectTagging,
  3468. getObjectTagging: getObjectTagging,
  3469. deleteObjectTagging: deleteObjectTagging,
  3470. selectObjectContent: selectObjectContent,
  3471. appendObject: appendObject,
  3472. // 分块上传相关方法
  3473. uploadPartCopy: uploadPartCopy,
  3474. multipartInit: multipartInit,
  3475. multipartUpload: multipartUpload,
  3476. multipartComplete: multipartComplete,
  3477. multipartList: multipartList,
  3478. multipartListPart: multipartListPart,
  3479. multipartAbort: multipartAbort,
  3480. // 工具方法
  3481. request: request,
  3482. getObjectUrl: getObjectUrl,
  3483. getAuth: getAuth,
  3484. };
  3485. function warnOldApi(apiName, fn, proto) {
  3486. util.each(['Cors', 'Acl'], function (suffix) {
  3487. if (apiName.slice(-suffix.length) === suffix) {
  3488. var oldName = apiName.slice(0, -suffix.length) + suffix.toUpperCase();
  3489. var apiFn = util.apiWrapper(apiName, fn);
  3490. var warned = false;
  3491. proto[oldName] = function () {
  3492. !warned && console.warn('warning: cos.' + oldName + ' has been deprecated. Please Use cos.' + apiName + ' instead.');
  3493. warned = true;
  3494. apiFn.apply(this, arguments);
  3495. };
  3496. }
  3497. });
  3498. }
  3499. module.exports.init = function (COS, task) {
  3500. task.transferToTaskMethod(API_MAP, 'putObject');
  3501. util.each(API_MAP, function (fn, apiName) {
  3502. COS.prototype[apiName] = util.apiWrapper(apiName, fn);
  3503. warnOldApi(apiName, fn, COS.prototype);
  3504. });
  3505. };