fix: properly handle io.Reader EOF in Push function#1
Conversation
Fix issue where Node.js nodes couldn't read body in subsequent requests after POST requests to Go gateway. The original code incorrectly required both io.EOF and nn==0 to break the read loop, but io.Reader can return EOF with data on final read. This caused premature stream closure and left connections in inconsistent state. Changes: - Process data (nn > 0) before checking for errors - Send EOF signal (empty DataPacket) only after all data is sent - Fix variable shadowing by using errSend instead of err
|
@greptileai review this |
Greptile SummaryThis PR fixes the
Confidence Score: 5/5Safe to merge — the change is a focused, well-reasoned correction to a single read loop that now faithfully follows the io.Reader contract. The rewritten loop correctly handles all four read outcomes (data-only, data+EOF, EOF-only, other error) without calling Read after EOF. The EOF signal packet is now sent exactly once and at the right moment, matching what the Node.js and Go receivers already expect. The variable-shadowing fix eliminates a subtle source of confusion with no behavioral downside. No new error paths are introduced. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant C as Push caller
participant P as Provider.Push
participant R as body (io.ReadCloser)
participant N as Peer (Node.js / Go)
C->>P: Push(services, headers, body)
P->>N: OpcodeServiceRequest (stream header)
loop Read body
P->>R: body.Read(buf)
alt "nn > 0, nil"
R-->>P: n bytes, nil
P->>N: OpcodeData [n bytes]
else "nn > 0, io.EOF (final chunk with data)"
R-->>P: n bytes, io.EOF
P->>N: OpcodeData [n bytes]
P->>N: "OpcodeData [] (empty = EOF signal)"
Note over P: break
else "nn == 0, io.EOF"
R-->>P: 0 bytes, io.EOF
P->>N: "OpcodeData [] (empty = EOF signal)"
Note over P: break
else other error
R-->>P: n bytes, err
P->>N: "OpcodeData [n bytes] (if nn > 0)"
P->>N: CloseStreamWithError
P-->>C: nil, error
end
end
N-->>P: stream.wg.Done
P-->>C: Stream, nil
Reviews (3): Last reviewed commit: "Update provider.go" | Re-trigger Greptile |
Greptile SummaryThis PR fixes a subtle but real bug in the
Confidence Score: 4/5The change is safe to merge; it correctly aligns the read loop with the Go io.Reader contract and the empty-DataPacket EOF signal that the receiver already expects. The core fix is sound — processing data before inspecting the error, then sending the explicit empty EOF packet and breaking, is the right pattern. The one subtlety is that on a non-EOF read error the new code now forwards any partial chunk it read to the peer before closing the stream, whereas the old code discarded it. This is an error-path behaviour change that the receiver currently has no special handling for, but it does not break anything in practice. provider.go — specifically the non-EOF error path inside the read loop where partial data is now forwarded before stream closure. Important Files Changed
Sequence DiagramsequenceDiagram
participant C as Caller
participant P as Push (provider.go)
participant R as body io.Reader
participant N as Remote Node
C->>P: Push(services, headers, body)
P->>N: ServiceRequestPacket (OpcodeServiceRequest)
loop Read body
P->>R: body.Read(buf)
alt "nn > 0, err = nil"
R-->>P: data chunk
P->>N: "DataPacket{Data: buf[:nn]}"
else "nn > 0, err = io.EOF"
R-->>P: final chunk + EOF
P->>N: "DataPacket{Data: buf[:nn]}"
P->>N: "DataPacket{Data: []} — EOF signal"
Note over P,N: Break loop
else "nn = 0, err = io.EOF"
R-->>P: clean EOF
P->>N: "DataPacket{Data: []} — EOF signal"
Note over P,N: Break loop
else non-EOF error
R-->>P: err
P->>N: CloseStreamWithError
P-->>C: return nil, err
end
end
N-->>P: ServiceResponsePacket
P-->>C: return stream, nil
Reviews (2): Last reviewed commit: "fix: properly handle io.Reader EOF in Pu..." | Re-trigger Greptile |
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Fix issue where Node.js nodes couldn't read body in subsequent requests after POST requests to Go gateway.
The original code incorrectly required both io.EOF and nn==0 to break the read loop, but io.Reader can return EOF with data on final read. This caused premature stream closure and left connections in inconsistent state.
Changes: