atatus-nodejs
Version:
Atatus APM agent for Node.js
170 lines (149 loc) • 3.75 kB
JavaScript
'use strict'
var _MAX_HTTP_BODY_CHARS = 20480 // expose for testing purposes
function totalChunkLength(chunk1, chunk2) {
var length1 = chunk1 ? chunk1.length || 0 : 0
var length2 = chunk2 ? chunk2.length || 0 : 0
return length1 + length2
}
function appendChunk(buf, chunk) {
if (chunk) {
if (Buffer.isBuffer(chunk)) {
try {
return buf ? Buffer.concat([buf, chunk]) : Buffer.from(chunk)
} catch (err) {
return buf
}
} else if (typeof chunk === 'string') {
try {
return buf
? Buffer.concat([buf, Buffer.from(chunk)])
: Buffer.from(chunk)
} catch (err) {
return buf
}
} else if (typeof chunk === 'object' || Array.isArray(chunk)) {
try {
return buf
? Buffer.concat([buf, Buffer.from(JSON.stringify(chunk))])
: Buffer.from(JSON.stringify(chunk))
} catch (err) {
return buf
}
} else {
// console.error('body chunk is not a Buffer or String.')
return buf
}
}
return buf
}
function bodyToBase64(body) {
if (!body) {
return body
}
if (body === 'BODY_SIZE_EXCEEDED') {
return body
}
if (Buffer.isBuffer(body)) {
return body.toString('base64')
} else if (typeof body === 'string') {
return Buffer.from(body).toString('base64')
} else if (typeof body.toString === 'function') {
return Buffer.from(body.toString()).toString('base64')
} else {
return ''
}
}
function getResponseBodyString(body, isCompresssed) {
try {
if (!body) {
return body
}
var result
var length
if (isCompresssed) {
length = body.length
result = bodyToBase64(body)
} else if (!Buffer.isBuffer(body) && typeof body === 'object') {
// in case of non POJO
result = JSON.stringify(body)
length = result.length
} else {
result = body.toString()
length = result.length
}
if (result === 'BODY_SIZE_EXCEEDED' || length > _MAX_HTTP_BODY_CHARS) {
result = isCompresssed ? null : 'The response body has exceeded the maximum allowed size.'
}
return result;
} catch (e) {
return 'Error: Unable to access the body.'
}
}
function decodeHeaders(header) {
try {
var keyVal = header.split('\r\n')
// Remove Request Line or Status Line
keyVal.shift()
var obj = {}
var i
for (i in keyVal) {
keyVal[i] = keyVal[i].split(':', 2)
if (keyVal[i].length != 2) {
continue
}
obj[keyVal[i][0].trim()] = keyVal[i][1].trim()
}
return obj
} catch (err) {
return {}
}
}
function getResponseHeaders(res) {
try {
if (res.getHeaders) {
return res.getHeaders()
}
try {
// access ._headers will result in exception
// in some versions fo node.
// so must be in try block.
if (res._headers) {
return res._headers
}
} catch (err) {
}
return res.headers || decodeHeaders(res._header)
} catch(err) {
return {}
}
}
function getSafeHost (req) {
try {
if (req.getHeader) {
return req.getHeader('Host')
}
if (req._headers) {
return req._headers.host
}
return ''
} catch (err) {
return ''
}
}
async function eachLimit(items, fn, limit) {
const results = []
while (items.length) {
const resolved = await Promise.all(items.splice(0, limit).map(fn))
results.push(...resolved)
}
return results
}
module.exports = {
_MAX_HTTP_BODY_CHARS: _MAX_HTTP_BODY_CHARS,
totalChunkLength: totalChunkLength,
appendChunk: appendChunk,
getResponseBodyString: getResponseBodyString,
getResponseHeaders: getResponseHeaders,
getSafeHost: getSafeHost,
asyncEachLimit: eachLimit
}