Content-Length header missing when Content-Type present

I’ve noticed that when I set the Content-Type header on a response, the Content-Length value is missing. I’m experiencing this using Wrangler, e.g. wrangler dev src/index.ts

// src/index.ts
export interface Env {}

export default {
  async fetch(
    request: Request,
    env: Env,
    ctx: ExecutionContext
  ): Promise<Response> {
    const headers: Record<string, string> = {
      "content-length": "987654321",
    };

    if (request.url.endsWith("json")) {
      headers["content-type"] = "application/json";
    }

    return new Response(null, {
      headers,
    });
  },
};

Some example responses:

➤ curl --head http://localhost:56541/foo
HTTP/1.1 200 OK
date: Sun, 02 Oct 2022 05:11:52 GMT
content-length: 987654321
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=7bZuv7ewZ5%2FpV2X%2B3EG5B%2BZ6gnwdF%2FARpUlQrGeDRT%2BVTKZxjdSNdx3lv0CYCvWcZ4WFGVuKhQEwfK5x0moihNb%2FCWgBrPPkaJQBSdBR9fVo%2FzYb%2B60IQezUJXaaWH2wwm7DVbzzvvWY5dWoabn0e6dCBct3PtB5OQ0JZgpT9DW2"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
vary: Accept-Encoding
cf-ray: 753af09b9d5061f6-YVR
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
server: cloudflare
Connection: keep-alive
Keep-Alive: timeout=5

➤ curl --head http://localhost:56541/foo.json
HTTP/1.1 200 OK
date: Sun, 02 Oct 2022 05:11:54 GMT
content-type: application/json
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=jPExiF%2Fm8%2B8K4JoqoFnD2hit%2BodQqCaTvTGPBsWwLOzxOAIKCAbK8OFeA1TJAOY5GjHqIA9o%2F%2FgNepHPkQkoCmenLpUOiB%2FMH%2B7e%2BL5g4qPzhQ2utbXnKKk2V53uBESLWs9DDj4iyZHkk13rxJemGcuAT7lqmBh2biufqnMgEjmG"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
vary: Accept-Encoding
cf-ray: 753af0a5edd961f6-YVR
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
server: cloudflare
Connection: keep-alive
Keep-Alive: timeout=5

Any ideas as to why this is? Having the Content-Length header present during local development is critical to integrate my API with downstream services.

Thanks.


Possibly related:

Hi @anthonylukach

Running wrangler dev --local, and not wrangler dev does include both headers, e.g.

% curl -I localhost:8787/foo.json
HTTP/1.1 200 OK
content-type: application/json
content-length: 987654321
Date: Mon, 03 Oct 2022 21:22:51 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Other than that having actual data (even if null is returned) works too e.g.

const jsonData = '{"foo":"bar"}'

// src/index.ts
export interface Env {}

export default {
  async fetch(
    request: Request,
    env: Env,
    // ctx: ExecutionContext
  ): Promise<Response> {
    const headers: Record<string, string> = {
      "content-length": `${jsonData.length}`,
    };

    if (request.url.endsWith("json")) {
      headers["content-type"] = "application/json";
    }

    return new Response(null, {
      headers,
    });
  },
};

This works in both with --local and without.

1 Like

Thanks @the!

Running wrangler dev --local, and not wrangler dev does include both headers

You’re correct that this problem does not occur when running --local mode. This is an acceptable workaround for me at the time.

Other than that having actual data (even if null is returned) works too e.g.

However, in this situation, I think you inadvertently pointed out a strange aspect of the bug. Whether you derive the content-length value from real data or not is immaterial (it’s all a string at the end of the day). What you illustrated is that the content-length only gets returned (in non-local mode) when the value is less than 48. Take a look at this:

// src/index.ts
export default {
  async fetch(request: Request): Promise<Response> {
    const headers: Record<string, string> = {
      "content-length": request.url.split("/").pop() || "",
      "content-type": "text/plain",
    };

    return new Response(null, {
      headers,
    });
  },
};
➤ curl --head http://localhost:8787/47
HTTP/1.1 200 OK
date: Mon, 03 Oct 2022 22:51:20 GMT
content-type: text/plain
content-length: 47
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=WFyftbBvpvA66WFEIr3FN2hulbjikWNneDsyb0BztMzZnfqJX8R8d5jP%2BtMI8r%2Fz9%2FbnGut6nfCttUOye9vxu7GRWFiAWVsvwo6jW50KkuRVCA9WnPQEUPqjpdFduSew4WTyz6HXmIrLfCE7308dXgStAfGIAfTcnYl56ywkZP0Y"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
vary: Accept-Encoding
cf-ray: 75493debbba0f4aa-YVR
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
server: cloudflare
Connection: keep-alive
Keep-Alive: timeout=5

➤ curl --head http://localhost:8787/48
HTTP/1.1 200 OK
date: Mon, 03 Oct 2022 22:51:22 GMT
content-type: text/plain
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=5d0qo8CEj%2FBxc0fZyFvmpiuaFT3ciQxo9Qo1m6uPUG1tdlRtI2jKKfXWKK3BmC0L7LPbXNxSKvayJRiQRQjeUH6e3BoMmEM5fMHhPoHvG2a75eixaDQ5XA3ElIsIAkcRVhyxZzR9R5sc5ZiOO7No4faarxwdlLRJm%2Bt9xRPGX84J"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
vary: Accept-Encoding
cf-ray: 75493df98b3bf4aa-YVR
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
server: cloudflare
Connection: keep-alive
Keep-Alive: timeout=5

I still think that this is a bug but can consider this solved for my needs. Any future readers can continue to track this in the following Github repo issue: https://github.com/cloudflare/wrangler/issues/2317

1 Like

Interesting @anthonylukach

I notice you opened the issue on the Wrangler v1 repository, not the Wrangler v2 repository. Are you using v1 or v2? (I’m using v2.)

1 Like

Good catch, I was not aware that v2 was managed in a separate repo. Now tracking this issue in https://github.com/cloudflare/wrangler2/issues/1972

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.