Skip to content

Conversation

@icing
Copy link
Contributor

@icing icing commented Nov 6, 2025

WIP, a new ratelimits implementation that allows for "pausing", e.g. pulling the rate limit down to 0 and then back up again.

A Curl_rlimit can be used for any resource that has time limited consumption. It's a "bucket" that is initially full, gets drained by taking things out and re-fills over the duration of a second. When a bucket becomes empty, it gives the time to wait until it is full again.

Each transfer has an up- and download "rlimit". For uploads, the client reader checks how much is left in the upload rlimit and only passed that many bytes to its caller. The passed amount is drained from the rlimit.

For downloads, the transfer loop limits its connection "recv" call by the amount left in the download rlimit. The actual bytes are written to the client and get drained from the download rlimit.

The multi handle checks for transfers in PERFORM state if there are wait times for the up-/down rlimits and, if so, set the TOO_FAST timer and sets the transfer in RATELIMIT state.

http2.c now checks the available rlimit for downloads to adjust/update the streams window size.

Update: implemented for ngtcp2

Update2: rate-limiting downloads does not seem possible with the quiche API.

Update3: on larger rate limits, the "bucket" interval goes down to 500ms for smoother spread.

Update4: speedlimit is not part of progress updates/checks. Unpausing the receive direction now resets the speed limit calculation.

Description of how this works in `docs/internal/RATELIMITS.ms`.

Notable implementation changes:
- KEEP_SEND_PAUSE/KEEP_SEND_HOLD and KEEP_RECV_PAUSE/KEEP_RECV_HOLD
  no longer exist. Pausing is down via blocked the new rlimits.
- KEEP_SEND_TIMED no longer exists. Pausing "100-continue" transfers
  is done in the new `Curl_http_perform_pollset()` method.
- HTTP/2 rate limiting implemented via window updates. When
  transfer initiaiting connection has a ratelimit, adjust the
  initial window size
- HTTP/3 ngtcp2 rate limitin implemnented via ack updates
- HTTP/3 quiche does not seem to support this via its API
- the default progress-meter has been improved for accuracy
  in "current speed" results.

pytest speed tests have been improved.
Remember the HTT/2 settings initial window size that applies
to new streams and update it for the about to be opened transfer
should this value change.

This allows rate limited transfer to start with a suitable window
and unlimited one to have the default value applied to them.
When rates are a multiple of 16k, go from 1 second to 500ms in
calculating and updating rates. This gives more precision.

Steps can be defined to be even smaller at the cost of increased
CPU usage (smaller wait times). 500ms seems acceptable in measuremnets.
…ransfers

Bundles the four methods to make semantics clear.
Prepares for folding the speed check into the call which may
give other errors besides ABORTED_BY_CALLBACK.
Since the Curl_pgrs*() functions are the only callers of the
speedchecks now, place them together.
@bagder bagder closed this in 24b36fd Nov 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants