index.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Load modules
  2. var Http = require('http');
  3. var Hoek = require('hoek');
  4. // Declare internals
  5. var internals = {};
  6. exports.wrap = function (error, statusCode, message) {
  7. Hoek.assert(error instanceof Error, 'Cannot wrap non-Error object');
  8. return (error.isBoom ? error : internals.initialize(error, statusCode || 500, message));
  9. };
  10. exports.create = function (statusCode, message, data) {
  11. return internals.create(statusCode, message, data, exports.create);
  12. };
  13. internals.create = function (statusCode, message, data, ctor) {
  14. var error = new Error(message ? message : undefined); // Avoids settings null message
  15. Error.captureStackTrace(error, ctor); // Filter the stack to our external API
  16. error.data = data || null;
  17. internals.initialize(error, statusCode);
  18. return error;
  19. };
  20. internals.initialize = function (error, statusCode, message) {
  21. var numberCode = parseInt(statusCode, 10);
  22. Hoek.assert(!isNaN(numberCode) && numberCode >= 400, 'First argument must be a number (400+):', statusCode);
  23. error.isBoom = true;
  24. error.isServer = numberCode >= 500;
  25. if (!error.hasOwnProperty('data')) {
  26. error.data = null;
  27. }
  28. error.output = {
  29. statusCode: numberCode,
  30. payload: {},
  31. headers: {}
  32. };
  33. error.reformat = internals.reformat;
  34. error.reformat();
  35. if (!message &&
  36. !error.message) {
  37. message = error.output.payload.error;
  38. }
  39. if (message) {
  40. error.message = (message + (error.message ? ': ' + error.message : ''));
  41. }
  42. return error;
  43. };
  44. internals.reformat = function () {
  45. this.output.payload.statusCode = this.output.statusCode;
  46. this.output.payload.error = Http.STATUS_CODES[this.output.statusCode] || 'Unknown';
  47. if (this.output.statusCode === 500) {
  48. this.output.payload.message = 'An internal server error occurred'; // Hide actual error from user
  49. }
  50. else if (this.message) {
  51. this.output.payload.message = this.message;
  52. }
  53. };
  54. // 4xx Client Errors
  55. exports.badRequest = function (message, data) {
  56. return internals.create(400, message, data, exports.badRequest);
  57. };
  58. exports.unauthorized = function (message, scheme, attributes) { // Or function (message, wwwAuthenticate[])
  59. var err = internals.create(401, message, undefined, exports.unauthorized);
  60. if (!scheme) {
  61. return err;
  62. }
  63. var wwwAuthenticate = '';
  64. var i = 0;
  65. var il = 0;
  66. if (typeof scheme === 'string') {
  67. // function (message, scheme, attributes)
  68. wwwAuthenticate = scheme;
  69. if (attributes || message) {
  70. err.output.payload.attributes = {};
  71. }
  72. if (attributes) {
  73. var names = Object.keys(attributes);
  74. for (i = 0, il = names.length; i < il; ++i) {
  75. var name = names[i];
  76. if (i) {
  77. wwwAuthenticate += ',';
  78. }
  79. var value = attributes[name];
  80. if (value === null ||
  81. value === undefined) { // Value can be zero
  82. value = '';
  83. }
  84. wwwAuthenticate += ' ' + name + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"';
  85. err.output.payload.attributes[name] = value;
  86. }
  87. }
  88. if (message) {
  89. if (attributes) {
  90. wwwAuthenticate += ',';
  91. }
  92. wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(message) + '"';
  93. err.output.payload.attributes.error = message;
  94. }
  95. else {
  96. err.isMissing = true;
  97. }
  98. }
  99. else {
  100. // function (message, wwwAuthenticate[])
  101. var wwwArray = scheme;
  102. for (i = 0, il = wwwArray.length; i < il; ++i) {
  103. if (i) {
  104. wwwAuthenticate += ', ';
  105. }
  106. wwwAuthenticate += wwwArray[i];
  107. }
  108. }
  109. err.output.headers['WWW-Authenticate'] = wwwAuthenticate;
  110. return err;
  111. };
  112. exports.forbidden = function (message, data) {
  113. return internals.create(403, message, data, exports.forbidden);
  114. };
  115. exports.notFound = function (message, data) {
  116. return internals.create(404, message, data, exports.notFound);
  117. };
  118. exports.methodNotAllowed = function (message, data) {
  119. return internals.create(405, message, data, exports.methodNotAllowed);
  120. };
  121. exports.notAcceptable = function (message, data) {
  122. return internals.create(406, message, data, exports.notAcceptable);
  123. };
  124. exports.proxyAuthRequired = function (message, data) {
  125. return internals.create(407, message, data, exports.proxyAuthRequired);
  126. };
  127. exports.clientTimeout = function (message, data) {
  128. return internals.create(408, message, data, exports.clientTimeout);
  129. };
  130. exports.conflict = function (message, data) {
  131. return internals.create(409, message, data, exports.conflict);
  132. };
  133. exports.resourceGone = function (message, data) {
  134. return internals.create(410, message, data, exports.resourceGone);
  135. };
  136. exports.lengthRequired = function (message, data) {
  137. return internals.create(411, message, data, exports.lengthRequired);
  138. };
  139. exports.preconditionFailed = function (message, data) {
  140. return internals.create(412, message, data, exports.preconditionFailed);
  141. };
  142. exports.entityTooLarge = function (message, data) {
  143. return internals.create(413, message, data, exports.entityTooLarge);
  144. };
  145. exports.uriTooLong = function (message, data) {
  146. return internals.create(414, message, data, exports.uriTooLong);
  147. };
  148. exports.unsupportedMediaType = function (message, data) {
  149. return internals.create(415, message, data, exports.unsupportedMediaType);
  150. };
  151. exports.rangeNotSatisfiable = function (message, data) {
  152. return internals.create(416, message, data, exports.rangeNotSatisfiable);
  153. };
  154. exports.expectationFailed = function (message, data) {
  155. return internals.create(417, message, data, exports.expectationFailed);
  156. };
  157. exports.badData = function (message, data) {
  158. return internals.create(422, message, data, exports.badData);
  159. };
  160. exports.preconditionRequired = function (message, data) {
  161. return internals.create(428, message, data, exports.preconditionRequired);
  162. };
  163. exports.tooManyRequests = function (message, data) {
  164. return internals.create(429, message, data, exports.tooManyRequests);
  165. };
  166. // 5xx Server Errors
  167. exports.internal = function (message, data, statusCode) {
  168. return internals.serverError(message, data, statusCode, exports.internal);
  169. };
  170. internals.serverError = function (message, data, statusCode, ctor) {
  171. var error;
  172. if (data instanceof Error) {
  173. error = exports.wrap(data, statusCode, message);
  174. } else {
  175. error = internals.create(statusCode || 500, message, undefined, ctor);
  176. error.data = data;
  177. }
  178. return error;
  179. };
  180. exports.notImplemented = function (message, data) {
  181. return internals.serverError(message, data, 501, exports.notImplemented);
  182. };
  183. exports.badGateway = function (message, data) {
  184. return internals.serverError(message, data, 502, exports.badGateway);
  185. };
  186. exports.serverTimeout = function (message, data) {
  187. return internals.serverError(message, data, 503, exports.serverTimeout);
  188. };
  189. exports.gatewayTimeout = function (message, data) {
  190. return internals.serverError(message, data, 504, exports.gatewayTimeout);
  191. };
  192. exports.badImplementation = function (message, data) {
  193. var err = internals.serverError(message, data, 500, exports.badImplementation);
  194. err.isDeveloperError = true;
  195. return err;
  196. };