87 lines
2.1 KiB
JavaScript
87 lines
2.1 KiB
JavaScript
'use strict'
|
|
|
|
const { parseHeaders } = require('../core/util')
|
|
const DecoratorHandler = require('../handler/decorator-handler')
|
|
const { ResponseError } = require('../core/errors')
|
|
|
|
class Handler extends DecoratorHandler {
|
|
#handler
|
|
#statusCode
|
|
#contentType
|
|
#decoder
|
|
#headers
|
|
#body
|
|
|
|
constructor (opts, { handler }) {
|
|
super(handler)
|
|
this.#handler = handler
|
|
}
|
|
|
|
onConnect (abort) {
|
|
this.#statusCode = 0
|
|
this.#contentType = null
|
|
this.#decoder = null
|
|
this.#headers = null
|
|
this.#body = ''
|
|
|
|
return this.#handler.onConnect(abort)
|
|
}
|
|
|
|
onHeaders (statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
|
|
this.#statusCode = statusCode
|
|
this.#headers = headers
|
|
this.#contentType = headers['content-type']
|
|
|
|
if (this.#statusCode < 400) {
|
|
return this.#handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
|
|
}
|
|
|
|
if (this.#contentType === 'application/json' || this.#contentType === 'text/plain') {
|
|
this.#decoder = new TextDecoder('utf-8')
|
|
}
|
|
}
|
|
|
|
onData (chunk) {
|
|
if (this.#statusCode < 400) {
|
|
return this.#handler.onData(chunk)
|
|
}
|
|
|
|
this.#body += this.#decoder?.decode(chunk, { stream: true }) ?? ''
|
|
}
|
|
|
|
onComplete (rawTrailers) {
|
|
if (this.#statusCode >= 400) {
|
|
this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? ''
|
|
|
|
if (this.#contentType === 'application/json') {
|
|
try {
|
|
this.#body = JSON.parse(this.#body)
|
|
} catch {
|
|
// Do nothing...
|
|
}
|
|
}
|
|
|
|
let err
|
|
const stackTraceLimit = Error.stackTraceLimit
|
|
Error.stackTraceLimit = 0
|
|
try {
|
|
err = new ResponseError('Response Error', this.#statusCode, this.#headers, this.#body)
|
|
} finally {
|
|
Error.stackTraceLimit = stackTraceLimit
|
|
}
|
|
|
|
this.#handler.onError(err)
|
|
} else {
|
|
this.#handler.onComplete(rawTrailers)
|
|
}
|
|
}
|
|
|
|
onError (err) {
|
|
this.#handler.onError(err)
|
|
}
|
|
}
|
|
|
|
module.exports = (dispatch) => (opts, handler) => opts.throwOnError
|
|
? dispatch(opts, new Handler(opts, { handler }))
|
|
: dispatch(opts, handler)
|