response-error.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 'use strict'
  2. const { parseHeaders } = require('../core/util')
  3. const DecoratorHandler = require('../handler/decorator-handler')
  4. const { ResponseError } = require('../core/errors')
  5. class Handler extends DecoratorHandler {
  6. #handler
  7. #statusCode
  8. #contentType
  9. #decoder
  10. #headers
  11. #body
  12. constructor (opts, { handler }) {
  13. super(handler)
  14. this.#handler = handler
  15. }
  16. onConnect (abort) {
  17. this.#statusCode = 0
  18. this.#contentType = null
  19. this.#decoder = null
  20. this.#headers = null
  21. this.#body = ''
  22. return this.#handler.onConnect(abort)
  23. }
  24. onHeaders (statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
  25. this.#statusCode = statusCode
  26. this.#headers = headers
  27. this.#contentType = headers['content-type']
  28. if (this.#statusCode < 400) {
  29. return this.#handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
  30. }
  31. if (this.#contentType === 'application/json' || this.#contentType === 'text/plain') {
  32. this.#decoder = new TextDecoder('utf-8')
  33. }
  34. }
  35. onData (chunk) {
  36. if (this.#statusCode < 400) {
  37. return this.#handler.onData(chunk)
  38. }
  39. this.#body += this.#decoder?.decode(chunk, { stream: true }) ?? ''
  40. }
  41. onComplete (rawTrailers) {
  42. if (this.#statusCode >= 400) {
  43. this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? ''
  44. if (this.#contentType === 'application/json') {
  45. try {
  46. this.#body = JSON.parse(this.#body)
  47. } catch {
  48. // Do nothing...
  49. }
  50. }
  51. let err
  52. const stackTraceLimit = Error.stackTraceLimit
  53. Error.stackTraceLimit = 0
  54. try {
  55. err = new ResponseError('Response Error', this.#statusCode, this.#headers, this.#body)
  56. } finally {
  57. Error.stackTraceLimit = stackTraceLimit
  58. }
  59. this.#handler.onError(err)
  60. } else {
  61. this.#handler.onComplete(rawTrailers)
  62. }
  63. }
  64. onError (err) {
  65. this.#handler.onError(err)
  66. }
  67. }
  68. module.exports = (dispatch) => (opts, handler) => opts.throwOnError
  69. ? dispatch(opts, new Handler(opts, { handler }))
  70. : dispatch(opts, handler)