@@ -21,1 +21,44 @@ # Writing tests | ||
| ``` | ||
| ## Guarding against unexpected disconnects | ||
| Undici's `Client` automatically reconnects after a socket error. This means | ||
| a test can silently disconnect, reconnect, and still pass. Unfortunately, | ||
| this could mask bugs like unexpected parser errors or protocol violations. | ||
| To catch these silent reconnections, add a disconnect guard after creating | ||
| a `Client`: | ||
| ```js | ||
| const { Client } = require('undici') | ||
| const { test, after } = require('node:test') | ||
| const { tspl } = require('@matteo.collina/tspl') | ||
| test('example with disconnect guard', async (t) => { | ||
| t = tspl(t, { plan: 1 }) | ||
| const client = new Client('http://localhost:3000') | ||
| after(() => client.close()) | ||
| client.on('disconnect', () => { | ||
| if (!client.closed && !client.destroyed) { | ||
| t.fail('unexpected disconnect') | ||
| } | ||
| }) | ||
| // ... test logic ... | ||
| }) | ||
| ``` | ||
| `client.close()` and `client.destroy()` both emit `'disconnect'` events, but | ||
| those are expected. The guard only fails when a disconnect happens during the | ||
| active test (i.e., `!client.closed && !client.destroyed` is true). | ||
| Skip the guard for tests where a disconnect is expected behavior, such as: | ||
| - Signal aborts (`signal.emit('abort')`, `ac.abort()`) | ||
| - Server-side destruction (`res.destroy()`, `req.socket.destroy()`) | ||
| - Client-side body destruction mid-stream (`data.body.destroy()`) | ||
| - Timeout errors (`HeadersTimeoutError`, `BodyTimeoutError`) | ||
| - Successful upgrades (the socket is detached from the `Client`) | ||
| - Retry/reconnect tests where the disconnect triggers the retry | ||
| - HTTP parser errors from malformed responses (`HTTPParserError`) |
@@ -496,6 +496,14 @@ 'use strict' | ||
| if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity) { | ||
| if (cacheControlDirectives.immutable && staleWhileRevalidate === -Infinity && staleIfError === -Infinity) { | ||
| immutable = now + 31536000000 | ||
| } | ||
| // When no stale directives or immutable flag, add a revalidation buffer | ||
| // equal to the freshness lifetime so the entry survives past staleAt long | ||
| // enough to be revalidated instead of silently disappearing. | ||
| if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity && immutable === -Infinity) { | ||
| const freshnessLifetime = staleAt - now | ||
| return staleAt + freshnessLifetime | ||
| } | ||
| return Math.max(staleAt, staleWhileRevalidate, staleIfError, immutable) | ||
@@ -502,0 +510,0 @@ } |
@@ -9,6 +9,6 @@ 'use strict' | ||
| const { isomorphicDecode } = require('../infra') | ||
| const { utf8DecodeBytes } = require('../../encoding') | ||
| const dd = Buffer.from('--') | ||
| const decoder = new TextDecoder() | ||
| const decoderIgnoreBOM = new TextDecoder('utf-8', { ignoreBOM: true }) | ||
@@ -192,3 +192,3 @@ /** | ||
| // 5.11.1. Let value be the UTF-8 decoding without BOM of body. | ||
| value = utf8DecodeBytes(Buffer.from(body)) | ||
| value = decoderIgnoreBOM.decode(Buffer.from(body)) | ||
| } | ||
@@ -195,0 +195,0 @@ |
+1
-1
| { | ||
| "name": "undici", | ||
| "version": "7.24.4", | ||
| "version": "7.24.5", | ||
| "description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -5,0 +5,0 @@ "homepage": "https://undici.nodejs.org", |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 9 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 9 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1600945
0.13%33984
0.02%