Add 0-RTT (early data) support#148
Conversation
benoitc
left a comment
There was a problem hiding this comment.
CI is red for now can you take care of it ? also the branch predates recent changes to support IPv6 can upi ensure to do your changes over the last main ?
i've commented the other parts in the source.
| "Resumed in-proc: early_data_accepted=~p status=~p", | ||
| [EarlyData, Status] | ||
| ), | ||
| ?assert(lists:member(EarlyData, [true, false, unknown])), |
There was a problem hiding this comment.
early_data_accepted/1's entire range is true|false|unknown, so it can never fail . This doesn't prove the server accepted 0-RTT. Rather add a path asserting That EarlyData is tru and was processed before handshake completion
| %% extension in EncryptedExtensions. Absence is rejection. | ||
| %% Clients that did not offer 0-RTT keep the default `false'. | ||
| OfferedZeroRtt = State#state.early_keys =/= undefined, | ||
| EarlyDataAccepted = OfferedZeroRtt andalso EarlyDataInEE, |
| %% Connection-level flow-control accounting is left untouched: 0-RTT | ||
| %% bytes were sent under the resumed limits, and the new 1-RTT keys | ||
| %% bring fresh `initial_max_data' / `initial_max_stream_data_*' | ||
| %% allowances from the server's transport parameters. | ||
| -spec reset_zero_rtt_streams([non_neg_integer()], #state{}) -> #state{}. | ||
| reset_zero_rtt_streams([], State) -> | ||
| State; | ||
| reset_zero_rtt_streams(RejectedIds, #state{streams = Streams, owner = Owner} = State) -> | ||
| NewStreams = lists:foldl(fun maps:remove/2, Streams, RejectedIds), | ||
| ?LOG_INFO( | ||
| #{ | ||
| what => zero_rtt_rejected, | ||
| rejected_stream_ids => RejectedIds, | ||
| count => length(RejectedIds) | ||
| }, | ||
| ?QUIC_LOG_META | ||
| ), | ||
| Owner ! {quic, self(), {early_data_rejected, RejectedIds}}, | ||
| State#state{ | ||
| streams = NewStreams, |
There was a problem hiding this comment.
If the application re-issues the same bytes on new 1-RTT streams, the connection-level bytes-sent counter still includes the discarded 0-RTT bytes this can trigger premature MAX_DATA exhaustion. Shouldn't we reset send-side FC to the server's real transport params.? Also: do rejected stream IDs leave a gap the server (which never saw them) handles cleanly?
| test_state_for_zero_rtt_reset/3, | ||
| test_zero_rtt_reset_info/1, | ||
| test_finalize_zero_rtt_handshake/2, | ||
| test_reset_zero_rtt_streams/2, | ||
| test_client_state_for_ee/4, | ||
| test_process_encrypted_extensions/2 |
There was a problem hiding this comment.
Project convention is to keep test-only exports in a separate module, can you move them out in test folder ?
| %% RFC 9114 §6.2.1 (SETTINGS-first), §7.2.4.2 (0-RTT initialization). | ||
| %%==================================================================== | ||
|
|
||
| early_data(enter, _OldState, State) -> |
There was a problem hiding this comment.
RFC 9114 §7.2.4.2: early requests must respect the server's remembered SETTINGS . is this loaded/ applied to qpack encoding? will it default to static or defuaults?
| {keep_state_and_data, [postpone]}; | ||
| bootstrapping(info, {quic, QC, {new_stream, _, _}}, #state{quic_conn = QC}) -> | ||
| {keep_state_and_data, [postpone]}; | ||
| bootstrapping(_EventType, _Event, _State) -> |
There was a problem hiding this comment.
bootstraping handle early_data_rejected but not session_tickett likeoter states does. Maybe we can make it consistent there too ?
| {deps, [ | ||
| {proper, "1.4.0"} | ||
| {proper, "1.4.0"}, | ||
| {meck, "1.0.0"} |
There was a problem hiding this comment.
bump to latest to support erlang 29.
Sure! I'll check! |
Lets a client with a session ticket send application data in its first flight instead of paying a full round trip on resumption. Wires the existing TLS 1.3 / QUIC PSK machinery through the public API and the HTTP/3 layer.
What's in here
Public API (quic.erl, quic_connection.erl)
TLS (quic_tls.erl)
HTTP/3 (quic_h3.erl, quic_h3_connection.erl)
Replay
I added meck as a dep, but i can remove it if needed.
Closes #147