util.js 2.3 KB

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