klaemo opened a new issue, #375:
URL: https://github.com/apache/couchdb-nano/issues/375

   ## Expected Behavior
   
   If the connection breaks off after CouchDB (or a proxy in front of it) has 
sent the response headers but before the body is complete, the request promise 
should reject. nano 10 (axios) did this.
   
   ## Current Behavior
   
   In nano 11 the result depends on the response's content type:
   
   - **`application/json`** (e.g. `db.get`, `db.list`, `db.view`): the request 
**resolves with `''`**. `responseHandler` in `lib/nano.js` wraps `await 
response.json()` in `try { … } catch { // do nothing }`. That catch was meant 
for bodies that aren't valid JSON, but it also catches undici's `TypeError: 
terminated` when the body read fails. So `db.get()` of an existing document 
resolves `""`. Callers see something like a missing document, crash later with 
a `TypeError`, or, worst case, write `{ ...doc }` with `doc === ''` back as a 
new document.
   - **`text/*`, `multipart/related` and binary bodies** (e.g. 
`db.attachment.get`): `response.text()` / `response.arrayBuffer()` throws 
inside the async `responseHandler`. `relax()` doesn't await or return it 
(`.then((response) => { responseHandler(…) })`), so the request promise **never 
settles**. The rejection is unhandled, which crashes the process under Node's 
default `--unhandled-rejections=throw`; if the app has an `unhandledRejection` 
handler, the call just hangs.
   
   Error responses (non-2xx) aren't affected: if reading the error body fails, 
the request still rejects with the status code. Streaming requests 
(`*AsStream`) take a separate code path.
   
   ## Possible Solution
   
   1. In the 2xx JSON branch, read the body with `response.text()` and only 
wrap `JSON.parse()` in the try/catch. A failed read then propagates, and a 
complete body that isn't JSON still resolves `''` as it does today.
   2. In `relax()`, return the `responseHandler(…)` promise from the `.then()` 
callback so that the existing `.catch()` handles failures. A body-read failure 
then rejects the same way a connection failure before the headers does: `error 
happened in your connection. Reason: SocketError: other side closed`.
   
   I have a patch with tests ready and will open a PR referencing this issue.
   
   ## Steps to Reproduce (for bugs)
   
   1. Save this as `repro.js` next to an install of `[email protected]`:
   
      ```js
      const http = require('node:http')
      const Nano = require('nano')
      const contentType = process.argv[2] || 'application/json'
   
      // answer 200, promise 100 bytes, send part of a document, then drop the 
connection
      const server = http.createServer((req, res) => {
        res.writeHead(200, { 'content-type': contentType, 'content-length': 100 
})
        res.write('{"_id":"meta","type":"ev')
        setTimeout(() => res.socket.destroy(), 10)
      })
   
      server.listen(0, '127.0.0.1', async () => {
        const db = Nano(`http://127.0.0.1:${server.address().port}`).use('db')
        try {
          console.log('resolved:', JSON.stringify(await db.get('meta')))
        } catch (e) {
          console.log('rejected:', e.message)
        }
        server.closeAllConnections()
        server.close()
      })
      ```
   
   2. `node repro.js` prints `resolved: ""`.
   3. `node repro.js text/plain` crashes with an unhandled `TypeError: 
terminated` (`[cause]: SocketError: other side closed`). `db.get()` never 
settles.
   4. Expected in both cases: `rejected: …`.
   
   ## Context
   
   I found this while upgrading an app from nano 10 to 11. On a dropped 
connection, a `db.get()` of an existing document returned `""` instead of 
throwing, and the app treated the document as missing. We're carrying a local 
patch for now.
   
   ## Your Environment
   
   * Version used: nano 11.0.7 (also current `main`, 53dea92)
   * Node.js: 24.21.0 (also reproduced on 20.20.2)
   * Operating System and version: Ubuntu 24.04 (Linux 6.8)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to