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