Skip to content

Core Cache: a known-length cache body sent to the client is framed as chunked instead of Content-Length #747

Open

Description

@zshenker

What happens

In this case:

  • a guest streams a found Core Cache entry to the client with found.to_stream() or to_stream_from_range(..);
  • it's in automatic framing mode;
  • the entry was inserted with known_length, or has finished filling.

Here Compute sends Content-Length, and Viceroy sends Transfer-Encoding: chunked. Also, in the guest, Body::known_length() on that body returns None under Viceroy, even though Found::known_length() returns Some(5000).

Reproduction

The minimal service is below (fastly 0.13.1, wasm32-wasip1). It inserts 5000 bytes with known_length(5000), looks the entry up and sends its body to the client. It also reports both known_length values in headers.

src/main.rs
//! Streams a finished, known-length Core Cache entry to the client in automatic framing mode.

use fastly::cache::core::{insert, lookup, CacheKey};
use fastly::{Request, Response};
use std::io::Write;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

fn main() {
    let _req = Request::from_client();
    let nanos = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos();
    let key: CacheKey = format!("cache-framing-{nanos}").into_bytes().into();
    let contents = vec![b'x'; 5000];

    let mut body = insert(key.clone(), Duration::from_secs(3600))
        .known_length(contents.len() as u64)
        .execute()
        .unwrap();
    body.write_all(&contents).unwrap();
    body.finish().unwrap();

    let found = lookup(key).execute().unwrap().expect("entry should be cached");
    let mut cached = found.to_stream().unwrap();
    let body_known_length = cached.known_length();

    Response::from_body(cached)
        .with_header("x-entry-known-length", format!("{:?}", found.known_length()))
        .with_header("x-body-known-length", format!("{body_known_length:?}"))
        .send_to_client();
}

Viceroy (0.21.1, and main at 20326e4), curl -s -D - -o /dev/null http://127.0.0.1:7676/:

HTTP/1.1 200 OK
x-entry-known-length: Some(5000)
x-body-known-length: None
transfer-encoding: chunked

Compute (same wasm, curl -s --http1.1 -D - -o /dev/null, the same result on 3 runs across different DEN cache nodes):

HTTP/1.1 200
Content-Length: 5000
x-entry-known-length: Some(5000)
x-body-known-length: Some(5000)

This repro is deployed on Compute, so you can check it directly:

curl -s --http1.1 -D - -o /dev/null https://factually-capable-herring.edgecompute.app/

Parity suite

compute-sdk-integration-tests doesn't cover this. No core-cache scenario sends a cached body downstream or checks its framing headers. framing_headers.vtc uses only ordinary bodies.

Related

#743 has a candidate fix. One question it left open was whether the guest's Body::known_length() should return Some(n) here. The Compute output above confirms that it should, which matches #743.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions