fix(http2): do not head-of-line block HEADERS, RST_STREAM and GOAWAY behind window-exhausted DATA (#2013)

> [!NOTE]
> This PR was generated by an AI coding agent (Jetski) on behalf of @mosuem.

`ConnectionMessageQueueOut` is a strict FIFO. Once the connection-level send window is exhausted, a `DataMessage` at the head of the queue blocks *everything* behind it, including frames that are not subject to flow control (RFC 9113 Section 6.9: *"Flow control only applies to frames that are identified as being subject to flow control. Of the frame types defined in this document, this includes only DATA frames."*). In practice: while one stream was waiting for `WINDOW_UPDATE`, no new request could be opened (`HEADERS`), no stream could be cancelled (`RST_STREAM`), and the connection could not be shut down gracefully (`GOAWAY`) until the peer granted credit.

- **`lib/src/flowcontrol/connection_queues.dart`**:
  - `_peekSendableMessage()` replaces the "first message or nothing" rule. When the window is exhausted and the head of the queue is a `DataMessage`, it returns the first `GOAWAY`, or the first `HEADERS` / `RST_STREAM` whose stream has no earlier queued message. Skipping a message of a stream blocks every later message of that stream (and, for a `PUSH_PROMISE`, of the promised stream), so per-stream frame order is preserved: trailers never overtake their own `DATA`.
  - The scan is linear in the queue length, and `StreamMessageQueueOut` keeps forwarding `DATA` into this queue while the connection window is exhausted (it only checks the stream window). To avoid rescanning on every `sendData()` call, `enqueueMessage` skips `_trySendMessages()` when a `DataMessage` is enqueued while `_connectionWindow.positiveWindow.wouldBuffer` is `true` (since the new `DataMessage` cannot be sent and cannot unblock any earlier queued message). Enqueueing a non-DATA message while blocked still costs one pass over the queue.

Added to `test/client_test.dart`:
- `headers-and-rst-not-blocked-or-reordered-on-exhausted-window`: stream 1 exhausts the connection window; stream 3's `HEADERS` and stream 5's `HEADERS` + `RST_STREAM` must still go out, in that order, before the window is replenished.
- `trailers-stay-behind-blocked-data-while-other-headers-bypass`: stream 1 has blocked `DATA` *and* queued trailers; stream 3's `HEADERS` bypass them, stream 1's trailers are only written after its `DATA`.

**Before fix:**
```text
00:05 +0 -1: client-tests client-errors headers-and-rst-not-blocked-or-reordered-on-exhausted-window [E]
  TimeoutException after 0:00:05.000000: Test timed out after 5 seconds.
00:10 +0 -2: client-tests client-errors trailers-stay-behind-blocked-data-while-other-headers-bypass [E]
  TimeoutException after 0:00:05.000000: Test timed out after 5 seconds.
```
(stream 3's `HEADERS` never leave the client while stream 1 waits for credit)

**After fix:**
```text
00:00 +2: All tests passed!
```
3 files changed
tree: aca27899793c82049c595f9fcdb7dbc5da821061
  1. .gemini/
  2. .github/
  3. pkgs/
  4. tool/
  5. .gitattributes
  6. .gitignore
  7. analysis_options.yaml
  8. CONTRIBUTING.md
  9. LICENSE
  10. mono_repo.yaml
  11. README.md
README.md

Build Status

A composable, Future-based library for making HTTP requests.

package:http contains a set of high-level functions and classes that make it easy to consume HTTP resources. It's multi-platform, and supports mobile, desktop, and the browser.

Packages

PackageDescriptionVersion
cronet_httpAn Android Flutter plugin that provides access to the Cronet HTTP client.pub package
cupertino_httpA macOS/iOS Flutter plugin that provides access to the Foundation URL Loading System.pub package
flutter_http_exampleDemonstrates how to use package:http in a Flutter app.—
httpA composable, multi-platform, Future-based API for HTTP requests.pub package
http2A HTTP/2 implementation in Dart.pub package
http_client_conformance_testsA library that tests whether implementations of package:http's Client class behave as expected.—
http_multi_serverA dart:io HttpServer wrapper that handles requests from multiple servers.pub package
http_parserA platform-independent package for parsing and serializing HTTP formats.pub package
http_profileA library used by HTTP client authors to integrate with the DevTools Network View.pub package
ok_httpAn Android Flutter plugin that provides access to the OkHttp HTTP client.pub package
web_socketAny easy-to-use library for communicating with WebSockets that has multiple implementations.pub package
web_socket_channelA WebSocket API that enables cross-platform communication via StreamChannel.pub package
web_socket_conformance_testsA library that tests whether implementations of package:web_socket's WebSocket class behave as expected.—

Contributing

If you'd like to contribute to any of these packages, see the Contributing Guide.