diff --git a/README.md b/README.md index 051a9df2dea..3ba89890df6 100644 --- a/README.md +++ b/README.md @@ -436,6 +436,7 @@ and `undici.Agent`) which will enable the family autoselection algorithm when es * [__Ethan Arrowood__](https://github.com/ethan-arrowood), * [__Matteo Collina__](https://github.com/mcollina), * [__Robert Nagy__](https://github.com/ronag), +* [__Matthew Aitken__](https://github.com/KhafraDev), ## License diff --git a/lib/core/util.js b/lib/core/util.js index 0e6197a4b29..259ba7b38a6 100644 --- a/lib/core/util.js +++ b/lib/core/util.js @@ -168,7 +168,7 @@ function bodyLength (body) { return 0 } else if (isStream(body)) { const state = body._readableState - return state && state.ended === true && Number.isFinite(state.length) + return state && state.objectMode === false && state.ended === true && Number.isFinite(state.length) ? state.length : null } else if (isBlobLike(body)) { diff --git a/lib/websocket/connection.js b/lib/websocket/connection.js index 8c821899f65..e0fa69726b4 100644 --- a/lib/websocket/connection.js +++ b/lib/websocket/connection.js @@ -1,6 +1,5 @@ 'use strict' -const { randomBytes, createHash } = require('crypto') const diagnosticsChannel = require('diagnostics_channel') const { uid, states } = require('./constants') const { @@ -22,6 +21,14 @@ channels.open = diagnosticsChannel.channel('undici:websocket:open') channels.close = diagnosticsChannel.channel('undici:websocket:close') channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error') +/** @type {import('crypto')} */ +let crypto +try { + crypto = require('crypto') +} catch { + +} + /** * @see https://websockets.spec.whatwg.org/#concept-websocket-establish * @param {URL} url @@ -66,7 +73,7 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish, options) // 5. Let keyValue be a nonce consisting of a randomly selected // 16-byte value that has been forgiving-base64-encoded and // isomorphic encoded. - const keyValue = randomBytes(16).toString('base64') + const keyValue = crypto.randomBytes(16).toString('base64') // 6. Append (`Sec-WebSocket-Key`, keyValue) to request’s // header list. @@ -148,7 +155,7 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish, options) // trailing whitespace, the client MUST _Fail the WebSocket // Connection_. const secWSAccept = response.headersList.get('Sec-WebSocket-Accept') - const digest = createHash('sha1').update(keyValue + uid).digest('base64') + const digest = crypto.createHash('sha1').update(keyValue + uid).digest('base64') if (secWSAccept !== digest) { failWebsocketConnection(ws, 'Incorrect hash received in Sec-WebSocket-Accept header.') return diff --git a/lib/websocket/frame.js b/lib/websocket/frame.js index 61bfd3915ce..d867ad118b2 100644 --- a/lib/websocket/frame.js +++ b/lib/websocket/frame.js @@ -1,15 +1,22 @@ 'use strict' -const { randomBytes } = require('crypto') const { maxUnsigned16Bit } = require('./constants') +/** @type {import('crypto')} */ +let crypto +try { + crypto = require('crypto') +} catch { + +} + class WebsocketFrameSend { /** * @param {Buffer|undefined} data */ constructor (data) { this.frameData = data - this.maskKey = randomBytes(4) + this.maskKey = crypto.randomBytes(4) } createFrame (opcode) { diff --git a/package.json b/package.json index eef22bf6a05..3846b9dc398 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "5.25.1", + "version": "5.25.2", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { diff --git a/test/content-length.js b/test/content-length.js index ecc1da34cc6..66c010a7c9e 100644 --- a/test/content-length.js +++ b/test/content-length.js @@ -300,3 +300,32 @@ test('response invalid content length with close', (t) => { }) }) }) + +test('request streaming with Readable.from(buf)', (t) => { + const server = createServer((req, res) => { + req.pipe(res) + }) + t.teardown(server.close.bind(server)) + server.listen(0, () => { + const client = new Client(`http://localhost:${server.address().port}`) + t.teardown(client.destroy.bind(client)) + + client.request({ + path: '/', + method: 'PUT', + body: Readable.from(Buffer.from('hello')) + }, (err, data) => { + const chunks = [] + t.error(err) + data.body + .on('data', (chunk) => { + chunks.push(chunk) + }) + .on('end', () => { + t.equal(Buffer.concat(chunks).toString(), 'hello') + t.pass() + t.end() + }) + }) + }) +})