Found during an adversarial review of 0.6.0 while preparing a downstream conformance test.
HttpMcpTestClient.readSseUntilResponse checks its deadline only after BufferedReader.readLine() returns:
while ((line = reader.readLine()) != null) {
if (System.nanoTime() > deadline) {
break;
}
...
}
Two consequences:
- A byte-silent stream blocks forever. If a server holds the POST SSE stream open and sends no bytes at all (no keep-alives — e.g. a keep-alive interval of 0, or a server that just stalls),
readLine() never returns and the deadline is unreachable. The method's own Javadoc claims the deadline means a server that never responds "fails the test with a message instead of hanging the build" — that only holds when the server keeps sending something. The request-level HttpRequest.timeout() doesn't help; it covers response headers only.
- A response arriving just past the deadline is discarded, not returned. The
break happens before the just-read line is parsed, so a response landing at deadline+ε turns into the IllegalStateException instead of a (late) success.
The 0.6.0 fix is still correct for the case it targeted (keep-alive streams, where lines keep arriving and the deadline fires within one keep-alive period) — this is the remaining gap.
Proposed fix for 0.7.0: enforce the deadline independently of line arrival — a watchdog that closes the stream at the deadline so readLine() unblocks with an exception (then translated into the timeout message), or a timed read via the async subscriber API. Regression test: a server mode that goes byte-silent after the handshake.
Found during an adversarial review of 0.6.0 while preparing a downstream conformance test.
HttpMcpTestClient.readSseUntilResponsechecks its deadline only afterBufferedReader.readLine()returns:Two consequences:
readLine()never returns and the deadline is unreachable. The method's own Javadoc claims the deadline means a server that never responds "fails the test with a message instead of hanging the build" — that only holds when the server keeps sending something. The request-levelHttpRequest.timeout()doesn't help; it covers response headers only.breakhappens before the just-read line is parsed, so a response landing at deadline+ε turns into theIllegalStateExceptioninstead of a (late) success.The 0.6.0 fix is still correct for the case it targeted (keep-alive streams, where lines keep arriving and the deadline fires within one keep-alive period) — this is the remaining gap.
Proposed fix for 0.7.0: enforce the deadline independently of line arrival — a watchdog that closes the stream at the deadline so
readLine()unblocks with an exception (then translated into the timeout message), or a timed read via the async subscriber API. Regression test: a server mode that goes byte-silent after the handshake.