UNPKG

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