Frame curl requests and scope the test fixture lifecycle
This commit is contained in:
@@ -4,6 +4,10 @@ This CLI sends HTTP and HTTPS requests through standard WASI HTTP.
|
||||
The host supplies TLS and transparent credential injection.
|
||||
The CLI does not request or read host credentials.
|
||||
Each redirect creates a separate request, so the host checks every hop.
|
||||
Every request has Content-Length, including empty requests.
|
||||
The client finishes the body before it waits for a response.
|
||||
It does not flush or poll the outgoing stream after its final byte.
|
||||
A fast peer can close that stream after it consumes the framed body.
|
||||
Verbose request output contains only headers that the CLI supplies.
|
||||
|
||||
## Supported options
|
||||
@@ -66,18 +70,17 @@ The shared `cwd-init/init.o` must exist first. Generate it from the repository r
|
||||
|
||||
```sh
|
||||
nix develop -c nu userland/cwd-init/build.nu
|
||||
CARGO_BUILD_JOBS=2 CARGO_TARGET_DIR=/tmp/p1-curl/server-target nix develop -c cargo build --manifest-path userland/curl/tests/server/Cargo.toml --locked
|
||||
mkdir -p /tmp/p1-curl
|
||||
/tmp/p1-curl/server-target/debug/curl-test-server /tmp/p1-curl/port
|
||||
```
|
||||
|
||||
Run the server as a managed job or in another terminal.
|
||||
Then run the comparisons from the repository root:
|
||||
Run the comparisons from the repository root:
|
||||
|
||||
```sh
|
||||
nix develop -c nu userland/curl/test.nu
|
||||
```
|
||||
|
||||
The script builds the native fixture with a persistent cache and starts it on a free port.
|
||||
Each run uses a fresh readiness file.
|
||||
The script stops the fixture after success or failure.
|
||||
The script compares deterministic local responses with native curl.
|
||||
It also checks a public HTTPS GET and verifies WASI-only component imports.
|
||||
The script retains its temporary files for inspection.
|
||||
|
||||
@@ -132,11 +132,13 @@ fn send(
|
||||
.append(name, value)
|
||||
.map_err(|_| error(2, "Invalid HTTP header"))?;
|
||||
}
|
||||
if let Some(data) = data {
|
||||
fields
|
||||
.set("content-length", &[data.len().to_string().into_bytes()])
|
||||
.map_err(|_| error(2, "Invalid content length"))?;
|
||||
}
|
||||
// Frame even empty requests so Hyper does not discard an unknown-length body.
|
||||
fields
|
||||
.set(
|
||||
"content-length",
|
||||
&[data.map_or(0, <[u8]>::len).to_string().into_bytes()],
|
||||
)
|
||||
.map_err(|_| error(2, "Invalid content length"))?;
|
||||
let request = OutgoingRequest::new(fields);
|
||||
let method = match method {
|
||||
"GET" => Method::Get,
|
||||
@@ -204,10 +206,8 @@ fn send(
|
||||
.map_err(|_| error(55, "Request write failed"))?;
|
||||
remaining = &remaining[count..];
|
||||
}
|
||||
stream
|
||||
.flush()
|
||||
.map_err(|_| error(55, "Request flush failed"))?;
|
||||
wait(stream.subscribe(), deadline)?;
|
||||
// After the last byte, the peer can already answer and close its reader.
|
||||
// Do not flush or poll that reader after the framed body is complete.
|
||||
drop(stream);
|
||||
}
|
||||
OutgoingBody::finish(outgoing, None).map_err(transport_error)?;
|
||||
|
||||
+22
-2
@@ -12,10 +12,30 @@ def compare [name: string, component: path, root: path, url: string, args: list,
|
||||
if $stderr { assert equal $wasi.stderr $native.stderr $name }
|
||||
print $'($name): PASS'
|
||||
}
|
||||
def main [component: path = '/tmp/p1-curl/target/wasm32-wasip2/release/curl.wasm', readiness: path = '/tmp/p1-curl/port'] {
|
||||
def main [component: path = '/tmp/p1-curl/target/wasm32-wasip2/release/curl.wasm'] {
|
||||
let component = ($component | path expand)
|
||||
mkdir /tmp/p1-curl
|
||||
let root = (^mktemp -d -p /tmp/p1-curl comparison.XXXXXX | str trim)
|
||||
let port = (open --raw $readiness | str trim)
|
||||
let manifest = ($env.FILE_PWD | path join tests/server/Cargo.toml)
|
||||
let build = (with-env {CARGO_BUILD_JOBS: '2', CARGO_TARGET_DIR: '/tmp/p1-curl/server-target'} { ^cargo build --manifest-path $manifest --locked } | complete)
|
||||
if $build.exit_code != 0 { error make {msg: ($build | to json)} }
|
||||
let readiness = ($root | path join port)
|
||||
let server = job spawn { ^/tmp/p1-curl/server-target/debug/curl-test-server $readiness out> ($root | path join server.out) err> ($root | path join server.err) }
|
||||
try {
|
||||
let deadline = (date now) + 5sec
|
||||
while not ($readiness | path exists) {
|
||||
if (date now) >= $deadline { error make {msg: $'Fixture did not start. Inspect ($root)/server.err'} }
|
||||
}
|
||||
let port = (open --raw $readiness | str trim)
|
||||
run-tests $component $root $port
|
||||
} catch {|failure|
|
||||
job kill $server
|
||||
error make {msg: $failure.msg}
|
||||
}
|
||||
job kill $server
|
||||
print 'Fixture stopped: PASS'
|
||||
}
|
||||
def run-tests [component: path, root: path, port: string] {
|
||||
let base = $'http://127.0.0.1:($port)'
|
||||
let wit = (^wasm-tools component wit $component | complete)
|
||||
assert equal $wit.exit_code 0
|
||||
|
||||
Reference in New Issue
Block a user