aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/undici/lib/api/util.js
blob: 2f983bf424c705909b3da58332ee5332dbe3bbe7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
const assert = require('node:assert')
const {
  ResponseStatusCodeError
} = require('../core/errors')

const { chunksDecode } = require('./readable')
const CHUNK_LIMIT = 128 * 1024

async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) {
  assert(body)

  let chunks = []
  let length = 0

  try {
    for await (const chunk of body) {
      chunks.push(chunk)
      length += chunk.length
      if (length > CHUNK_LIMIT) {
        chunks = []
        length = 0
        break
      }
    }
  } catch {
    chunks = []
    length = 0
    // Do nothing....
  }

  const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`

  if (statusCode === 204 || !contentType || !length) {
    queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers)))
    return
  }

  const stackTraceLimit = Error.stackTraceLimit
  Error.stackTraceLimit = 0
  let payload

  try {
    if (isContentTypeApplicationJson(contentType)) {
      payload = JSON.parse(chunksDecode(chunks, length))
    } else if (isContentTypeText(contentType)) {
      payload = chunksDecode(chunks, length)
    }
  } catch {
    // process in a callback to avoid throwing in the microtask queue
  } finally {
    Error.stackTraceLimit = stackTraceLimit
  }
  queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers, payload)))
}

const isContentTypeApplicationJson = (contentType) => {
  return (
    contentType.length > 15 &&
    contentType[11] === '/' &&
    contentType[0] === 'a' &&
    contentType[1] === 'p' &&
    contentType[2] === 'p' &&
    contentType[3] === 'l' &&
    contentType[4] === 'i' &&
    contentType[5] === 'c' &&
    contentType[6] === 'a' &&
    contentType[7] === 't' &&
    contentType[8] === 'i' &&
    contentType[9] === 'o' &&
    contentType[10] === 'n' &&
    contentType[12] === 'j' &&
    contentType[13] === 's' &&
    contentType[14] === 'o' &&
    contentType[15] === 'n'
  )
}

const isContentTypeText = (contentType) => {
  return (
    contentType.length > 4 &&
    contentType[4] === '/' &&
    contentType[0] === 't' &&
    contentType[1] === 'e' &&
    contentType[2] === 'x' &&
    contentType[3] === 't'
  )
}

module.exports = {
  getResolveErrorBodyCallback,
  isContentTypeApplicationJson,
  isContentTypeText
}