💾 Archived View for gmi.noulin.net › gitRepositories › git-off › file › src › node_modules › aws-sdk… captured on 2024-09-29 at 00:46:02. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
util.js (26894B)
1 /* eslint guard-for-in:0 */ 2 var AWS; 3 4 /** 5 * A set of utility methods for use with the AWS SDK. 6 * 7 * @!attribute abort 8 * Return this value from an iterator function {each} or {arrayEach} 9 * to break out of the iteration. 10 * @example Breaking out of an iterator function 11 * AWS.util.each({a: 1, b: 2, c: 3}, function(key, value) { 12 * if (key == 'b') return AWS.util.abort; 13 * }); 14 * @see each 15 * @see arrayEach 16 * @api private 17 */ 18 var util = { 19 engine: function engine() { 20 if (util.isBrowser() && typeof navigator !== 'undefined') { 21 return navigator.userAgent; 22 } else { 23 return process.platform + '/' + process.version; 24 } 25 }, 26 27 userAgent: function userAgent() { 28 var name = util.isBrowser() ? 'js' : 'nodejs'; 29 var agent = 'aws-sdk-' + name + '/' + require('./core').VERSION; 30 if (name === 'nodejs') agent += ' ' + util.engine(); 31 return agent; 32 }, 33 34 isBrowser: function isBrowser() { return process && process.browser; }, 35 isNode: function isNode() { return !util.isBrowser(); }, 36 uriEscape: function uriEscape(string) { 37 var output = encodeURIComponent(string); 38 output = output.replace(/[^A-Za-z0-9_.~\-%]+/g, escape); 39 40 // AWS percent-encodes some extra non-standard characters in a URI 41 output = output.replace(/[*]/g, function(ch) { 42 return '%' + ch.charCodeAt(0).toString(16).toUpperCase(); 43 }); 44 45 return output; 46 }, 47 48 uriEscapePath: function uriEscapePath(string) { 49 var parts = []; 50 util.arrayEach(string.split('/'), function (part) { 51 parts.push(util.uriEscape(part)); 52 }); 53 return parts.join('/'); 54 }, 55 56 urlParse: function urlParse(url) { 57 return util.url.parse(url); 58 }, 59 60 urlFormat: function urlFormat(url) { 61 return util.url.format(url); 62 }, 63 64 queryStringParse: function queryStringParse(qs) { 65 return util.querystring.parse(qs); 66 }, 67 68 queryParamsToString: function queryParamsToString(params) { 69 var items = []; 70 var escape = util.uriEscape; 71 var sortedKeys = Object.keys(params).sort(); 72 73 util.arrayEach(sortedKeys, function(name) { 74 var value = params[name]; 75 var ename = escape(name); 76 var result = ename + '='; 77 if (Array.isArray(value)) { 78 var vals = []; 79 util.arrayEach(value, function(item) { vals.push(escape(item)); }); 80 result = ename + '=' + vals.sort().join('&' + ename + '='); 81 } else if (value !== undefined && value !== null) { 82 result = ename + '=' + escape(value); 83 } 84 items.push(result); 85 }); 86 87 return items.join('&'); 88 }, 89 90 readFileSync: function readFileSync(path) { 91 if (util.isBrowser()) return null; 92 return require('fs').readFileSync(path, 'utf-8'); 93 }, 94 95 base64: { 96 97 encode: function encode64(string) { 98 return new util.Buffer(string).toString('base64'); 99 }, 100 101 decode: function decode64(string) { 102 return new util.Buffer(string, 'base64'); 103 } 104 105 }, 106 107 buffer: { 108 toStream: function toStream(buffer) { 109 if (!util.Buffer.isBuffer(buffer)) buffer = new util.Buffer(buffer); 110 111 var readable = new (util.stream.Readable)(); 112 var pos = 0; 113 readable._read = function(size) { 114 if (pos >= buffer.length) return readable.push(null); 115 116 var end = pos + size; 117 if (end > buffer.length) end = buffer.length; 118 readable.push(buffer.slice(pos, end)); 119 pos = end; 120 }; 121 122 return readable; 123 }, 124 125 /** 126 * Concatenates a list of Buffer objects. 127 */ 128 concat: function(buffers) { 129 var length = 0, 130 offset = 0, 131 buffer = null, i; 132 133 for (i = 0; i < buffers.length; i++) { 134 length += buffers[i].length; 135 } 136 137 buffer = new util.Buffer(length); 138 139 for (i = 0; i < buffers.length; i++) { 140 buffers[i].copy(buffer, offset); 141 offset += buffers[i].length; 142 } 143 144 return buffer; 145 } 146 }, 147 148 string: { 149 byteLength: function byteLength(string) { 150 if (string === null || string === undefined) return 0; 151 if (typeof string === 'string') string = new util.Buffer(string); 152 153 if (typeof string.byteLength === 'number') { 154 return string.byteLength; 155 } else if (typeof string.length === 'number') { 156 return string.length; 157 } else if (typeof string.size === 'number') { 158 return string.size; 159 } else if (typeof string.path === 'string') { 160 return require('fs').lstatSync(string.path).size; 161 } else { 162 throw util.error(new Error('Cannot determine length of ' + string), 163 { object: string }); 164 } 165 }, 166 167 upperFirst: function upperFirst(string) { 168 return string[0].toUpperCase() + string.substr(1); 169 }, 170 171 lowerFirst: function lowerFirst(string) { 172 return string[0].toLowerCase() + string.substr(1); 173 } 174 }, 175 176 ini: { 177 parse: function string(ini) { 178 var currentSection, map = {}; 179 util.arrayEach(ini.split(/\r?\n/), function(line) { 180 line = line.split(/(^|\s)[;#]/)[0]; // remove comments 181 var section = line.match(/^\s*\[([^\[\]]+)\]\s*$/); 182 if (section) { 183 currentSection = section[1]; 184 } else if (currentSection) { 185 var item = line.match(/^\s*(.+?)\s*=\s*(.+?)\s*$/); 186 if (item) { 187 map[currentSection] = map[currentSection] || {}; 188 map[currentSection][item[1]] = item[2]; 189 } 190 } 191 }); 192 193 return map; 194 } 195 }, 196 197 fn: { 198 noop: function() {}, 199 200 /** 201 * Turn a synchronous function into as "async" function by making it call 202 * a callback. The underlying function is called with all but the last argument, 203 * which is treated as the callback. The callback is passed passed a first argument 204 * of null on success to mimick standard node callbacks. 205 */ 206 makeAsync: function makeAsync(fn, expectedArgs) { 207 if (expectedArgs && expectedArgs <= fn.length) { 208 return fn; 209 } 210 211 return function() { 212 var args = Array.prototype.slice.call(arguments, 0); 213 var callback = args.pop(); 214 var result = fn.apply(null, args); 215 callback(result); 216 }; 217 } 218 }, 219 220 /** 221 * Date and time utility functions. 222 */ 223 date: { 224 225 /** 226 * @return [Date] the current JavaScript date object. Since all 227 * AWS services rely on this date object, you can override 228 * this function to provide a special time value to AWS service 229 * requests. 230 */ 231 getDate: function getDate() { 232 if (!AWS) AWS = require('./core'); 233 if (AWS.config.systemClockOffset) { // use offset when non-zero 234 return new Date(new Date().getTime() + AWS.config.systemClockOffset); 235 } else { 236 return new Date(); 237 } 238 }, 239 240 /** 241 * @return [String] the date in ISO-8601 format 242 */ 243 iso8601: function iso8601(date) { 244 if (date === undefined) { date = util.date.getDate(); } 245 return date.toISOString().replace(/\.\d{3}Z$/, 'Z'); 246 }, 247 248 /** 249 * @return [String] the date in RFC 822 format 250 */ 251 rfc822: function rfc822(date) { 252 if (date === undefined) { date = util.date.getDate(); } 253 return date.toUTCString(); 254 }, 255 256 /** 257 * @return [Integer] the UNIX timestamp value for the current time 258 */ 259 unixTimestamp: function unixTimestamp(date) { 260 if (date === undefined) { date = util.date.getDate(); } 261 return date.getTime() / 1000; 262 }, 263 264 /** 265 * @param [String,number,Date] date 266 * @return [Date] 267 */ 268 from: function format(date) { 269 if (typeof date === 'number') { 270 return new Date(date * 1000); // unix timestamp 271 } else { 272 return new Date(date); 273 } 274 }, 275 276 /** 277 * Given a Date or date-like value, this function formats the 278 * date into a string of the requested value. 279 * @param [String,number,Date] date 280 * @param [String] formatter Valid formats are: 281 # * 'iso8601' 282 # * 'rfc822' 283 # * 'unixTimestamp' 284 * @return [String] 285 */ 286 format: function format(date, formatter) { 287 if (!formatter) formatter = 'iso8601'; 288 return util.date[formatter](util.date.from(date)); 289 }, 290 291 parseTimestamp: function parseTimestamp(value) { 292 if (typeof value === 'number') { // unix timestamp (number) 293 return new Date(value * 1000); 294 } else if (value.match(/^\d+$/)) { // unix timestamp 295 return new Date(value * 1000); 296 } else if (value.match(/^\d{4}/)) { // iso8601 297 return new Date(value); 298 } else if (value.match(/^\w{3},/)) { // rfc822 299 return new Date(value); 300 } else { 301 throw util.error( 302 new Error('unhandled timestamp format: ' + value), 303 {code: 'TimestampParserError'}); 304 } 305 } 306 307 }, 308 309 crypto: { 310 crc32Table: [ 311 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 312 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 313 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 314 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 315 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 316 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 317 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 318 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 319 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 320 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 321 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 322 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 323 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 324 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 325 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 326 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 327 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 328 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 329 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 330 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 331 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 332 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 333 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 334 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 335 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 336 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 337 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 338 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 339 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 340 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 341 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 342 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 343 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 344 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 345 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 346 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 347 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 348 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 349 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 350 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 351 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 352 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 353 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 354 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 355 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 356 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 357 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 358 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 359 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 360 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 361 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 362 0x2D02EF8D], 363 364 crc32: function crc32(data) { 365 var tbl = util.crypto.crc32Table; 366 var crc = 0 ^ -1; 367 368 if (typeof data === 'string') { 369 data = new util.Buffer(data); 370 } 371 372 for (var i = 0; i < data.length; i++) { 373 var code = data.readUInt8(i); 374 crc = (crc >>> 8) ^ tbl[(crc ^ code) & 0xFF]; 375 } 376 return (crc ^ -1) >>> 0; 377 }, 378 379 hmac: function hmac(key, string, digest, fn) { 380 if (!digest) digest = 'binary'; 381 if (digest === 'buffer') { digest = undefined; } 382 if (!fn) fn = 'sha256'; 383 if (typeof string === 'string') string = new util.Buffer(string); 384 return util.crypto.lib.createHmac(fn, key).update(string).digest(digest); 385 }, 386 387 md5: function md5(data, digest, callback) { 388 return util.crypto.hash('md5', data, digest, callback); 389 }, 390 391 sha256: function sha256(data, digest, callback) { 392 return util.crypto.hash('sha256', data, digest, callback); 393 }, 394 395 hash: function(algorithm, data, digest, callback) { 396 var hash = util.crypto.createHash(algorithm); 397 if (!digest) { digest = 'binary'; } 398 if (digest === 'buffer') { digest = undefined; } 399 if (typeof data === 'string') data = new util.Buffer(data); 400 var sliceFn = util.arraySliceFn(data); 401 var isBuffer = util.Buffer.isBuffer(data); 402 //Identifying objects with an ArrayBuffer as buffers 403 if (util.isBrowser() && typeof ArrayBuffer !== 'undefined' && data && data.buffer instanceof ArrayBuffer) isBuffer = true; 404 405 if (callback && typeof data === 'object' && 406 typeof data.on === 'function' && !isBuffer) { 407 data.on('data', function(chunk) { hash.update(chunk); }); 408 data.on('error', function(err) { callback(err); }); 409 data.on('end', function() { callback(null, hash.digest(digest)); }); 410 } else if (callback && sliceFn && !isBuffer && 411 typeof FileReader !== 'undefined') { 412 // this might be a File/Blob 413 var index = 0, size = 1024 * 512; 414 var reader = new FileReader(); 415 reader.onerror = function() { 416 callback(new Error('Failed to read data.')); 417 }; 418 reader.onload = function() { 419 var buf = new util.Buffer(new Uint8Array(reader.result)); 420 hash.update(buf); 421 index += buf.length; 422 reader._continueReading(); 423 }; 424 reader._continueReading = function() { 425 if (index >= data.size) { 426 callback(null, hash.digest(digest)); 427 return; 428 } 429 430 var back = index + size; 431 if (back > data.size) back = data.size; 432 reader.readAsArrayBuffer(sliceFn.call(data, index, back)); 433 }; 434 435 reader._continueReading(); 436 } else { 437 if (util.isBrowser() && typeof data === 'object' && !isBuffer) { 438 data = new util.Buffer(new Uint8Array(data)); 439 } 440 var out = hash.update(data).digest(digest); 441 if (callback) callback(null, out); 442 return out; 443 } 444 }, 445 446 toHex: function toHex(data) { 447 var out = []; 448 for (var i = 0; i < data.length; i++) { 449 out.push(('0' + data.charCodeAt(i).toString(16)).substr(-2, 2)); 450 } 451 return out.join(''); 452 }, 453 454 createHash: function createHash(algorithm) { 455 return util.crypto.lib.createHash(algorithm); 456 } 457 458 }, 459 460 /** @!ignore */ 461 462 /* Abort constant */ 463 abort: {}, 464 465 each: function each(object, iterFunction) { 466 for (var key in object) { 467 if (Object.prototype.hasOwnProperty.call(object, key)) { 468 var ret = iterFunction.call(this, key, object[key]); 469 if (ret === util.abort) break; 470 } 471 } 472 }, 473 474 arrayEach: function arrayEach(array, iterFunction) { 475 for (var idx in array) { 476 if (Object.prototype.hasOwnProperty.call(array, idx)) { 477 var ret = iterFunction.call(this, array[idx], parseInt(idx, 10)); 478 if (ret === util.abort) break; 479 } 480 } 481 }, 482 483 update: function update(obj1, obj2) { 484 util.each(obj2, function iterator(key, item) { 485 obj1[key] = item; 486 }); 487 return obj1; 488 }, 489 490 merge: function merge(obj1, obj2) { 491 return util.update(util.copy(obj1), obj2); 492 }, 493 494 copy: function copy(object) { 495 if (object === null || object === undefined) return object; 496 var dupe = {}; 497 // jshint forin:false 498 for (var key in object) { 499 dupe[key] = object[key]; 500 } 501 return dupe; 502 }, 503 504 isEmpty: function isEmpty(obj) { 505 for (var prop in obj) { 506 if (Object.prototype.hasOwnProperty.call(obj, prop)) { 507 return false; 508 } 509 } 510 return true; 511 }, 512 513 arraySliceFn: function arraySliceFn(obj) { 514 var fn = obj.slice || obj.webkitSlice || obj.mozSlice; 515 return typeof fn === 'function' ? fn : null; 516 }, 517 518 isType: function isType(obj, type) { 519 // handle cross-"frame" objects 520 if (typeof type === 'function') type = util.typeName(type); 521 return Object.prototype.toString.call(obj) === '[object ' + type + ']'; 522 }, 523 524 typeName: function typeName(type) { 525 if (Object.prototype.hasOwnProperty.call(type, 'name')) return type.name; 526 var str = type.toString(); 527 var match = str.match(/^\s*function (.+)\(/); 528 return match ? match[1] : str; 529 }, 530 531 error: function error(err, options) { 532 var originalError = null; 533 if (typeof err.message === 'string' && err.message !== '') { 534 if (typeof options === 'string' || (options && options.message)) { 535 originalError = util.copy(err); 536 originalError.message = err.message; 537 } 538 } 539 err.message = err.message || null; 540 541 if (typeof options === 'string') { 542 err.message = options; 543 } else if (typeof options === 'object' && options !== null) { 544 util.update(err, options); 545 if (options.message) 546 err.message = options.message; 547 if (options.code || options.name) 548 err.code = options.code || options.name; 549 if (options.stack) 550 err.stack = options.stack; 551 } 552 553 if (typeof Object.defineProperty === 'function') { 554 Object.defineProperty(err, 'name', {writable: true, enumerable: false}); 555 Object.defineProperty(err, 'message', {enumerable: true}); 556 } 557 558 err.name = options && options.name || err.name || err.code || 'Error'; 559 err.time = new Date(); 560 561 if (originalError) err.originalError = originalError; 562 563 return err; 564 }, 565 566 /** 567 * @api private 568 */ 569 inherit: function inherit(klass, features) { 570 var newObject = null; 571 if (features === undefined) { 572 features = klass; 573 klass = Object; 574 newObject = {}; 575 } else { 576 var ctor = function ConstructorWrapper() {}; 577 ctor.prototype = klass.prototype; 578 newObject = new ctor(); 579 } 580 581 // constructor not supplied, create pass-through ctor 582 if (features.constructor === Object) { 583 features.constructor = function() { 584 if (klass !== Object) { 585 return klass.apply(this, arguments); 586 } 587 }; 588 } 589 590 features.constructor.prototype = newObject; 591 util.update(features.constructor.prototype, features); 592 features.constructor.__super__ = klass; 593 return features.constructor; 594 }, 595 596 /** 597 * @api private 598 */ 599 mixin: function mixin() { 600 var klass = arguments[0]; 601 for (var i = 1; i < arguments.length; i++) { 602 // jshint forin:false 603 for (var prop in arguments[i].prototype) { 604 var fn = arguments[i].prototype[prop]; 605 if (prop !== 'constructor') { 606 klass.prototype[prop] = fn; 607 } 608 } 609 } 610 return klass; 611 }, 612 613 /** 614 * @api private 615 */ 616 hideProperties: function hideProperties(obj, props) { 617 if (typeof Object.defineProperty !== 'function') return; 618 619 util.arrayEach(props, function (key) { 620 Object.defineProperty(obj, key, { 621 enumerable: false, writable: true, configurable: true }); 622 }); 623 }, 624 625 /** 626 * @api private 627 */ 628 property: function property(obj, name, value, enumerable, isValue) { 629 var opts = { 630 configurable: true, 631 enumerable: enumerable !== undefined ? enumerable : true 632 }; 633 if (typeof value === 'function' && !isValue) { 634 opts.get = value; 635 } 636 else { 637 opts.value = value; opts.writable = true; 638 } 639 640 Object.defineProperty(obj, name, opts); 641 }, 642 643 /** 644 * @api private 645 */ 646 memoizedProperty: function memoizedProperty(obj, name, get, enumerable) { 647 var cachedValue = null; 648 649 // build enumerable attribute for each value with lazy accessor. 650 util.property(obj, name, function() { 651 if (cachedValue === null) { 652 cachedValue = get(); 653 } 654 return cachedValue; 655 }, enumerable); 656 }, 657 658 /** 659 * TODO Remove in major version revision 660 * This backfill populates response data without the 661 * top-level payload name. 662 * 663 * @api private 664 */ 665 hoistPayloadMember: function hoistPayloadMember(resp) { 666 var req = resp.request; 667 var operation = req.operation; 668 var output = req.service.api.operations[operation].output; 669 if (output.payload) { 670 var payloadMember = output.members[output.payload]; 671 var responsePayload = resp.data[output.payload]; 672 if (payloadMember.type === 'structure') { 673 util.each(responsePayload, function(key, value) { 674 util.property(resp.data, key, value, false); 675 }); 676 } 677 } 678 }, 679 680 /** 681 * Compute SHA-256 checksums of streams 682 * 683 * @api private 684 */ 685 computeSha256: function computeSha256(body, done) { 686 if (util.isNode()) { 687 var Stream = util.stream.Stream; 688 var fs = require('fs'); 689 if (body instanceof Stream) { 690 if (typeof body.path === 'string') { // assume file object 691 var settings = {}; 692 if (typeof body.start === 'number') { 693 settings.start = body.start; 694 } 695 if (typeof body.end === 'number') { 696 settings.end = body.end; 697 } 698 body = fs.createReadStream(body.path, settings); 699 } else { // TODO support other stream types 700 return done(new Error('Non-file stream objects are ' + 701 'not supported with SigV4')); 702 } 703 } 704 } 705 706 util.crypto.sha256(body, 'hex', function(err, sha) { 707 if (err) done(err); 708 else done(null, sha); 709 }); 710 }, 711 712 /** 713 * @api private 714 */ 715 isClockSkewed: function isClockSkewed(serverTime) { 716 if (serverTime) { 717 util.property(AWS.config, 'isClockSkewed', 718 Math.abs(new Date().getTime() - serverTime) >= 300000, false); 719 return AWS.config.isClockSkewed; 720 } 721 }, 722 723 applyClockOffset: function applyClockOffset(serverTime) { 724 if (serverTime) 725 AWS.config.systemClockOffset = serverTime - new Date().getTime(); 726 }, 727 728 /** 729 * @api private 730 */ 731 extractRequestId: function extractRequestId(resp) { 732 var requestId = resp.httpResponse.headers['x-amz-request-id'] || 733 resp.httpResponse.headers['x-amzn-requestid']; 734 735 if (!requestId && resp.data && resp.data.ResponseMetadata) { 736 requestId = resp.data.ResponseMetadata.RequestId; 737 } 738 739 if (requestId) { 740 resp.requestId = requestId; 741 } 742 743 if (resp.error) { 744 resp.error.requestId = requestId; 745 } 746 }, 747 748 /** 749 * @api private 750 */ 751 addPromises: function addPromises(constructors, PromiseDependency) { 752 if (PromiseDependency === undefined && AWS && AWS.config) { 753 PromiseDependency = AWS.config.getPromisesDependency(); 754 } 755 if (PromiseDependency === undefined && typeof Promise !== 'undefined') { 756 PromiseDependency = Promise; 757 } 758 if (typeof PromiseDependency !== 'function') var deletePromises = true; 759 if (!Array.isArray(constructors)) constructors = [constructors]; 760 761 for (var ind = 0; ind < constructors.length; ind++) { 762 var constructor = constructors[ind]; 763 if (deletePromises) { 764 if (constructor.deletePromisesFromClass) { 765 constructor.deletePromisesFromClass(); 766 } 767 } else if (constructor.addPromisesToClass) { 768 constructor.addPromisesToClass(PromiseDependency); 769 } 770 } 771 }, 772 773 /** 774 * @api private 775 */ 776 promisifyMethod: function promisifyMethod(methodName, PromiseDependency) { 777 return function promise() { 778 var self = this; 779 return new PromiseDependency(function(resolve, reject) { 780 self[methodName](function(err, data) { 781 if (err) { 782 reject(err); 783 } else { 784 resolve(data); 785 } 786 }); 787 }); 788 }; 789 }, 790 791 /** 792 * @api private 793 */ 794 isDualstackAvailable: function isDualstackAvailable(service) { 795 if (!service) return false; 796 var metadata = require('../apis/metadata.json'); 797 if (typeof service !== 'string') service = service.serviceIdentifier; 798 if (typeof service !== 'string' || !metadata.hasOwnProperty(service)) return false; 799 return !!metadata[service].dualstackAvailable; 800 }, 801 802 /** 803 * @api private 804 */ 805 calculateRetryDelay: function calculateRetryDelay(retryCount, retryDelayOptions) { 806 if (!retryDelayOptions) retryDelayOptions = {}; 807 var customBackoff = retryDelayOptions.customBackoff || null; 808 if (typeof customBackoff === 'function') { 809 return customBackoff(retryCount); 810 } 811 var base = retryDelayOptions.base || 100; 812 var delay = Math.random() * (Math.pow(2, retryCount) * base); 813 return delay; 814 }, 815 816 /** 817 * @api private 818 */ 819 handleRequestWithRetries: function handleRequestWithRetries(httpRequest, options, cb) { 820 if (!options) options = {}; 821 var http = AWS.HttpClient.getInstance(); 822 var httpOptions = options.httpOptions || {}; 823 var retryCount = 0; 824 825 var errCallback = function(err) { 826 var maxRetries = options.maxRetries || 0; 827 if (err && err.code === 'TimeoutError') err.retryable = true; 828 if (err && err.retryable && retryCount < maxRetries) { 829 retryCount++; 830 var delay = util.calculateRetryDelay(retryCount, options.retryDelayOptions); 831 setTimeout(sendRequest, delay + (err.retryAfter || 0)); 832 } else { 833 cb(err); 834 } 835 }; 836 837 var sendRequest = function() { 838 var data = ''; 839 http.handleRequest(httpRequest, httpOptions, function(httpResponse) { 840 httpResponse.on('data', function(chunk) { data += chunk.toString(); }); 841 httpResponse.on('end', function() { 842 var statusCode = httpResponse.statusCode; 843 if (statusCode < 300) { 844 cb(null, data); 845 } else { 846 var retryAfter = parseInt(httpResponse.headers['retry-after'], 10) * 1000 || 0; 847 var err = util.error(new Error(), 848 { retryable: statusCode >= 500 || statusCode === 429 } 849 ); 850 if (retryAfter && err.retryable) err.retryAfter = retryAfter; 851 errCallback(err); 852 } 853 }); 854 }, errCallback); 855 }; 856 857 process.nextTick(sendRequest); 858 } 859 860 }; 861 862 module.exports = util;