helpers.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. var util = require('../util');
  2. var AWS = require('../core');
  3. /**
  4. * Prepend prefix defined by API model to endpoint that's already
  5. * constructed. This feature does not apply to operations using
  6. * endpoint discovery and can be disabled.
  7. * @api private
  8. */
  9. function populateHostPrefix(request) {
  10. var enabled = request.service.config.hostPrefixEnabled;
  11. if (!enabled) return request;
  12. var operationModel = request.service.api.operations[request.operation];
  13. //don't marshal host prefix when operation has endpoint discovery traits
  14. if (hasEndpointDiscover(request)) return request;
  15. if (operationModel.endpoint && operationModel.endpoint.hostPrefix) {
  16. var hostPrefixNotation = operationModel.endpoint.hostPrefix;
  17. var hostPrefix = expandHostPrefix(hostPrefixNotation, request.params, operationModel.input);
  18. prependEndpointPrefix(request.httpRequest.endpoint, hostPrefix);
  19. validateHostname(request.httpRequest.endpoint.hostname);
  20. }
  21. return request;
  22. }
  23. /**
  24. * @api private
  25. */
  26. function hasEndpointDiscover(request) {
  27. var api = request.service.api;
  28. var operationModel = api.operations[request.operation];
  29. var isEndpointOperation = api.endpointOperation && (api.endpointOperation === util.string.lowerFirst(operationModel.name));
  30. return (operationModel.endpointDiscoveryRequired !== 'NULL' || isEndpointOperation === true);
  31. }
  32. /**
  33. * @api private
  34. */
  35. function expandHostPrefix(hostPrefixNotation, params, shape) {
  36. util.each(shape.members, function(name, member) {
  37. if (member.hostLabel === true) {
  38. if (typeof params[name] !== 'string' || params[name] === '') {
  39. throw util.error(new Error(), {
  40. message: 'Parameter ' + name + ' should be a non-empty string.',
  41. code: 'InvalidParameter'
  42. });
  43. }
  44. var regex = new RegExp('\\{' + name + '\\}', 'g');
  45. hostPrefixNotation = hostPrefixNotation.replace(regex, params[name]);
  46. }
  47. });
  48. return hostPrefixNotation;
  49. }
  50. /**
  51. * @api private
  52. */
  53. function prependEndpointPrefix(endpoint, prefix) {
  54. if (endpoint.host) {
  55. endpoint.host = prefix + endpoint.host;
  56. }
  57. if (endpoint.hostname) {
  58. endpoint.hostname = prefix + endpoint.hostname;
  59. }
  60. }
  61. /**
  62. * @api private
  63. */
  64. function validateHostname(hostname) {
  65. var labels = hostname.split('.');
  66. //Reference: https://tools.ietf.org/html/rfc1123#section-2
  67. var hostPattern = /^[a-zA-Z0-9]{1}$|^[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]$/;
  68. util.arrayEach(labels, function(label) {
  69. if (!label.length || label.length < 1 || label.length > 63) {
  70. throw util.error(new Error(), {
  71. code: 'ValidationError',
  72. message: 'Hostname label length should be between 1 to 63 characters, inclusive.'
  73. });
  74. }
  75. if (!hostPattern.test(label)) {
  76. throw AWS.util.error(new Error(),
  77. {code: 'ValidationError', message: label + ' is not hostname compatible.'});
  78. }
  79. });
  80. }
  81. module.exports = {
  82. populateHostPrefix: populateHostPrefix
  83. };