Establishes the package layout, limits/error model and decision-log convention that every later HTTP/2 phase depends on, per flash/docs/http2/IMPLEMENTATION-PLAN.md Phase 0. - dev.relism.flash.h2: package-info (architecture overview), Http2ErrorCode (the 14 RFC 9113 §7 codes with precomputed 4-byte wire encodings), Http2Exception (connection error -> GOAWAY) and Http2StreamException (stream error -> RST_STREAM), neither extending IOException, both with stack-trace capture disabled on the hot rejection path. - Http2Limits: every bound Phase 0 requires (concurrent streams, frame size, header list size, CONTINUATION/reset/settings/ping rate bounds, flow-control windows, HPACK table size/string length, assembly and idle timeouts), each documented with the attack or RFC clause it addresses. - dev.relism.flash.http.Http1Limits: the h1 bounds needed by EX-03 (strict Content-Length) and EX-08 (header count/size limits). - flash/docs/http2/DECISIONS.md seeded with DEC-01..DEC-11 (the ten decisions implied by the plan itself, plus DEC-11 recording that commits keep scope `core` rather than adding `h2` to AGENTS.md). - flash/docs/http2/IMPLEMENTATION-PLAN.md: added the Progress Ledger (tracks phase status across sessions) and checked off Phase 0's DoD. 19 new tests, full flash module suite green (226/226). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
47 lines
2.1 KiB
Java
47 lines
2.1 KiB
Java
package dev.relism.flash.h2;
|
|
|
|
/**
|
|
* A <b>stream-level</b> HTTP/2 error, scoped to one stream id. Results in an {@code RST_STREAM}
|
|
* frame for {@link #streamId()} with {@link #errorCode()}; the connection and every other
|
|
* stream on it are unaffected. Compare {@link Http2Exception}, whose scope is the whole
|
|
* connection.
|
|
*
|
|
* <p>Deliberately does <b>not</b> extend {@link java.io.IOException}, for the same reason as
|
|
* {@link Http2Exception}: the connection loop must be able to distinguish "we decided to reject
|
|
* this stream" from "the socket failed" by catching unrelated exception types.
|
|
*
|
|
* <h3>Why this allocates, unlike {@code Http2Exception}'s singletons</h3>
|
|
* Every instance carries a distinct {@link #streamId()}, so it cannot be a shared singleton the
|
|
* way {@code Http2Exception}'s message-less constants are. This is still acceptable under R2:
|
|
* {@code RST_STREAM} generation is an error path, not the steady-state request path, and R2
|
|
* exempts error paths. The scenario where this matters most — a peer opening and resetting
|
|
* thousands of streams per second (the Rapid Reset pattern, CVE-2023-44487) — is bounded by
|
|
* rate limits (Phase 13), not by making the rejection itself allocation-free; a hostile peer
|
|
* that can force RST_STREAM generation fast enough for GC pressure to matter has already
|
|
* tripped {@code Http2Limits.MAX_RESET_STREAMS_PER_INTERVAL} and the connection is being torn
|
|
* down anyway.
|
|
*
|
|
* <p>Stack trace capture is disabled for the same cost reason as {@link Http2Exception}.
|
|
*/
|
|
public final class Http2StreamException extends RuntimeException {
|
|
|
|
private final Http2ErrorCode errorCode;
|
|
private final int streamId;
|
|
|
|
public Http2StreamException(int streamId, Http2ErrorCode errorCode, String message) {
|
|
super(message, null, false, false);
|
|
this.streamId = streamId;
|
|
this.errorCode = errorCode;
|
|
}
|
|
|
|
/** The id of the stream this error terminates. */
|
|
public int streamId() {
|
|
return streamId;
|
|
}
|
|
|
|
/** The RFC 9113 §7 error code to send in the {@code RST_STREAM} frame. */
|
|
public Http2ErrorCode errorCode() {
|
|
return errorCode;
|
|
}
|
|
}
|