util.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. const assert = require('node:assert')
  2. const {
  3. ResponseStatusCodeError
  4. } = require('../core/errors')
  5. const { chunksDecode } = require('./readable')
  6. const CHUNK_LIMIT = 128 * 1024
  7. async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) {
  8. assert(body)
  9. let chunks = []
  10. let length = 0
  11. try {
  12. for await (const chunk of body) {
  13. chunks.push(chunk)
  14. length += chunk.length
  15. if (length > CHUNK_LIMIT) {
  16. chunks = []
  17. length = 0
  18. break
  19. }
  20. }
  21. } catch {
  22. chunks = []
  23. length = 0
  24. // Do nothing....
  25. }
  26. const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`
  27. if (statusCode === 204 || !contentType || !length) {
  28. queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers)))
  29. return
  30. }
  31. const stackTraceLimit = Error.stackTraceLimit
  32. Error.stackTraceLimit = 0
  33. let payload
  34. try {
  35. if (isContentTypeApplicationJson(contentType)) {
  36. payload = JSON.parse(chunksDecode(chunks, length))
  37. } else if (isContentTypeText(contentType)) {
  38. payload = chunksDecode(chunks, length)
  39. }
  40. } catch {
  41. // process in a callback to avoid throwing in the microtask queue
  42. } finally {
  43. Error.stackTraceLimit = stackTraceLimit
  44. }
  45. queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers, payload)))
  46. }
  47. const isContentTypeApplicationJson = (contentType) => {
  48. return (
  49. contentType.length > 15 &&
  50. contentType[11] === '/' &&
  51. contentType[0] === 'a' &&
  52. contentType[1] === 'p' &&
  53. contentType[2] === 'p' &&
  54. contentType[3] === 'l' &&
  55. contentType[4] === 'i' &&
  56. contentType[5] === 'c' &&
  57. contentType[6] === 'a' &&
  58. contentType[7] === 't' &&
  59. contentType[8] === 'i' &&
  60. contentType[9] === 'o' &&
  61. contentType[10] === 'n' &&
  62. contentType[12] === 'j' &&
  63. contentType[13] === 's' &&
  64. contentType[14] === 'o' &&
  65. contentType[15] === 'n'
  66. )
  67. }
  68. const isContentTypeText = (contentType) => {
  69. return (
  70. contentType.length > 4 &&
  71. contentType[4] === '/' &&
  72. contentType[0] === 't' &&
  73. contentType[1] === 'e' &&
  74. contentType[2] === 'x' &&
  75. contentType[3] === 't'
  76. )
  77. }
  78. module.exports = {
  79. getResolveErrorBodyCallback,
  80. isContentTypeApplicationJson,
  81. isContentTypeText
  82. }