Aktueller Stand

This commit is contained in:
2026-01-22 19:05:45 +01:00
parent 85dee61a4d
commit e280e4eadb
1967 changed files with 397327 additions and 74093 deletions

View File

@@ -1,7 +1,7 @@
'use strict'
const http = require('node:http')
const { Writable, Readable } = require('node:stream')
const { Writable, Readable, addAbortSignal } = require('node:stream')
const util = require('node:util')
const setCookie = require('set-cookie-parser')
@@ -9,7 +9,17 @@ const setCookie = require('set-cookie-parser')
function Response (req, onEnd, reject) {
http.ServerResponse.call(this, req)
this._lightMyRequest = { headers: null, trailers: {}, payloadChunks: [] }
if (req._lightMyRequest?.payloadAsStream) {
const read = this.emit.bind(this, 'drain')
this._lightMyRequest = { headers: null, trailers: {}, stream: new Readable({ read }) }
const signal = req._lightMyRequest.signal
if (signal) {
addAbortSignal(signal, this._lightMyRequest.stream)
}
} else {
this._lightMyRequest = { headers: null, trailers: {}, payloadChunks: [] }
}
// This forces node@8 to always render the headers
this.setHeader('foo', 'bar'); this.removeHeader('foo')
@@ -19,28 +29,51 @@ function Response (req, onEnd, reject) {
let called = false
const onEndSuccess = (payload) => {
// no need to early-return if already called because this handler is bound `once`
if (called) return
called = true
if (this._promiseCallback) {
return process.nextTick(() => onEnd(payload))
}
process.nextTick(() => onEnd(null, payload))
}
this._lightMyRequest.onEndSuccess = onEndSuccess
let finished = false
const onEndFailure = (err) => {
if (called) return
if (called) {
if (this._lightMyRequest.stream && !finished) {
if (!err) {
err = new Error('response destroyed before completion')
err.code = 'LIGHT_ECONNRESET'
}
this._lightMyRequest.stream.destroy(err)
this._lightMyRequest.stream.on('error', () => {})
}
return
}
called = true
if (!err) {
err = new Error('response destroyed before completion')
err.code = 'LIGHT_ECONNRESET'
}
if (this._promiseCallback) {
return process.nextTick(() => reject(err))
}
process.nextTick(() => onEnd(err, null))
}
this.once('finish', () => {
const res = generatePayload(this)
res.raw.req = req
onEndSuccess(res)
})
if (this._lightMyRequest.stream) {
this.once('finish', () => {
finished = true
this._lightMyRequest.stream.push(null)
})
} else {
this.once('finish', () => {
const res = generatePayload(this)
res.raw.req = req
onEndSuccess(res)
})
}
this.connection.once('error', onEndFailure)
@@ -64,6 +97,10 @@ Response.prototype.writeHead = function () {
copyHeaders(this)
if (this._lightMyRequest.stream) {
this._lightMyRequest.onEndSuccess(generatePayload(this))
}
return result
}
@@ -72,8 +109,12 @@ Response.prototype.write = function (data, encoding, callback) {
clearTimeout(this.timeoutHandle)
}
http.ServerResponse.prototype.write.call(this, data, encoding, callback)
this._lightMyRequest.payloadChunks.push(Buffer.from(data, encoding))
return true
if (this._lightMyRequest.stream) {
return this._lightMyRequest.stream.push(Buffer.from(data, encoding))
} else {
this._lightMyRequest.payloadChunks.push(Buffer.from(data, encoding))
return true
}
}
Response.prototype.end = function (data, encoding, callback) {
@@ -110,7 +151,7 @@ Response.prototype.addTrailers = function (trailers) {
function generatePayload (response) {
// This seems only to happen when using `fastify-express` - see https://github.com/fastify/fastify-express/issues/47
/* istanbul ignore if */
/* c8 ignore next 3 */
if (response._lightMyRequest.headers === null) {
copyHeaders(response)
}
@@ -129,22 +170,32 @@ function generatePayload (response) {
}
}
// Prepare payload and trailers
const rawBuffer = Buffer.concat(response._lightMyRequest.payloadChunks)
res.rawPayload = rawBuffer
// we keep both of them for compatibility reasons
res.payload = rawBuffer.toString()
res.body = res.payload
res.trailers = response._lightMyRequest.trailers
// Prepare payload parsers
res.json = function parseJsonPayload () {
return JSON.parse(res.payload)
if (response._lightMyRequest.payloadChunks) {
// Prepare payload and trailers
const rawBuffer = Buffer.concat(response._lightMyRequest.payloadChunks)
res.rawPayload = rawBuffer
// we keep both of them for compatibility reasons
res.payload = rawBuffer.toString()
res.body = res.payload
// Prepare payload parsers
res.json = function parseJsonPayload () {
return JSON.parse(res.payload)
}
} else {
res.json = function () {
throw new Error('Response payload is not available with payloadAsStream: true')
}
}
// Provide stream Readable for advanced user
res.stream = function streamPayload () {
if (response._lightMyRequest.stream) {
return response._lightMyRequest.stream
}
return Readable.from(response._lightMyRequest.payloadChunks)
}
@@ -154,7 +205,7 @@ function generatePayload (response) {
// Throws away all written data to prevent response from buffering payload
function getNullSocket () {
return new Writable({
write (chunk, encoding, callback) {
write (_chunk, _encoding, callback) {
setImmediate(callback)
}
})
@@ -179,7 +230,7 @@ function copyHeaders (response) {
// Add raw headers
;['Date', 'Connection', 'Transfer-Encoding'].forEach((name) => {
const regex = new RegExp('\\r\\n' + name + ': ([^\\r]*)\\r\\n')
const field = response._header.match(regex)
const field = response._header?.match(regex)
if (field) {
response._lightMyRequest.headers[name.toLowerCase()] = field[1]
}