Commits
Tarun Sukhani authored f40ef0aec5b
[PF-34/PF-35/PF-36] Audit ship-blockers + 1.12.0 version bump + release notes Three ship-blocker fixes from the post-PF-33 multi-agent audit, plus the v1.12.0 release notes and the version bump in framework/build.xml. PF-34: WebSocket Outbound close()/futureClose() data race - The writeAndClose listener fires on the EventLoop and called futureClose() without holding the `this` monitor, racing with close()'s synchronized write to closeTask. Under JMM rules the listener could observe stale null closeTask and silently skip invoking the close promise, leaving the WebSocket connection orphaned. - futureClose() is now synchronized; the onRedeem callback delegates to a new synchronized finalizeClose() helper instead of inline mutating closeTask. Java synchronized methods lock on the instance monitor; reentrant on the inline-callback case. - Two reviewers (refcount and concurrency) independently flagged this — strongest possible signal for a real bug. PF-35: serve500 leaked a ByteBuf on every 500 (3 sites) - Each serve500 path did `ByteBuf buf = Unpooled.copiedBuffer(bytes); nettyResponse.content().clear().writeBytes(buf);` — the intermediate `buf` has refcount 1 and goes out of scope unreleased. Heap-backed so no direct- memory leak, but Netty's PARANOID leak detector flags this once a 500 is triggered. - Replaced with the byte[] overload of writeBytes — drops the intermediate buffer entirely. Three sites: primary template render, static fallback render, last-ditch render. PF-36: HEAD requests on error paths still sent a body (RFC 7230 §3.3.2) - DefaultFullHttpResponse(version, status, buf) carries body bytes regardless of request method. The main writeResponse path handles HEAD correctly via byte[0] content; serve404, serve500 (3 sites), and the serveStatic error fallback did not. - Now check `nettyRequest.method().equals(HttpMethod.HEAD)` at each error-path site. For HEAD: pass Unpooled.EMPTY_BUFFER as response content while preserving Content-Length (per RFC 7230 §3.3.2 second sentence — HEAD CL matches what the equivalent GET would return). Release notes (documentation/manual/releases/release1.12.x/releasenotes-1.12.0.textile): - Documents the breaking changes (removed deprecated ctors with migration paths, pipeline FQCN updates, maxContentLength semantic change) - Inventories the new play.netty.spoolThresholdBytes config with tuning guidance - Lists known limitations carrying forward (PF-37 through PF-43) - Includes an upgrade checklist build.xml: baseversion bumped 1.11.12 → 1.12.0 to match the v1.12.x branch designation; ant package now produces play-1.12.0.zip. Verified with `ant clean unittest`: 295/295 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>