Skip to content

The response body API names the streaming call write() for the buffered one #180

Description

@EdmondDantes

HttpResponse::write() appends to a buffer and puts nothing on the wire
(src/http_response.c:641); the call that commits headers and streams is
send() (src/http_response.c:997). Node (res.write), Swoole
($response->write) and Go (w.Write) stream under the first name, so a
handler ported from any of them holds the whole body in memory and delivers it
in one piece at end(). Both field reports behind the body-contract work
(YanGusik/laravel-spawn#50, #60) came from the API rather than from the
adapter's own code.

Four more names in the same class report something other than what they say.

sendable() answers one bool for four questions — closed, sealed by
sendFile(), detached, full (src/http_response.c:1341). README.md
documented it as a liveness check until #174, and that is the loop which
truncated the stream in #60. Both replacements are already in: isWritable()
for liveness (#176), tryWrite() and awaitWritable() for room (#178).

isClosed() returns response->closed, the flag end() sets
(src/http_response.c:1557). It reports nothing about the connection, so a
handler that reads it as "the peer is gone" gets a wrong answer for the whole
life of the response.

getBodyStream() returns null and setBodyStream() throws "not yet
implemented" (src/http_response.c:721,731). Neither has ever had an
implementation behind it.

The naming already cost a working call site inside this repository:
tests/perf/servers/server_stream.php:45 calls ->send() with no argument
(arginfo requires one, stubs/HttpResponse.php_arginfo.h:67) and streams its
chunks with ->write(), which buffers them. The stream profile of the perf
harness fails with ArgumentCountError before it measures anything.

Proposal

Today After Behaviour
send(string): static write(string): static streams; send() kept one minor as an alias
write(string): static appendBody(string): static appends to the buffered body
isClosed(): bool isEnded(): bool end() has been called
sendable(): bool removed tombstone naming isWritable() and tryWrite()
getBodyStream(): mixed removed never implemented
setBodyStream(mixed): static removed never implemented

send() carries no E_DEPRECATED: it is a per-chunk call, and PHP emits the
notice on every one of them.

Compatibility

Seven CHANGELOG entries. laravel-spawn is a two-line diff — Sse::connected()
calls isWritable() (done ahead of the rename in YanGusik/laravel-spawn#63,
#64), and send() becomes write().

The dangerous one is write(): a handler that used it for buffered appending
keeps compiling and starts streaming, which commits headers on the first call
and makes every later setHeader() throw. The CHANGELOG entry has to name it
first.

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