Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DELETE requests add a "Content-Length: 0" header, causing undici to error "Request body length does not match content-length header" #7

Open
dan-hammond opened this issue Aug 31, 2023 · 6 comments

Comments

@dan-hammond
Copy link

Environment

  • Operating System: Darwin
  • Node Version: v20.5.1
  • Nuxt Version: 3.7.0
  • CLI Version: 3.7.2
  • Nitro Version: 2.6.2
  • Package Manager: [email protected]
  • Builder: -
  • User Config: -
  • Runtime Modules: -
  • Build Modules: -

Reproduction

I confess I haven't made one up-front. I think the explanation below might be enough, but if not I can try to figure out a reproduction.

Describe the bug

When making a DELETE request, the request has a "Content-Length: 0" header added to it, which causes Node's undici to respond with the following error:

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11576:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async sendProxy (file:///myprojectpath/node_modules/h3/dist/index.mjs:1049:20)
    at async Object.handler (file:///myprojectpath/node_modules/h3/dist/index.mjs:1646:19)
    at async Server.toNodeHandle (file:///myprojectpath/node_modules/h3/dist/index.mjs:1857:7) {
  cause: RequestContentLengthMismatchError: Request body length does not match content-length header
      at write (node:internal/deps/undici/undici:10059:41)
      at _resume (node:internal/deps/undici/undici:10037:33)
      at resume (node:internal/deps/undici/undici:9938:7)
      at [dispatch] (node:internal/deps/undici/undici:9286:11)
      at Client.Intercept (node:internal/deps/undici/undici:9017:20)
      at Client.dispatch (node:internal/deps/undici/undici:7772:44)
      at [dispatch] (node:internal/deps/undici/undici:7991:32)
      at Pool.dispatch (node:internal/deps/undici/undici:7772:44)
      at [dispatch] (node:internal/deps/undici/undici:10556:27)
      at Agent.Intercept (node:internal/deps/undici/undici:9017:20) {
    code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
  }

More context has been provided here:
nodejs/undici#2046 (comment)

Here's the same code in this fork:

* Sets `content-length` to '0' if request is of DELETE type.

This is all somewhat beyond me, but I would think it's not the responsibility of the proxy to be adding HTTP headers that weren't provided in the initial request, unless it's intentional behaviour written in middleware or proxy route rules.

I appreciate that Node may end up fixing their underlying behaviour to allow DELETE requests with a Content-Length, but that may not solve the problem for people proxying to other non-JS back-ends.

Similarly, I have read in the linked undici issue that Safari does send Content-Length: 0 with DELETE requests, so it would be useful to know how I can filter those out. I am using extendRouteRules in a Nuxt module to register my proxy rules, and am doing so as a wildcard for a whole path prefix. Is that currently possible?

Additional context

No response

Logs

No response

@pi0
Copy link
Member

pi0 commented Sep 1, 2023

Thanks for the issue. Related upstream issues http-party/node-http-proxy#1343 and nodejs/node#27880

This feature was originally introduced in http-proxy via http-party/node-http-proxy#742 as part of bug fix for nginx and chunked streaming. I will have to check it more in defails.

Anyway i think it is a valid bug if we are overriding the existing content-length.

@wug-ge
Copy link

wug-ge commented Sep 13, 2023

I'm facing the same issue using Nuxt,js routeRules proxy and my DELETE requests don't work.

Putting

delete opts.fetchOptions.headers['content-length']

before this line

https://github.com/unjs/h3/blob/12ccb81432a62783fe951a8170976c8162bce44a/src/utils/proxy.ts#L77

solves my issue, otherwise it fails with a UND_ERR_REQ_CONTENT_LENGTH_MISMATCH.

I'm haven't digged deep enough into the ecosystem to understand fully what's going on, I'd really appreciate if someone could explain further what exactly is happening / provide a workaround.

For now I might have to use a different proxy.

If wanted, I'm happy to do some digging myself. (not sure how efficient I'll be here though)

@brc-dd
Copy link

brc-dd commented Oct 31, 2023

undici fixed this in nodejs/undici#2046 , but not sure if it'll be backported to LTS. I'm using nitro.experimental.nodeFetchCompat till that fix makes to a node LTS 👀

@wug-ge
Copy link

wug-ge commented Dec 8, 2023

@brc-dd can you explain what you mean by using nitro.experimental.nodeFetchCompat?

I can't find much about it, what it is and how do I set it in my Nuxt config? 😄

I tested this issue with node 18, 20 and 21 and it persists in all versions. My current workaround is to add something random in the body of the DELETE request, which is quiet ugly...

@Denoder
Copy link

Denoder commented Jan 11, 2024

@wug-ge

export default defineNuxtConfig({
    nitro: {
        experimental: {
            nodeFetchCompat: true
        }
    }
})

@brc-dd
Copy link

brc-dd commented Jan 11, 2024

You might also need to disable built-in fetch. I'm using this kind of setup:

// package.json

  "scripts": {
    "dev": "pnpm nuxt dev",
    "build": "pnpm nuxt build",
    "generate": "pnpm nuxt generate",
    "preview": "pnpm nuxt preview",
    "postinstall": "pnpm nuxt prepare",
    "nuxt": "NODE_OPTIONS='--no-experimental-fetch' nuxt"
  }
// nuxt.config.ts

export default defineNuxtConfig({
  nitro: {
    experimental: {
      nodeFetchCompat: true
    }
  }
})

At the time I posted that comment, it was working fine just by setting in nuxt.config, but broke between some Nuxt minor IG. So you might need to add both. I have confirmed that it works fine in latest Node.js without any extra config, so probably this issue can be closed as I think this was always an upstream issue.

PS: I just read [email protected] release notes and looks like it should now work fine on latest LTS too. 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants