-
Notifications
You must be signed in to change notification settings - Fork 566
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
client.request throws Error with setEncoding #1125
Comments
Just check if elements in body are string or Buffer and concat accordingly. |
I think that mixing strings and buffers could result in data loss at chunk boundaries. Then it seems that it can be made simple. if (typeof chunk === 'str') {
chunk = Buffer.from(chunk)
} |
I think that would work. |
okey. I'll do test & create PR. |
@ronag diff --git a/lib/api/readable.js b/lib/api/readable.js
index 3bb454e..c1a80db 100644
--- a/lib/api/readable.js
+++ b/lib/api/readable.js
@@ -196,6 +196,10 @@ function consumeStart (consume) {
const { _readableState: state } = consume.stream
for (const chunk of state.buffer) {
+ if (consume.stream.readableEncoding) {
+ consumePush(consume, Buffer.from(chunk, consume.stream.readableEncoding))
+ continue
+ }
consumePush(consume, chunk)
} The first reproduction code now works with this fix. But this reproduction code doesn't work. import { createServer } from 'http'
import { Client } from 'undici'
import { once } from 'events'
import assert from 'assert'
const data = Buffer.from('あいうえお')
const server = createServer((request, response) => {
response.write(data.slice(0, 1))
setTimeout(() => {
response.write(data.slice(1))
response.end()
}, 100)
}).listen()
await once(server, 'listening')
const client = new Client(`http://localhost:${server.address().port}`)
try {
const { body, headers, statusCode } = await client.request({
path: '/',
method: 'GET'
})
console.log(`response received ${statusCode}`)
console.log('headers', headers)
body.setEncoding('utf8')
const text = await body.text()
console.log(Buffer.from(text))
console.log(Buffer.from(data))
assert.strictEqual(text, data, 'multi byte')
} catch (error) {
console.error('error!!:', error)
} finally {
client.close()
server.close()
} $ node test-first-byte.mjs
response received 200
headers {
date: 'Tue, 07 Dec 2021 05:31:38 GMT',
connection: 'keep-alive',
'keep-alive': 'timeout=5',
'transfer-encoding': 'chunked'
}
<Buffer ef bf bd ef bf bd e3 81 84 e3 81 86 e3 81 88 e3 81 8a>
<Buffer e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a>
error!!: AssertionError [ERR_ASSERTION]: multi byte
at file:///tmp/test_undici/index2.mjs:31:10
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: '��いうえお',
expected: [Buffer [Uint8Array]],
operator: 'strictEqual'
} It looks like the first few bytes are lost. So I think we need another way. |
I you open a PR with the tests then we can collaborate on it. |
OK. Thanks. |
Bug Description
client.request
throws an error whenbody.json()
&body.text()
are called withsetEncoding
.Reproducible By
Expected Behavior
Logs & Screenshots
Environment
Node.js v16.13.1
undici v4.11.0
Additional context
chunk
is converted to a string by StringDecoder only when consumeStart is executed.I think that this code needs to use
consume.stream._readableState.decoder.end()
inconsumeEnd
instead ofBuffer.concat(body)
if the value is inreadableEncoding
.Is this the right way to fix it?
I also considered a method to overwrite StringDecoder so that it is not created in setEncoding.
However, it seems that it will be difficult to upgrade because it depends too much on the structure of Stream.
Ref: #1119
CC: @mcollina
The text was updated successfully, but these errors were encountered: