From 1a5d5eb1c91d34c522937a8010cbc81bca7fe78e Mon Sep 17 00:00:00 2001 From: Kershaw Chang Date: Fri, 23 Dec 2022 10:16:53 +0000 Subject: [PATCH] Bug 1805652 - neqo v0.6.3, r=necko-reviewers,jesup Differential Revision: https://phabricator.services.mozilla.com/D164657 --- .cargo/config.in | 2 +- Cargo.lock | 22 +- netwerk/protocol/http/Http3Session.cpp | 6 + netwerk/socket/neqo_glue/Cargo.toml | 10 +- netwerk/socket/neqo_glue/src/lib.rs | 11 + netwerk/test/http3server/Cargo.toml | 10 +- netwerk/test/http3server/src/main.rs | 27 +- .../rust/neqo-common/.cargo-checksum.json | 2 +- third_party/rust/neqo-common/Cargo.toml | 4 +- .../rust/neqo-crypto/.cargo-checksum.json | 2 +- third_party/rust/neqo-crypto/Cargo.toml | 4 +- third_party/rust/neqo-crypto/build.rs | 4 +- third_party/rust/neqo-crypto/src/agent.rs | 12 +- third_party/rust/neqo-crypto/src/hp.rs | 8 +- third_party/rust/neqo-crypto/src/p11.rs | 1 - third_party/rust/neqo-crypto/src/prio.rs | 1 - third_party/rust/neqo-crypto/src/ssl.rs | 1 - .../rust/neqo-http3/.cargo-checksum.json | 2 +- third_party/rust/neqo-http3/Cargo.toml | 2 +- .../rust/neqo-http3/src/client_events.rs | 13 + third_party/rust/neqo-http3/src/connection.rs | 304 ++++++++++++- .../rust/neqo-http3/src/connection_client.rs | 408 ++++++++++++++++-- .../rust/neqo-http3/src/connection_server.rs | 22 +- .../src/features/extended_connect/mod.rs | 23 +- .../features/extended_connect}/tests/mod.rs | 0 .../tests/webtransport/datagrams.rs | 128 ++++++ .../tests/webtransport/mod.rs | 127 +++++- .../tests/webtransport/negotiation.rs | 290 +++++++++++++ .../tests/webtransport/sessions.rs | 95 ++-- .../tests/webtransport/streams.rs | 166 +++---- .../extended_connect/webtransport_session.rs | 56 ++- .../extended_connect/webtransport_streams.rs | 4 +- third_party/rust/neqo-http3/src/frames/mod.rs | 17 +- .../rust/neqo-http3/src/frames/reader.rs | 10 +- .../rust/neqo-http3/src/frames/tests/mod.rs | 2 +- third_party/rust/neqo-http3/src/lib.rs | 176 +++++++- .../neqo-http3/src/qpack_decoder_receiver.rs | 2 +- .../neqo-http3/src/qpack_encoder_receiver.rs | 2 +- .../rust/neqo-http3/src/recv_message.rs | 2 +- third_party/rust/neqo-http3/src/server.rs | 7 + .../src/server_connection_events.rs | 11 + .../rust/neqo-http3/src/server_events.rs | 58 ++- .../rust/neqo-http3/src/stream_type_reader.rs | 10 +- third_party/rust/neqo-http3/tests/httpconn.rs | 89 +++- .../rust/neqo-http3/tests/webtransport.rs | 315 ++++++++++++++ .../tests/webtransport/negotiation.rs | 156 ------- .../rust/neqo-qpack/.cargo-checksum.json | 2 +- third_party/rust/neqo-qpack/Cargo.toml | 2 +- .../rust/neqo-qpack/src/header_block.rs | 2 +- .../rust/neqo-qpack/src/qpack_send_buf.rs | 2 +- .../rust/neqo-transport/.cargo-checksum.json | 2 +- third_party/rust/neqo-transport/Cargo.toml | 2 +- third_party/rust/neqo-transport/src/cid.rs | 4 +- .../neqo-transport/src/connection/idle.rs | 2 +- .../rust/neqo-transport/src/connection/mod.rs | 35 +- .../src/connection/tests/close.rs | 2 +- .../src/connection/tests/idle.rs | 83 +++- .../src/connection/tests/stream.rs | 2 +- third_party/rust/neqo-transport/src/fc.rs | 2 +- third_party/rust/neqo-transport/src/lib.rs | 1 + third_party/rust/neqo-transport/src/path.rs | 2 +- third_party/rust/neqo-transport/src/qlog.rs | 4 +- .../rust/neqo-transport/src/recovery.rs | 4 +- .../rust/neqo-transport/src/recv_stream.rs | 8 +- .../rust/neqo-transport/src/send_stream.rs | 14 +- third_party/rust/neqo-transport/src/stats.rs | 2 +- .../rust/neqo-transport/src/tracking.rs | 8 +- .../rust/neqo-transport/tests/sim/mod.rs | 2 +- 68 files changed, 2272 insertions(+), 539 deletions(-) rename third_party/rust/neqo-http3/{ => src/features/extended_connect}/tests/mod.rs (100%) create mode 100644 third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/datagrams.rs rename third_party/rust/neqo-http3/{ => src/features/extended_connect}/tests/webtransport/mod.rs (82%) create mode 100644 third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs rename third_party/rust/neqo-http3/{ => src/features/extended_connect}/tests/webtransport/sessions.rs (81%) rename third_party/rust/neqo-http3/{ => src/features/extended_connect}/tests/webtransport/streams.rs (89%) create mode 100644 third_party/rust/neqo-http3/tests/webtransport.rs delete mode 100644 third_party/rust/neqo-http3/tests/webtransport/negotiation.rs diff --git a/.cargo/config.in b/.cargo/config.in index 9d3c8ced46f2..182355e39f88 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -97,7 +97,7 @@ replace-with = "vendored-sources" [source."https://github.com/mozilla/neqo"] git = "https://github.com/mozilla/neqo" -tag = "v0.6.1" +tag = "v0.6.3" replace-with = "vendored-sources" [source."https://github.com/mozilla/uniffi-rs.git"] diff --git a/Cargo.lock b/Cargo.lock index ea2789f07799..6488c380d9be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3594,8 +3594,8 @@ dependencies = [ [[package]] name = "neqo-common" -version = "0.6.1" -source = "git+https://github.com/mozilla/neqo?tag=v0.6.1#e71e860489447fed25b64bd8ec31a804dccb0dad" +version = "0.6.3" +source = "git+https://github.com/mozilla/neqo?tag=v0.6.3#4fe628bb911e4437169d974baa628c159e96f879" dependencies = [ "chrono", "env_logger 0.9.0", @@ -3607,10 +3607,10 @@ dependencies = [ [[package]] name = "neqo-crypto" -version = "0.6.1" -source = "git+https://github.com/mozilla/neqo?tag=v0.6.1#e71e860489447fed25b64bd8ec31a804dccb0dad" +version = "0.6.3" +source = "git+https://github.com/mozilla/neqo?tag=v0.6.3#4fe628bb911e4437169d974baa628c159e96f879" dependencies = [ - "bindgen 0.59.999", + "bindgen 0.63.0", "log", "mozbuild", "neqo-common", @@ -3621,8 +3621,8 @@ dependencies = [ [[package]] name = "neqo-http3" -version = "0.6.1" -source = "git+https://github.com/mozilla/neqo?tag=v0.6.1#e71e860489447fed25b64bd8ec31a804dccb0dad" +version = "0.6.3" +source = "git+https://github.com/mozilla/neqo?tag=v0.6.3#4fe628bb911e4437169d974baa628c159e96f879" dependencies = [ "enumset", "lazy_static", @@ -3639,8 +3639,8 @@ dependencies = [ [[package]] name = "neqo-qpack" -version = "0.6.1" -source = "git+https://github.com/mozilla/neqo?tag=v0.6.1#e71e860489447fed25b64bd8ec31a804dccb0dad" +version = "0.6.3" +source = "git+https://github.com/mozilla/neqo?tag=v0.6.3#4fe628bb911e4437169d974baa628c159e96f879" dependencies = [ "lazy_static", "log", @@ -3653,8 +3653,8 @@ dependencies = [ [[package]] name = "neqo-transport" -version = "0.6.1" -source = "git+https://github.com/mozilla/neqo?tag=v0.6.1#e71e860489447fed25b64bd8ec31a804dccb0dad" +version = "0.6.3" +source = "git+https://github.com/mozilla/neqo?tag=v0.6.3#4fe628bb911e4437169d974baa628c159e96f879" dependencies = [ "indexmap", "lazy_static", diff --git a/netwerk/protocol/http/Http3Session.cpp b/netwerk/protocol/http/Http3Session.cpp index 8cb6fe879af6..c7aea04faced 100644 --- a/netwerk/protocol/http/Http3Session.cpp +++ b/netwerk/protocol/http/Http3Session.cpp @@ -729,6 +729,12 @@ nsresult Http3Session::ProcessEvents() { mStreamIdHash.InsertOrUpdate(wtStream->StreamId(), std::move(wtStream)); } break; + case WebTransportEventExternal::Tag::Datagram: + LOG( + ("Http3Session::ProcessEvents - " + "WebTransportEventExternal::Tag::Datagram [this=%p]", + this)); + break; } } break; default: diff --git a/netwerk/socket/neqo_glue/Cargo.toml b/netwerk/socket/neqo_glue/Cargo.toml index 5f21b826a3c6..ed4cce53fbbb 100644 --- a/netwerk/socket/neqo_glue/Cargo.toml +++ b/netwerk/socket/neqo_glue/Cargo.toml @@ -9,10 +9,10 @@ license = "MPL-2.0" name = "neqo_glue" [dependencies] -neqo-http3 = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } -neqo-transport = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } -neqo-common = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } -neqo-qpack = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } +neqo-http3 = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } +neqo-transport = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } +neqo-common = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } +neqo-qpack = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } xpcom = { path = "../../../xpcom/rust/xpcom" } @@ -26,7 +26,7 @@ static_prefs = { path = "../../../modules/libpref/init/static_prefs", optional = winapi = {version = "0.3", features = ["ws2def"] } [dependencies.neqo-crypto] -tag = "v0.6.1" +tag = "v0.6.3" git = "https://github.com/mozilla/neqo" default-features = false features = ["gecko"] diff --git a/netwerk/socket/neqo_glue/src/lib.rs b/netwerk/socket/neqo_glue/src/lib.rs index 98f9719dda72..d823d1220929 100644 --- a/netwerk/socket/neqo_glue/src/lib.rs +++ b/netwerk/socket/neqo_glue/src/lib.rs @@ -696,6 +696,9 @@ pub enum WebTransportEventExternal { stream_type: WebTransportStreamType, session_id: u64, }, + Datagram { + session_id: u64, + }, } impl WebTransportEventExternal { @@ -728,6 +731,14 @@ impl WebTransportEventExternal { stream_type: stream_id.stream_type().into(), session_id: session_id.as_u64(), }, + WebTransportEvent::Datagram { + session_id, + datagram: _ + } => { + WebTransportEventExternal::Datagram { + session_id: session_id.as_u64(), + } + } } } } diff --git a/netwerk/test/http3server/Cargo.toml b/netwerk/test/http3server/Cargo.toml index 870caddcaf64..ece0e64b3a30 100644 --- a/netwerk/test/http3server/Cargo.toml +++ b/netwerk/test/http3server/Cargo.toml @@ -6,17 +6,17 @@ edition = "2018" license = "MPL-2.0" [dependencies] -neqo-transport = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } -neqo-common = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } -neqo-http3 = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } -neqo-qpack = { tag = "v0.6.1", git = "https://github.com/mozilla/neqo" } +neqo-transport = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } +neqo-common = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } +neqo-http3 = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } +neqo-qpack = { tag = "v0.6.3", git = "https://github.com/mozilla/neqo" } mio = "0.6.17" mio-extras = "2.0.5" log = "0.4.0" base64 = "0.13" [dependencies.neqo-crypto] -tag = "v0.6.1" +tag = "v0.6.3" git = "https://github.com/mozilla/neqo" default-features = false features = ["gecko"] diff --git a/netwerk/test/http3server/src/main.rs b/netwerk/test/http3server/src/main.rs index 10b0ae795994..07495c8f4bcb 100644 --- a/netwerk/test/http3server/src/main.rs +++ b/netwerk/test/http3server/src/main.rs @@ -11,6 +11,7 @@ use neqo_crypto::{generate_ech_keys, init_db, AllowZeroRtt, AntiReplay}; use neqo_http3::{ Error, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, WebTransportRequest, WebTransportServerEvent, + WebTransportSessionAcceptAction, }; use neqo_transport::server::Server; use neqo_transport::{ @@ -431,13 +432,13 @@ impl HttpServer for Http3TestServer { let path = ph.value(); qtrace!("Serve request {}", path); if path == "/success" { - session.response(true).unwrap(); + session.response(&WebTransportSessionAcceptAction::Accept).unwrap(); } else if path == "/reject" { - session.response(false).unwrap(); + session.response(&WebTransportSessionAcceptAction::Reject([Header::new(":status", "404")].to_vec())).unwrap(); } else if path == "/closeafter0ms" { - session.response(true).unwrap(); + session.response(&WebTransportSessionAcceptAction::Accept).unwrap(); } else if path == "/closeafter100ms" { - session.response(true).unwrap(); + session.response(&WebTransportSessionAcceptAction::Accept).unwrap(); let expires = Instant::now() + Duration::from_millis(100); if !self.sessions_to_close.contains_key(&expires) { self.sessions_to_close.insert(expires, Vec::new()); @@ -447,17 +448,17 @@ impl HttpServer for Http3TestServer { .unwrap() .push(session); } else if path == "/create_unidi_stream" { - session.response(true).unwrap(); + session.response(&WebTransportSessionAcceptAction::Accept).unwrap(); self.sessions_to_create_stream.push((session, StreamType::UniDi)); } else if path == "/create_bidi_stream" { - session.response(true).unwrap(); + session.response(&WebTransportSessionAcceptAction::Accept).unwrap(); self.sessions_to_create_stream.push((session, StreamType::BiDi)); } else { - session.response(true).unwrap(); + session.response(&WebTransportSessionAcceptAction::Accept).unwrap(); } } _ => { - session.response(false).unwrap(); + session.response(&WebTransportSessionAcceptAction::Reject([Header::new(":status", "404")].to_vec())).unwrap(); } } } @@ -476,6 +477,16 @@ impl HttpServer for Http3TestServer { self.webtransport_bidi_stream.insert(stream); } } + Http3ServerEvent::WebTransport(WebTransportServerEvent::Datagram { + session, + datagram, + }) => { + qdebug!( + "WebTransportServerEvent::Datagram {:?} {:?}", + session, + datagram + ); + } } } } diff --git a/third_party/rust/neqo-common/.cargo-checksum.json b/third_party/rust/neqo-common/.cargo-checksum.json index d6f5d97e5745..cf41e01f39b6 100644 --- a/third_party/rust/neqo-common/.cargo-checksum.json +++ b/third_party/rust/neqo-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1e35362eb965155414173a29d9f0fbe1af3c6a66aa158af6701f235688dacd5c","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"5aeb997fd0eca77241d1cc173f0d37aa8d2ec1725d5e3739c28f1999bf7c4bed","src/datagram.rs":"742aa0f39ac24d63431b58e23ebf925e27ec42340e5911020475de5f7f457a6d","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"c5f9f65a642b5782589a4caaf1e758845daa7ebf56c58dc9ef9f836e48026d29","src/incrdecoder.rs":"458f0228e41018d58f5a83c7895c9ea283f310fcb91c969e22026eb8ca3c84c9","src/lib.rs":"bf3e9922196f09554ef55d24c3331bb4c249d583fbbd9f5815670d9d23160838","src/log.rs":"f1ba46a9c2ef10b27211561f4851f933db941ec85ccd3425376d060034aea051","src/qlog.rs":"ca323c91d61810ebef2ebeb967836dda384a60a9fb492c2b8d1b235a98f2e4bf","src/timer.rs":"e63af7e7df968bf702583f263cfb63e6dca4e599bacffa2de0a6383d85333636","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"b27c96cc0da9ca1bc8731ee35100064dcf11df63613d08d02a2e07a66a6ffef0","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"5aeb997fd0eca77241d1cc173f0d37aa8d2ec1725d5e3739c28f1999bf7c4bed","src/datagram.rs":"742aa0f39ac24d63431b58e23ebf925e27ec42340e5911020475de5f7f457a6d","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"c5f9f65a642b5782589a4caaf1e758845daa7ebf56c58dc9ef9f836e48026d29","src/incrdecoder.rs":"458f0228e41018d58f5a83c7895c9ea283f310fcb91c969e22026eb8ca3c84c9","src/lib.rs":"bf3e9922196f09554ef55d24c3331bb4c249d583fbbd9f5815670d9d23160838","src/log.rs":"f1ba46a9c2ef10b27211561f4851f933db941ec85ccd3425376d060034aea051","src/qlog.rs":"ca323c91d61810ebef2ebeb967836dda384a60a9fb492c2b8d1b235a98f2e4bf","src/timer.rs":"e63af7e7df968bf702583f263cfb63e6dca4e599bacffa2de0a6383d85333636","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-common/Cargo.toml b/third_party/rust/neqo-common/Cargo.toml index a3253f31aa46..f85e6609fcce 100644 --- a/third_party/rust/neqo-common/Cargo.toml +++ b/third_party/rust/neqo-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neqo-common" -version = "0.6.1" +version = "0.6.3" authors = ["Bobby Holley "] edition = "2018" rust-version = "1.57.0" @@ -12,7 +12,7 @@ log = {version = "0.4.0", default-features = false} env_logger = {version = "0.9", default-features = false} lazy_static = "1.3.0" qlog = "0.4.0" -chrono = "0.4.10" +chrono = {version = "0.4.10", default-features = false, features = ["std"]} [features] default = ["deny-warnings"] diff --git a/third_party/rust/neqo-crypto/.cargo-checksum.json b/third_party/rust/neqo-crypto/.cargo-checksum.json index b4cd717ab70e..0186893c97d8 100644 --- a/third_party/rust/neqo-crypto/.cargo-checksum.json +++ b/third_party/rust/neqo-crypto/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"372b8108f43f8df1f6f26e72e434a2ae0ba00b8b4dba193451eb427738734069","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"cb3e29ac6d1fd7083ffab81494afe1b9a2d9e41c60774438fd9681974c87c252","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"99df86d0c11da5a8cbcc3be2560e6d764234a21b5d9b5f7ab1b70696e4f8670e","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"e11ea62b4605b84400edbd5fc394f008fc26d3b67467ba7fe1597b90db4c6a12","src/agent.rs":"1dfab420ca00789f745d440476b272e672ae756536f743d1faa9aa214bc0bcda","src/agentio.rs":"bce4c3dfcfa433209a409ac0c0752f8c95ab37bb6239a42f99b83858e8747bd1","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"628fc2384cdeb2a32bfbecb83c99af393df97fd6a76c6e8827e8240c0d47328b","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"447f6297f50914249d0c92ec61d74df6c65ce4affceecb8cafe40927e855fe1d","src/err.rs":"f2cc71de2b40d7bba8119eeaee200337db9a0126176ba06e4902d7312facdb58","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"3ff432cc9d40e1dc56e9f983b54b593647c4063a5ae0f16de0a64d033ac9bd94","src/hp.rs":"722a798a7d280b66bd0f8adc6f9135f7d8130f7f0ef45ea12b85d47a88adefda","src/lib.rs":"8d1bfe33999b20eeb5f7eef70d4c634de560de5376029f81b2412bca60176c39","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"2ff35a2512bcf894684f24b94640e7fe9d4df6a20264aa3714f2f02fdb99e73d","src/prio.rs":"d9bd43a4d84db70fd552239d0852ea60b960957912f614b929d27dadccca803a","src/replay.rs":"c9bc0261fe1ae22e7212774c315a2669784e57762ca975a15250d4a33dbf3ea3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"d5d98e34b100568fecade932832379c52530c70a51ad2d37ee6b2dd008865f01","src/selfencrypt.rs":"f11ae7f6f1e6b602b6e729d71597116fb172190b57102af4f76b22fbe78c8b6a","src/ssl.rs":"ace1a162c3b189d52b5e5f9827c4300b7d47d3b2ae29a976d3bbc46c52328253","src/time.rs":"9bacbed11b0e40402731a9803fd1531272e00e199217c1560130ede50d7020f6","tests/aead.rs":"31b5b4374cc5ca2deee6267c4d5b4858defc74e694ec85af196339a76548a17c","tests/agent.rs":"94819f9eeba2afa0c25adc821755900f1488fd47af6d84d9507a112c29d1752a","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"0fcfa8958686aacb42c56c51c6b234842fe990470d2069a67509869baaa18452","tests/hkdf.rs":"47830c1ea58a02d100522bdde6fabc02bb447ccb85affa0cdc44bc25da1be32a","tests/hp.rs":"316973740210fc1f8166920582795a41347a0aec9024fdc480e2ee83a7a5332d","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"fc03d4b7219e6615de21d3a5a2fa14e4ccd32014e081848b3fd917fcddf48d42","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"cb3e29ac6d1fd7083ffab81494afe1b9a2d9e41c60774438fd9681974c87c252","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"536e0436f19152aa5a23c340e93ebc24c3640153a8c885b723a9379432a9c6d4","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"e11ea62b4605b84400edbd5fc394f008fc26d3b67467ba7fe1597b90db4c6a12","src/agent.rs":"a0029413c37c71599971e08df8352fbfd7b7d1970a889ef85a1cabaff256ab11","src/agentio.rs":"bce4c3dfcfa433209a409ac0c0752f8c95ab37bb6239a42f99b83858e8747bd1","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"628fc2384cdeb2a32bfbecb83c99af393df97fd6a76c6e8827e8240c0d47328b","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"447f6297f50914249d0c92ec61d74df6c65ce4affceecb8cafe40927e855fe1d","src/err.rs":"f2cc71de2b40d7bba8119eeaee200337db9a0126176ba06e4902d7312facdb58","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"3ff432cc9d40e1dc56e9f983b54b593647c4063a5ae0f16de0a64d033ac9bd94","src/hp.rs":"606cae31d5cbbd5fd8f02e74e8e372ce6fabc7da3d0c625e905ff74e6cdde0e6","src/lib.rs":"8d1bfe33999b20eeb5f7eef70d4c634de560de5376029f81b2412bca60176c39","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"d76a3d365fad3d7fbc8f7c0aacefc65ef737b9286672fa800d14711f50736a0e","src/prio.rs":"e5e169296c0ac69919c59fb6c1f8bd6bf079452eaa13d75da0edd41d435d3f6f","src/replay.rs":"c9bc0261fe1ae22e7212774c315a2669784e57762ca975a15250d4a33dbf3ea3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"d5d98e34b100568fecade932832379c52530c70a51ad2d37ee6b2dd008865f01","src/selfencrypt.rs":"f11ae7f6f1e6b602b6e729d71597116fb172190b57102af4f76b22fbe78c8b6a","src/ssl.rs":"90dfa84ebad961c5ecf3c2e85f9de7acf678dd3aed7e2b9f068036512f70a97d","src/time.rs":"9bacbed11b0e40402731a9803fd1531272e00e199217c1560130ede50d7020f6","tests/aead.rs":"31b5b4374cc5ca2deee6267c4d5b4858defc74e694ec85af196339a76548a17c","tests/agent.rs":"94819f9eeba2afa0c25adc821755900f1488fd47af6d84d9507a112c29d1752a","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"0fcfa8958686aacb42c56c51c6b234842fe990470d2069a67509869baaa18452","tests/hkdf.rs":"47830c1ea58a02d100522bdde6fabc02bb447ccb85affa0cdc44bc25da1be32a","tests/hp.rs":"316973740210fc1f8166920582795a41347a0aec9024fdc480e2ee83a7a5332d","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-crypto/Cargo.toml b/third_party/rust/neqo-crypto/Cargo.toml index ad2597fad394..6de1db239aeb 100644 --- a/third_party/rust/neqo-crypto/Cargo.toml +++ b/third_party/rust/neqo-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neqo-crypto" -version = "0.6.1" +version = "0.6.3" authors = ["Martin Thomson "] edition = "2018" rust-version = "1.57.0" @@ -12,7 +12,7 @@ neqo-common = { path = "../neqo-common" } log = {version = "0.4.0", default-features = false} [build-dependencies] -bindgen = {version = "0.59", default-features = false, features= ["runtime"]} +bindgen = {version = "0.63", default-features = false, features= ["runtime"]} serde = "1.0" serde_derive = "1.0" toml = "0.5" diff --git a/third_party/rust/neqo-crypto/build.rs b/third_party/rust/neqo-crypto/build.rs index 10684a9cb9c6..3769ba07191d 100644 --- a/third_party/rust/neqo-crypto/build.rs +++ b/third_party/rust/neqo-crypto/build.rs @@ -102,7 +102,7 @@ fn nss_dir() -> PathBuf { let dir = Path::new(&out_dir).join("nss"); if !dir.exists() { Command::new("hg") - .args(&[ + .args([ "clone", "https://hg.mozilla.org/projects/nss", dir.to_str().unwrap(), @@ -113,7 +113,7 @@ fn nss_dir() -> PathBuf { let nspr_dir = Path::new(&out_dir).join("nspr"); if !nspr_dir.exists() { Command::new("hg") - .args(&[ + .args([ "clone", "https://hg.mozilla.org/projects/nspr", nspr_dir.to_str().unwrap(), diff --git a/third_party/rust/neqo-crypto/src/agent.rs b/third_party/rust/neqo-crypto/src/agent.rs index 7ea68a7ec547..9163c4c711c1 100644 --- a/third_party/rust/neqo-crypto/src/agent.rs +++ b/third_party/rust/neqo-crypto/src/agent.rs @@ -596,7 +596,7 @@ impl SecretAgent { /// Return any fatal alert that the TLS stack might have sent. #[must_use] pub fn alert(&self) -> Option<&Alert> { - (&*self.alert).as_ref() + (*self.alert).as_ref() } /// Call this function to mark the peer as authenticated. @@ -930,7 +930,7 @@ impl Client { /// Error returned when the configuration is invalid. pub fn enable_ech(&mut self, ech_config_list: impl AsRef<[u8]>) -> Res<()> { let config = ech_config_list.as_ref(); - qdebug!([self], "Enable ECH for a server: {}", hex_with_len(&config)); + qdebug!([self], "Enable ECH for a server: {}", hex_with_len(config)); self.ech_config = Vec::from(config); if config.is_empty() { unsafe { ech::SSL_EnableTls13GreaseEch(self.agent.fd, PRBool::from(true)) } @@ -1189,8 +1189,8 @@ impl Deref for Agent { #[must_use] fn deref(&self) -> &SecretAgent { match self { - Self::Client(c) => &**c, - Self::Server(s) => &**s, + Self::Client(c) => c, + Self::Server(s) => s, } } } @@ -1198,8 +1198,8 @@ impl Deref for Agent { impl DerefMut for Agent { fn deref_mut(&mut self) -> &mut SecretAgent { match self { - Self::Client(c) => &mut **c, - Self::Server(s) => &mut **s, + Self::Client(c) => c, + Self::Server(s) => s, } } } diff --git a/third_party/rust/neqo-crypto/src/hp.rs b/third_party/rust/neqo-crypto/src/hp.rs index 7bfd08a34b91..f968943c00bc 100644 --- a/third_party/rust/neqo-crypto/src/hp.rs +++ b/third_party/rust/neqo-crypto/src/hp.rs @@ -150,7 +150,7 @@ impl HpKey { output.as_mut_ptr(), &mut output_len, c_int::try_from(output.len())?, - (&sample[..Self::SAMPLE_SIZE]).as_ptr().cast(), + sample[..Self::SAMPLE_SIZE].as_ptr().cast(), c_int::try_from(Self::SAMPLE_SIZE).unwrap(), ) })?; @@ -162,7 +162,7 @@ impl HpKey { let params: CK_CHACHA20_PARAMS = CK_CHACHA20_PARAMS { pBlockCounter: sample.as_ptr() as *mut u8, blockCounterBits: 32, - pNonce: (&sample[4..Self::SAMPLE_SIZE]).as_ptr() as *mut _, + pNonce: sample[4..Self::SAMPLE_SIZE].as_ptr() as *mut _, ulNonceBits: 96, }; let mut output_len: c_uint = 0; @@ -172,10 +172,10 @@ impl HpKey { **key, CK_MECHANISM_TYPE::from(CKM_CHACHA20), addr_of_mut!(param_item), - (&mut output[..]).as_mut_ptr(), + output[..].as_mut_ptr(), &mut output_len, c_uint::try_from(output.len())?, - (&output[..]).as_ptr(), + output[..].as_ptr(), c_uint::try_from(output.len())?, ) })?; diff --git a/third_party/rust/neqo-crypto/src/p11.rs b/third_party/rust/neqo-crypto/src/p11.rs index 9deecaf0e471..7848cf08c8a5 100644 --- a/third_party/rust/neqo-crypto/src/p11.rs +++ b/third_party/rust/neqo-crypto/src/p11.rs @@ -20,7 +20,6 @@ use std::os::raw::{c_int, c_uint}; use std::ptr::null_mut; #[allow(clippy::upper_case_acronyms)] -#[allow(unknown_lints, deref_nullptr)] // Until bindgen#1651 is fixed. #[allow(clippy::unreadable_literal)] #[allow(unknown_lints, clippy::borrow_as_ptr)] mod nss_p11 { diff --git a/third_party/rust/neqo-crypto/src/prio.rs b/third_party/rust/neqo-crypto/src/prio.rs index f06027cc37b7..527d8739c857 100644 --- a/third_party/rust/neqo-crypto/src/prio.rs +++ b/third_party/rust/neqo-crypto/src/prio.rs @@ -5,7 +5,6 @@ // except according to those terms. #![allow(clippy::upper_case_acronyms)] -#![allow(unknown_lints, deref_nullptr)] // Until bindgen#1651 is fixed. #![allow( dead_code, non_upper_case_globals, diff --git a/third_party/rust/neqo-crypto/src/ssl.rs b/third_party/rust/neqo-crypto/src/ssl.rs index 29c149df893e..b3c0c127089c 100644 --- a/third_party/rust/neqo-crypto/src/ssl.rs +++ b/third_party/rust/neqo-crypto/src/ssl.rs @@ -14,7 +14,6 @@ unknown_lints, clippy::borrow_as_ptr )] -#![allow(unknown_lints, deref_nullptr)] // Until bindgen#1651 is fixed. use crate::constants::Epoch; use crate::err::{secstatus_to_res, Res}; diff --git a/third_party/rust/neqo-http3/.cargo-checksum.json b/third_party/rust/neqo-http3/.cargo-checksum.json index 539e981f66ce..1731da7cf285 100644 --- a/third_party/rust/neqo-http3/.cargo-checksum.json +++ b/third_party/rust/neqo-http3/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"7dd3f73b8b65f903607977de05ae02595340dd5e7afe6ac5010e400fc440c506","src/buffered_send_stream.rs":"4bc45ca03252dc34ab421a2af3499191b182a619143c61d5609a46377c9a0f3d","src/client_events.rs":"9d86145febad2f3fb05007eae3f5ad4834c78dd709fe388f05590405e34a614b","src/conn_params.rs":"7e33526de9c83c163049a2caf2bff0f997351cc61fad76fb6e8c6ec4b9f09938","src/connection.rs":"72c3c2a3c19481d519f4c1928c51dc7c1d4ab6e6cb2bd9ecfdfc5d5c09f485bb","src/connection_client.rs":"e4914a8e44eb6045615382eacf2499b0195574f19ce36e161ad3d3e186f69ebb","src/connection_server.rs":"de1e0359b902b1e98c923a8d5488302a68a3312b466590fdddaee6ec8327813b","src/control_stream_local.rs":"b86e1f869ad59bf2663501942a1a65d94c1dbc3e8770982459e0b620be4b6cf0","src/control_stream_remote.rs":"7a261ac7df77e90a428ab0f92457a934a92a8c581462fc1818efd3de0c0ebd69","src/features/extended_connect/mod.rs":"2bc2f0570b11318f3225173001dad1a5f05e4bf60dee49a2bf9d40e3a411e138","src/features/extended_connect/webtransport_session.rs":"abf84892c429c2ee79efd8e215bfd9da182163ba859cd24b6ee4ba6becceb6bd","src/features/extended_connect/webtransport_streams.rs":"784c5e317bb6af33f653ba82c1a5666b657c2a210263a415e913494f61613464","src/features/mod.rs":"a981ebbd03e7bb7ea2313e883452e44f052c48f28edb7fd53a0825911b490230","src/frames/hframe.rs":"8206e1a27ad805899f7e722c05dffa92649704bbaf98ff2a70a7ca1d6a55395e","src/frames/mod.rs":"258dd4bdf2daca19a62cd697d2c7f4709a35668b2b4dce3203675e814c9b40b8","src/frames/reader.rs":"0802cd8b41204bcec424fc6ed704a3bdbed0e5d38444f7a9b0550ad877b076a6","src/frames/tests/hframe.rs":"33a30bb98bb512606a06ae1752e1ed9e4588b7d3f5e9439ec83bb2e779d4ac80","src/frames/tests/mod.rs":"4933c519069ee4dac23587588f2b792c12d1363e92d0105e1eb169082e213559","src/frames/tests/reader.rs":"312a3deda7b3a4bbd7afed879c94d0644fce8e34435365ef9cae1fbaa62496af","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"0eebdf9a275cd53ee6525f7387941601d119d933203d9b2425377adf8348d425","src/headers_checks.rs":"b80c1da2d9f336fa88f7b7f2a834d8e90e826260811771c7729785fdc92b20d4","src/lib.rs":"58d23d794cf5c68d6f2b68e93e3e7d1c5546d64d5d2357ca7cb7858aeb434124","src/priority.rs":"ae0fa461031893b4f7e0d12666072e7a4da80b1e8a1c0663ab9f9e27b3242754","src/push_controller.rs":"aa2a64180d8cb1b87682d0d8bbc42167188e8e1890261cb4cabb76de1fcc708b","src/qlog.rs":"44b6cdbb1d9d6ca47b793e9dbe531b8fdbd40147375f7e4c89aeab536c5d286b","src/qpack_decoder_receiver.rs":"75008d8ea5d538ee34aca4df72e58489417604ccafb61b064280782d6754dd0d","src/qpack_encoder_receiver.rs":"f95cc7d49e4d442b93d522f14ddfc581629664d84d6e13d03a520e855bbe442d","src/recv_message.rs":"5f70fb474e387653d7982374131b3b0c08417509469f273ccebf842bfcee836f","src/request_target.rs":"9182b641f7a7b55272e0e2e872d24a35b1207f35399221b08b899857c3e873ab","src/send_message.rs":"9e1b22ede2a105a79d7c02178801e1a46b06a80dc1c0d2a7d69b0eea7e89f319","src/server.rs":"ab00f395f7767d733091af3e3317527e5c302b2e5062b33943211ede75f10109","src/server_connection_events.rs":"3d89c2d9a30ee719acfbaae4b7720cb354eb73b11bc6ceb44571d68b05192b8b","src/server_events.rs":"3081fdd1e1950aeecae031452cd683335fb0a9dcec51722e614c5939f747b9d9","src/settings.rs":"e7babcce34c49d897c7d5ed93ef8e9ad02524cebff96a249c2ce84f1b968be21","src/stream_type_reader.rs":"f790b2aaa6758ad85487d98376895b5ee2c3098ffd4586825e1bb0b3c2375c75","tests/httpconn.rs":"f8d6e6a693d17cf2eb192a730e6fc929bd2814552356ce8d4423a0e3eac8c59d","tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","tests/priority.rs":"a606e5fa03451e09e28c7d5f1820ee85a4567e3969a1690c979761e62123bf54","tests/send_message.rs":"673ae1d0bf2dce46c21ee8353f45f189d2cb64a2f6e137ae38da6b2262ad066e","tests/webtransport/mod.rs":"635c0b0fe682a844f4366335a40b8b3a6539abe30843ee1bcfaf87a34b1d476c","tests/webtransport/negotiation.rs":"2da85dfd45e3dfdbab7608768d734e1f150e1b0ba14e982cbb6de16ba62789c2","tests/webtransport/sessions.rs":"5b4d8483ac018ad5a28adad5e778e2ed48db9c441d1354f6cf21d8e5c6f1a8b3","tests/webtransport/streams.rs":"fd5f075d93f0241290566f59f747d95530d2df579890fd0f6b9e79a557c89a67"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"bf794c0aeb6200aafc695374c2218afd0cf6f7bab7e6b1c370eb0171fb785169","src/buffered_send_stream.rs":"4bc45ca03252dc34ab421a2af3499191b182a619143c61d5609a46377c9a0f3d","src/client_events.rs":"978ab01cf82c2390db442c6d8440209f9498f52a00ede7c8ea9813e649e15ae3","src/conn_params.rs":"7e33526de9c83c163049a2caf2bff0f997351cc61fad76fb6e8c6ec4b9f09938","src/connection.rs":"fe38c174b54b65c696e8fdc89da337cb19783fee78d6d6407223a8d13bb36c6a","src/connection_client.rs":"131b20981697002386ef2dff63345dfa4227547dd028293e16f91f72c1b9cd26","src/connection_server.rs":"365f246a0caa5d310da21587525b4793cd3046d973cce8f3aa62b8a1eac493a7","src/control_stream_local.rs":"b86e1f869ad59bf2663501942a1a65d94c1dbc3e8770982459e0b620be4b6cf0","src/control_stream_remote.rs":"7a261ac7df77e90a428ab0f92457a934a92a8c581462fc1818efd3de0c0ebd69","src/features/extended_connect/mod.rs":"94fc7b98ac335ffad4eb41d162b87f0ae9a86205cd3ef9c79d21081a99d6e610","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"0d8021b94491100d56f4c66ad852bea9d3f1286135e523e217db0e0487284172","src/features/extended_connect/tests/webtransport/mod.rs":"db7b31e6826e2fb6ab8051434d649d78a70d3b7e92e3760f79f7995c7b651558","src/features/extended_connect/tests/webtransport/negotiation.rs":"2d8b0bfa015eb7b57a844aea8abf4ae3c0ab478d1bf84bb53ef8b1837ca7b7ec","src/features/extended_connect/tests/webtransport/sessions.rs":"8471db54293452aa5ae2a0aab565b51e2907238679d5f4074ab3cc05f24036ff","src/features/extended_connect/tests/webtransport/streams.rs":"0ef81aef536f01413b13738cf59f69c7f819a75d655de3d6b905f2f3d84f8509","src/features/extended_connect/webtransport_session.rs":"3dea89800b4b364d140a443d12b25393fa3f50f9bc3f8d6f52e8f9b88cd74049","src/features/extended_connect/webtransport_streams.rs":"9562e5bf321f1338514a70ee89ccd88a15cd4ccf727ea3533b55bb1d5be27f04","src/features/mod.rs":"a981ebbd03e7bb7ea2313e883452e44f052c48f28edb7fd53a0825911b490230","src/frames/hframe.rs":"8206e1a27ad805899f7e722c05dffa92649704bbaf98ff2a70a7ca1d6a55395e","src/frames/mod.rs":"7d0a46ca147336d14781edb8dbee8b03c2e4bcd6646f5473a9d93d31fe73fecb","src/frames/reader.rs":"3d7af10a21833049aa0277caec4abe13d677d2d62526f1c83126f2defe19ee5e","src/frames/tests/hframe.rs":"33a30bb98bb512606a06ae1752e1ed9e4588b7d3f5e9439ec83bb2e779d4ac80","src/frames/tests/mod.rs":"81cac9702e9016dacd60085c2e3968093b356fe682ced33d7c9c1f3151b9201c","src/frames/tests/reader.rs":"312a3deda7b3a4bbd7afed879c94d0644fce8e34435365ef9cae1fbaa62496af","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"0eebdf9a275cd53ee6525f7387941601d119d933203d9b2425377adf8348d425","src/headers_checks.rs":"b80c1da2d9f336fa88f7b7f2a834d8e90e826260811771c7729785fdc92b20d4","src/lib.rs":"50ac4975d3b5b5680a1f8d144da16b40f080bbe90e05679fe50d59ad5937d10b","src/priority.rs":"ae0fa461031893b4f7e0d12666072e7a4da80b1e8a1c0663ab9f9e27b3242754","src/push_controller.rs":"aa2a64180d8cb1b87682d0d8bbc42167188e8e1890261cb4cabb76de1fcc708b","src/qlog.rs":"44b6cdbb1d9d6ca47b793e9dbe531b8fdbd40147375f7e4c89aeab536c5d286b","src/qpack_decoder_receiver.rs":"50c5e7679304b227a5f86ab681396d59c5885a8d7a4b72985cce82f3f8eaa129","src/qpack_encoder_receiver.rs":"3deca0555826167bbaf8099eb1b394883e5e5c8c4ee68261f8c4816bdf686eda","src/recv_message.rs":"1f740c59676f5913108de68f41db1dfc1b8d6feeb0467c61ae652d6d26e75682","src/request_target.rs":"9182b641f7a7b55272e0e2e872d24a35b1207f35399221b08b899857c3e873ab","src/send_message.rs":"9e1b22ede2a105a79d7c02178801e1a46b06a80dc1c0d2a7d69b0eea7e89f319","src/server.rs":"cfcb1e9e44f3e4de220fe71cee9f4633bed911f49c1bc40a44b6ff95ec6f5a76","src/server_connection_events.rs":"df18dac1ca9048567a6aac4db34aa031cb80135b1ef6cd3ae67e3f621015e081","src/server_events.rs":"be39b5c07c6f1981b8d4c4afd8dfc704b0b2b440831f364079aeffeec4dedd8f","src/settings.rs":"e7babcce34c49d897c7d5ed93ef8e9ad02524cebff96a249c2ce84f1b968be21","src/stream_type_reader.rs":"983362180f19e47c938b3b81650e71c5bc5a55500ff425b1617d74e2ec9357f5","tests/httpconn.rs":"8b62aa9a24ccc45f436aa57ff7d5b37394d844eced6b204085fc5086b1a643c7","tests/priority.rs":"a606e5fa03451e09e28c7d5f1820ee85a4567e3969a1690c979761e62123bf54","tests/send_message.rs":"673ae1d0bf2dce46c21ee8353f45f189d2cb64a2f6e137ae38da6b2262ad066e","tests/webtransport.rs":"73b1b5a0297452e92c81793b986cbe666f6efe114b9ab5f719be5d3e92f1819c"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-http3/Cargo.toml b/third_party/rust/neqo-http3/Cargo.toml index f6ee1d539551..294d0c5c2522 100644 --- a/third_party/rust/neqo-http3/Cargo.toml +++ b/third_party/rust/neqo-http3/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neqo-http3" -version = "0.6.1" +version = "0.6.3" authors = ["Dragana Damjanovic "] edition = "2018" rust-version = "1.57.0" diff --git a/third_party/rust/neqo-http3/src/client_events.rs b/third_party/rust/neqo-http3/src/client_events.rs index df10071da92b..e17a29c85490 100644 --- a/third_party/rust/neqo-http3/src/client_events.rs +++ b/third_party/rust/neqo-http3/src/client_events.rs @@ -35,6 +35,10 @@ pub enum WebTransportEvent { stream_id: StreamId, session_id: StreamId, }, + Datagram { + session_id: StreamId, + datagram: Vec, + }, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -211,6 +215,15 @@ impl ExtendedConnectEvents for Http3ClientEvents { }, )); } + + fn new_datagram(&self, session_id: StreamId, datagram: Vec) { + self.insert(Http3ClientEvent::WebTransport( + WebTransportEvent::Datagram { + session_id, + datagram, + }, + )); + } } impl Http3ClientEvents { diff --git a/third_party/rust/neqo-http3/src/connection.rs b/third_party/rust/neqo-http3/src/connection.rs index a78ddbd10e4c..cdecfff343ee 100644 --- a/third_party/rust/neqo-http3/src/connection.rs +++ b/third_party/rust/neqo-http3/src/connection.rs @@ -27,11 +27,12 @@ use crate::{ HttpRecvStreamEvents, NewStreamType, Priority, PriorityHandler, ReceiveOutput, RecvStream, RecvStreamEvents, SendStream, SendStreamEvents, }; -use neqo_common::{qdebug, qerror, qinfo, qtrace, qwarn, Header, MessageType, Role}; +use neqo_common::{qdebug, qerror, qinfo, qtrace, qwarn, Decoder, Header, MessageType, Role}; use neqo_qpack::decoder::QPackDecoder; use neqo_qpack::encoder::QPackEncoder; use neqo_transport::{ - AppError, Connection, ConnectionError, State, StreamId, StreamType, ZeroRttState, + AppError, Connection, ConnectionError, DatagramTracking, State, StreamId, StreamType, + ZeroRttState, }; use std::cell::RefCell; use std::collections::{BTreeSet, HashMap}; @@ -41,7 +42,7 @@ use std::rc::Rc; use crate::{Error, Res}; -pub struct RequestDescription<'b, 't, T> +pub(crate) struct RequestDescription<'b, 't, T> where T: AsRequestTarget<'t> + ?Sized + Debug, { @@ -52,6 +53,20 @@ where pub priority: Priority, } +pub enum WebTransportSessionAcceptAction { + Accept, + Reject(Vec
), +} + +impl ::std::fmt::Display for WebTransportSessionAcceptAction { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + WebTransportSessionAcceptAction::Accept => f.write_str("Accept"), + WebTransportSessionAcceptAction::Reject(_) => f.write_str("Reject"), + } + } +} + #[derive(Debug)] enum Http3RemoteSettingsState { NotReceived, @@ -59,6 +74,19 @@ enum Http3RemoteSettingsState { ZeroRtt(HSettings), } +/// States: +/// - `Initializing`: this is the state during the QUIC handshake, +/// - `ZeroRtt`: 0-RTT has been enabled and is active +/// - Connected +/// - GoingAway(StreamId): The connection has received a `GOAWAY` frame +/// - Closing(ConnectionError): The connection is closed. The closing has been initiated by this +/// end of the connection, e.g., the `CONNECTION_CLOSE` frame has been sent. In this state, the +/// connection waits a certain amount of time to retransmit the `CONNECTION_CLOSE` frame if +/// needed. +/// - Closed(ConnectionError): This is the final close state: closing has been initialized by the +/// peer and an ack for the `CONNECTION_CLOSE` frame has been sent or the closing has been +/// initiated by this end of the connection and the ack for the `CONNECTION_CLOSE` has been +/// received or the waiting time has passed. #[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone)] pub enum Http3State { Initializing, @@ -79,6 +107,194 @@ impl Http3State { } } +/** +# HTTP/3 core implementation + +This is the core implementation of HTTP/3 protocol. It implements most of the features of the +protocol. `Http3Client` and `Http3ServerHandler` implement only client and server side behavior. + +The API consists of: +- functions that correspond to the `Http3Client` and `Http3ServerHandler` API: + - `new` + - `close` + - `fetch` - only used by the client-side implementation + - `read_data` + - `stream_reset_send` + - `stream_stop_sending` + - `cancel_fetch` + - `stream_close_send` +- functions that correspond to [`WebTransport`](https://w3c.github.io/webtransport/) functions: + - `webtransport_create_session` - only used by the client-side implementation + - `webtransport_session_accept` - only used by the server-side implementation + - `webtransport_close_session` + - `webtransport_create_stream_local` - this function is called when an application wants to open + a new `WebTransport` stream. For example `Http3Client::webtransport_create_stream` will call + this function. + - `webtransport_create_stream_remote` - this is called when a `WebTransport` stream has been + opened by the peer and this function sets up the appropriate handler for the stream. +- functions that are called by `process_http3` + - `process_sending` - some send-streams are buffered streams(see the Streams section) and this + function is called to trigger sending of the buffer data. +- functions that are called to handle `ConnectionEvent`s: + - `add_new_stream` + - `handle_stream_readable` + - `handle_stream_reset` + - `handle_stream_stop_sending` + - `handle_state_change` + - `handle_zero_rtt_rejected` +- Additional functions: + - `set_features_listener` + - `stream_has_pending_data` + - `has_data_to_send` + - `add_streams` + - `add_recv_stream` + - `queue_control_frame` + - `queue_update_priority` + - `set_0rtt_settings` + - `get_settings` + - `state` + - `webtransport_enabled` + +## Streams + +Each `Http3Connection` holds a list of stream handlers. Each send and receive-handler is registered in +`send_streams` and `recv_streams`. Unidirectional streams are registered only on one of the lists +and bidirectional streams are registered in both lists and the 2 handlers are independent, e.g. one +can be closed and removed ane second may still be active. + +The only streams that are not registered are the local control stream, local QPACK decoder stream, +and local QPACK encoder stream. These streams are send-streams and sending data on this stream is +handled a bit differently. This is done in the `process_sending` function, i.e. the control data is +sent first and QPACK data is sent after regular stream data is sent because this stream may have +new data only after regular streams are handled (TODO we may improve this a bit to send QPACK +commands before headers.) + +There are the following types of streams: +- `Control`: there is only a receiver stream of this type and the handler is `ControlStreamRemote`. +- `Decoder`: there is only a receiver stream of this type and the handler is `DecoderRecvStream`. +- `Encoder`: there is only a receiver stream of this type and the handler is `EncoderRecvStream`. +- `NewStream`: there is only a receiver stream of this type and the handler is + `NewStreamHeadReader`. +- `Http`: `SendMessage` and `RecvMessage` handlers are responsible for this type of streams. +- `Push`: `RecvMessage` is responsible for this type of streams. +- `ExtendedConnect`: `WebTransportSession` is responsible sender and receiver handler. +- `WebTransport(StreamId)`: `WebTransportSendStream` and `WebTransportRecvStream` are responsible + sender and receiver handler. +- `Unknown`: These are all other stream types that are not unknown to the current implementation + and should be handled properly by the spec, e.g., in our implementation the streams are + reset. + +The streams are registered in `send_streams` and `recv_streams` in following ways depending if they +are local or remote: +- local streams: + - all local stream will be registered with the appropriate handler. +- remote streams: + - all new incoming streams are registered with `NewStreamHeadReader`. This is triggered by + `ConnectionEvent::NewStream` and `add_new_stream` is called. + - reading from a `NewStreamHeadReader` stream, via the `receive` function, will decode a stream + type. `NewStreamHeadReader::receive` will return `ReceiveOutput::NewStream(_)` when a stream + type has been decoded. After this point the stream: + - will be regegistered with the appropriate handler, + - will be canceled if is an unknown stream type or + - the connection will fail if it is unallowed stream type (receiveing HTTP request on the + client-side). + The output is handled in `handle_new_stream`, for control, qpack streams and partially + `WebTransport` streams, otherwise the output is handled by `Http3Client` and `Http3ServerHandler`. + + +### Receiving data + +Reading from a stream is triggered by `ConnectionEvent::RecvStreamReadable` events for the stream. +The receive handler is retrieved from `recv_streams` and its `RecvStream::receive` function is +called. + +Receiving data on `Http` streams is also triggered by the `read_data` function. +`ConnectionEvent::RecvStreamReadable` events will trigger reading `HEADERS` frame and frame headers +for `DATA` frames which will produce `Http3ClientEvent` or `Http3ServerEvent` events. The content of +`DATA` frames is read by the application using the `read_data` function. The `read_data` function +may read frame headers for consecutive `DATA` frames. + +On a `WebTransport(_)` stream data will be read only by the `read_data` function. The +`RecvStream::receive` function only produces an `Http3ClientEvent` or `Http3ServerEvent` event. + +The `receive` and `read_data` functions may detect that the stream is done, e.g. FIN received. In +this case, the stream will be removed from the `recv_stream` register, see `remove_recv_stream`. + +### Sending data + +All sender stream handlers have buffers. Data is first written into a buffer before being supplied +to the QUIC layer. All data except the `DATA` frame and `WebTransport(_)`’s payload are written +into the buffer. This includes stream type byte, e.g. `WEBTRANSPORT_STREAM` as well. In the case of +`Http` and `WebTransport(_)` applications can write directly to the QUIC layer using the +`send_data` function to avoid copying data. Sending data via the `send_data` function is only +possible if there is no buffered data. + +If a stream has buffered data it will be registered in the `streams_with_pending_data` queue and +actual sending will be performed in the `process_sending` function call. (This is done in this way, +i.e. data is buffered first and then sent, for 2 reasons: in this way, sending will happen in a +single function, therefore error handling and clean up is easier and the QUIIC layer may not be +able to accept all data and being able to buffer data is required in any case.) + +The `send` and `send_data` functions may detect that the stream is closed and all outstanding data +has been transferred to the QUIC layer. In this case, the stream will be removed from the +`send_stream` register. + +### `ControlStreamRemote` + +The `ControlStreamRemote` handler uses `FrameReader` to read and decode frames received on the +control frame. The `receive` returns `ReceiveOutput::ControlFrames(_)` with a list of control +frames read (the list may be empty). The control frames are handled by `Http3Connection` and/or by +`Http3Client` and `Http3ServerHandler`. + +### `DecoderRecvStream` and `EncoderRecvStream` + +The `receive` functions of these handlers call corresponding `receive` functions of `QPackDecoder` +and `QPackDecoder`. + +`DecoderRecvStream` returns `ReceiveOutput::UnblockedStreams(_)` that may contain a list of stream +ids that are unblocked by receiving qpack decoder commands. `Http3Connection` will handle this +output by calling `receive` for the listed stream ids. + +`EncoderRecvStream` only returns `ReceiveOutput::NoOutput`. + +Both handlers may return an error that will close the connection. + +### `NewStreamHeadReader` + +A new incoming receiver stream registers a `NewStreamHeadReader` handler. This handler reads the +first bytes of a stream to detect a stream type. The `receive` function returns +`ReceiveOutput::NoOutput` if a stream type is still not known by reading the available stream data +or `ReceiveOutput::NewStream(_)`. The handling of the output is explained above. + +### `SendMessage` and `RecvMessage` + +`RecvMessage::receive` only returns `ReceiveOutput::NoOutput`. It also have an event listener of +type `HttpRecvStreamEvents`. The listener is called when headers are ready, or data is ready, etc. + +For example for `Http` stream the listener will produce `HeaderReady` and `DataReadable` events. + +### `WebTransportSession` + +A `WebTransport` session is connected to a control stream that is in essence an HTTP transaction. +Therefore, `WebTransportSession` will internally use a `SendMessage` and `RecvMessage` handler to +handle parsing and sending of HTTP part of the control stream. When HTTP headers are exchenged, +`WebTransportSession` will take over handling of stream data. `WebTransportSession` sets +`WebTransportSessionListener` as the `RecvMessage` event listener. + +`WebTransportSendStream` and `WebTransportRecvStream` are associated with a `WebTransportSession` +and they will be canceled if the session is closed. To be avle to do this `WebTransportSession` +holds a list of its active streams and clean up is done in `remove_extended_connect`. + +### `WebTransportSendStream` and `WebTransportRecvStream` + +`WebTransport` streams are associated with a session. `WebTransportSendStream` and +`WebTransportRecvStream` hold a reference to the session and are registered in the session upon + creation by `Http3Connection`. The `WebTransportSendStream` and `WebTransportRecvStream` + handlers will be unregistered from the session if they are closed, reset, or canceled. + +The call to function `receive` may produce `Http3ClientEvent::DataReadable`. Actual reading of +data is done in the `read_data` function. +*/ #[derive(Debug)] pub(crate) struct Http3Connection { role: Role, @@ -126,10 +342,15 @@ impl Http3Connection { } } + /// This function is called when a not default feature needs to be negotiated. This is currently + /// only used for the `WebTransport` feature. The negotiation is done via the `SETTINGS` frame + /// and when the peer's `SETTINGS` frame has been received the listener will be called. pub fn set_features_listener(&mut self, feature_listener: Http3ClientEvents) { self.webtransport.set_listener(feature_listener); } + /// This function creates and initializes, i.e. send stream type, the control and qpack + /// streams. fn initialize_http3_connection(&mut self, conn: &mut Connection) -> Res<()> { qinfo!([self], "Initialize the http3 connection."); self.control_stream_local.create(conn)?; @@ -173,6 +394,10 @@ impl Http3Connection { !self.streams_with_pending_data.is_empty() } + /// This function calls the `send` function for all streams that have data to send. If a stream + /// has data to send it will be added to the `streams_with_pending_data` list. + /// + /// Control and QPACK streams are handled differently and are never added to the list. fn send_non_control_streams(&mut self, conn: &mut Connection) -> Res<()> { let to_send = mem::take(&mut self.streams_with_pending_data); for stream_id in to_send { @@ -192,7 +417,8 @@ impl Http3Connection { Ok(()) } - /// Call `send` for all streams that need to send data. + /// Call `send` for all streams that need to send data. See explanation for the main structure + /// for more details. pub fn process_sending(&mut self, conn: &mut Connection) -> Res<()> { // check if control stream has data to send. self.control_stream_local @@ -228,6 +454,8 @@ impl Http3Connection { } } + /// This is called when a `ConnectionEvent::NewStream` event is received. This register the + /// stream with a `NewStreamHeadReader` handler. pub fn add_new_stream(&mut self, stream_id: StreamId) { qtrace!([self], "A new stream: {}.", stream_id); self.recv_streams.insert( @@ -236,6 +464,8 @@ impl Http3Connection { ); } + /// The function calls `receive` for a stream. It also deals with the outcome of a read by + /// calling `handle_stream_manipulation_output`. #[allow(clippy::option_if_let_else)] // False positive as borrow scope isn't lexical here. fn stream_receive(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res { qtrace!([self], "Readable stream {}.", stream_id); @@ -271,8 +501,9 @@ impl Http3Connection { /// This function handles reading from all streams, i.e. control, qpack, request/response /// stream and unidi stream that are still do not have a type. /// The function cannot handle: - /// 1) a Push stream (if an unknown unidi stream is decoded to be a push stream) - /// 2) frames `MaxPushId` or `Goaway` must be handled by `Http3Client`/`Server`. + /// 1) a `Push(_)`, `Htttp` or `WebTransportStream(_)` stream + /// 2) frames `MaxPushId`, `PriorityUpdateRequest`, `PriorityUpdateRequestPush` or `Goaway` + /// must be handled by `Http3Client`/`Server`. /// The function returns `ReceiveOutput`. pub fn handle_stream_readable( &mut self, @@ -306,7 +537,7 @@ impl Http3Connection { ReceiveOutput::NewStream(_) => { unreachable!("NewStream should have been handled already") } - _ => Ok(output), + ReceiveOutput::NoOutput => Ok(output), } } @@ -419,6 +650,17 @@ impl Http3Connection { } } + pub fn handle_datagram(&mut self, datagram: &[u8]) { + let mut decoder = Decoder::new(datagram); + let session = decoder + .decode_varint() + .and_then(|id| self.recv_streams.get_mut(&StreamId::from(id))) + .and_then(|stream| stream.webtransport()); + if let Some(s) = session { + s.borrow_mut().datagram(decoder.decode_remainder().to_vec()); + } + } + fn check_stream_exists(&self, stream_type: Http3StreamType) -> Res<()> { if self .recv_streams @@ -431,10 +673,10 @@ impl Http3Connection { } } - /// If the new stream is a control stream, this function creates a proper handler + /// If the new stream is a control or QPACK stream, this function creates a proper handler /// and perform a read. - /// if the new stream is a push stream, the function returns `ReceiveOutput::PushStream` - /// and the caller will handle it. + /// if the new stream is a `Push(_)`, `Http` or `WebTransportStream(_)` stream, the function + /// returns `ReceiveOutput::NewStream(_)` and the caller will handle it. /// If the stream is of a unknown type the stream will be closed. fn handle_new_stream( &mut self, @@ -872,9 +1114,12 @@ impl Http3Connection { conn: &mut Connection, stream_id: StreamId, events: Box, - accept: bool, + accept_res: &WebTransportSessionAcceptAction, ) -> Res<()> { - qtrace!("Respond to WebTransport session with accept={}.", accept); + qtrace!( + "Respond to WebTransport session with accept={}.", + accept_res + ); if !self.webtransport_enabled() { return Err(Error::Unavailable); } @@ -891,17 +1136,17 @@ impl Http3Connection { let send_stream = self.send_streams.get_mut(&stream_id); - match (send_stream, recv_stream, accept) { + match (send_stream, recv_stream, accept_res) { (None, None, _) => Err(Error::InvalidStreamId), (None, Some(_), _) | (Some(_), None, _) => { // TODO this needs a better error self.cancel_fetch(stream_id, Error::HttpRequestRejected.code(), conn)?; Err(Error::InvalidStreamId) } - (Some(s), Some(_r), false) => { + (Some(s), Some(_r), WebTransportSessionAcceptAction::Reject(headers)) => { if s.http_stream() .ok_or(Error::InvalidStreamId)? - .send_headers(&[Header::new(":status", "404")], conn) + .send_headers(headers, conn) .is_ok() { mem::drop(self.stream_close_send(conn, stream_id)); @@ -912,7 +1157,7 @@ impl Http3Connection { } Ok(()) } - (Some(s), Some(_r), true) => { + (Some(s), Some(_r), WebTransportSessionAcceptAction::Accept) => { if s.http_stream() .ok_or(Error::InvalidStreamId)? .send_headers(&[Header::new(":status", "200")], conn) @@ -1090,8 +1335,25 @@ impl Http3Connection { } } - // If the control stream has received frames MaxPushId or Goaway which handling is specific to - // the client and server, we must give them to the specific client/server handler. + pub fn webtransport_send_datagram( + &mut self, + session_id: StreamId, + conn: &mut Connection, + buf: &[u8], + id: impl Into, + ) -> Res<()> { + self.recv_streams + .get_mut(&session_id) + .ok_or(Error::InvalidStreamId)? + .webtransport() + .ok_or(Error::InvalidStreamId)? + .borrow_mut() + .send_datagram(conn, buf, id) + } + + /// If the control stream has received frames `MaxPushId`, `Goaway`, `PriorityUpdateRequest` or + /// `PriorityUpdateRequestPush` which handling is specific to the client and server, we must + /// give them to the specific client/server handler. fn handle_control_frame(&mut self, f: HFrame) -> Res> { qinfo!([self], "Handle a control frame {:?}", f); if !matches!(f, HFrame::Settings { .. }) @@ -1266,11 +1528,7 @@ impl Http3Connection { wt: &Rc>, conn: &mut Connection, ) { - let out = wt.borrow_mut().take_sub_streams(); - if out.is_none() { - return; - } - let (recv, send) = out.unwrap(); + let (recv, send) = wt.borrow_mut().take_sub_streams(); for id in recv { qtrace!("Remove the extended connect sub receiver stream {}", id); diff --git a/third_party/rust/neqo-http3/src/connection_client.rs b/third_party/rust/neqo-http3/src/connection_client.rs index 6980f26a6f83..2735cf44fdad 100644 --- a/third_party/rust/neqo-http3/src/connection_client.rs +++ b/third_party/rust/neqo-http3/src/connection_client.rs @@ -21,10 +21,11 @@ use neqo_common::{ use neqo_crypto::{agent::CertificateInfo, AuthenticationStatus, ResumptionToken, SecretAgentInfo}; use neqo_qpack::Stats as QpackStats; use neqo_transport::{ - AppError, Connection, ConnectionEvent, ConnectionId, ConnectionIdGenerator, Output, - Stats as TransportStats, StreamId, StreamType, Version, ZeroRttState, + AppError, Connection, ConnectionEvent, ConnectionId, ConnectionIdGenerator, DatagramTracking, + Output, Stats as TransportStats, StreamId, StreamType, Version, ZeroRttState, }; use std::cell::RefCell; +use std::convert::TryFrom; use std::fmt::Debug; use std::fmt::Display; use std::mem; @@ -59,6 +60,231 @@ fn alpn_from_quic_version(version: Version) -> &'static str { } } +/// # The HTTP/3 client API +/// +/// This module implements the HTTP/3 client API. The main implementation of the protocol is in +/// [connection.rs](https://github.com/mozilla/neqo/blob/main/neqo-http3/src/connection.rs) which +/// implements common behavior for the client-side and the server-side. `Http3Client` structure +/// implements the public API and set of functions that differ between the client and the server. + +/// The API is used for: +/// - create and close an endpoint: +/// - [`new`](struct.Http3Client.html#method.new) +/// - [`new_with_conn`](struct.Http3Client.html#method.new_with_conn) +/// - [`close`](struct.Http3Client.html#method.close) +/// - configuring an endpoint: +/// - [`authenticated`](struct.Http3Client.html#method.authenticated) +/// - [`enable_ech`](struct.Http3Client.html#method.enable_ech) +/// - [`enable_resumption`](struct.Http3Client.html#method.enable_resumption) +/// - [`initiate_key_update`](struct.Http3Client.html#method.initiate_key_update) +/// - [`set_qlog`](struct.Http3Client.html#method.set_qlog) +/// - retrieving information about a connection: +/// - [`peer_certificate`](struct.Http3Client.html#method.peer_certificate) +/// - [`qpack_decoder_stats`](struct.Http3Client.html#method.qpack_decoder_stats) +/// - [`qpack_encoder_stats`](struct.Http3Client.html#method.qpack_encoder_stats) +/// - [`transport_stats`](struct.Http3Client.html#method.transport_stats) +/// - [`state`](struct.Http3Client.html#method.state) +/// - [`take_resumption_token`](struct.Http3Client.html#method.take_resumption_token) +/// - [`tls_inf`](struct.Http3Client.html#method.tls_info) +/// - driving HTTP/3 session: +/// - [`process_output`](struct.Http3Client.html#method.process_output) +/// - [`process_input`](struct.Http3Client.html#method.process_input) +/// - [`process`](struct.Http3Client.html#method.process) +/// - create requests, send/receive data, and cancel requests: +/// - [`fetch`](struct.Http3Client.html#method.fetch) +/// - [`send_data`](struct.Http3Client.html#method.send_data) +/// - [`read_dara`](struct.Http3Client.html#method.read_data) +/// - [`stream_close_send`](struct.Http3Client.html#method.stream_close_send) +/// - [`cancel_fetch`](struct.Http3Client.html#method.cancel_fetch) +/// - [`stream_reset_send`](struct.Http3Client.html#method.stream_reset_send) +/// - [`stream_stop_sending`](struct.Http3Client.html#method.stream_stop_sending) +/// - [`set_stream_max_data`](struct.Http3Client.html#method.set_stream_max_data) +/// - priority feature: +/// - [`priority_update`](struct.Http3Client.html#method.priority_update) +/// - `WebTransport` feature: +/// - [`webtransport_create_session`](struct.Http3Client.html#method.webtransport_create_session) +/// - [`webtransport_close_session`](struct.Http3Client.html#method.webtransport_close_session) +/// - [`webtransport_create_stream`](struct.Http3Client.html#method.webtransport_create_sstream) +/// - [`webtransport_enabled`](struct.Http3Client.html#method.webtransport_enabled) +/// +/// ## Examples +/// +/// ### Fetching a resource +/// +/// ```ignore +/// let mut client = Http3Client::new(...); +/// +/// // Perform a handshake +/// ... +/// +/// let req = client +/// .fetch( +/// Instant::now(), +/// "GET", +/// &("https", "something.com", "/"), +/// &[Header::new("example1", "value1"), Header::new("example1", "value2")], +/// Priority::default(), +/// ) +/// .unwrap(); +/// +/// client.stream_close_send(req).unwrap(); +/// +/// loop { +/// // exchange packets +/// ... +/// +/// while let Some(event) = client.next_event() { +/// match event { +/// Http3ClientEvent::HeaderReady { stream_id, headers, interim, fin } => { +/// println!("New response headers received for stream {:?} [fin={?}, interim={:?}]: {:?}", +/// stream_id, +/// fin, +/// interim, +/// headers, +/// ); +/// } +/// Http3ClientEvent::DataReadable { stream_id } => { +/// println!("New data available on stream {}", stream_id); +/// let mut buf = [0; 100]; +/// let (amount, fin) = client.read_data(now(), stream_id, &mut buf).unwrap(); +/// println!("Read {:?} bytes from stream {:?} [fin={?}]", +/// amount, +/// stream_id, +/// fin, +/// ); +/// } +/// _ => { +/// println!("Unhandled event {:?}", event); +/// } +/// } +/// } +/// } +///``` +/// +/// ### Creating a `WebTransport` session +/// +/// ```ignore +/// let mut client = Http3Client::new(...); +/// +/// // Perform a handshake +/// ... +/// +/// // Create a session +/// let wt_session_id = client +/// .webtransport_create_session(now(), &("https", "something.com", "/"), &[]) +/// .unwrap(); +/// +/// loop { +/// // exchange packets +/// ... +/// +/// while let Some(event) = client.next_event() { +/// match event { +/// Http3ClientEvent::WebTransport(WebTransportEvent::Session{ +/// stream_id, +/// status +/// }) => { +/// println!("The response from the server: WebTransport session ID {:?} status={:?}", +/// stream_id, +/// status, +/// ); +/// } +/// _ => { +/// println!("Unhandled event {:?}", event); +/// } +/// } +/// } +/// } +/// +///``` +/// +/// ### `WebTransport`: create a stream, send and receive data on the stream +/// +/// ```ignore +/// const BUF_CLIENT: &[u8] = &[0; 10]; +/// // wt_session_id is the session ID of a newly created WebTransport session, see the example above. +/// +/// // create a stream +/// let wt_stream_id = client +/// .webtransport_create_stream(wt_session_id, StreamType::BiDi) +/// .unwrap(); +/// +/// // send data +/// let data_sent = client.send_data(wt_stream_id, BUF_CLIENT).unwrap(); +/// assert_eq!(data_sent, BUF_CLIENT.len()); +/// +/// // close stream for sending +/// client.stream_close_send(wt_stream_id).unwrap(); +/// +/// // wait for data from the server +/// loop { +/// // exchange packets +/// ... +/// +/// while let Some(event) = client.next_event() { +/// match event { +/// Http3ClientEvent::DataReadable{ stream_id } => { +/// println!("Data receivedd form the server on WebTransport stream ID {:?}", +/// stream_id, +/// ); +/// let mut buf = [0; 100]; +/// let (amount, fin) = client.read_data(now(), stream_id, &mut buf).unwrap(); +/// println!("Read {:?} bytes from stream {:?} [fin={?}]", +/// amount, +/// stream_id, +/// fin, +/// ); +/// } +/// _ => { +/// println!("Unhandled event {:?}", event); +/// } +/// } +/// } +/// } +/// ``` +/// +/// ### `WebTransport`: receive a new stream form the server +/// +/// ```ignore +/// // wt_session_id is the session ID of a newly created WebTransport session, see the example above. +/// +/// // wait for a new stream from the server +/// loop { +/// // exchange packets +/// ... +/// +/// while let Some(event) = client.next_event() { +/// match event { +/// Http3ClientEvent::WebTransport(WebTransportEvent::NewStream { +/// stream_id, +/// session_id, +/// }) => { +/// println!("New stream received on session{:?}, stream id={:?} stream type={:?}", +/// sesson_id.stream_id(), +/// stream_id.stream_id(), +/// stream_id.stream_type() +/// ); +/// } +/// Http3ClientEvent::DataReadable{ stream_id } => { +/// println!("Data receivedd form the server on WebTransport stream ID {:?}", +/// stream_id, +/// ); +/// let mut buf = [0; 100]; +/// let (amount, fin) = client.read_data(now(), stream_id, &mut buf).unwrap(); +/// println!("Read {:?} bytes from stream {:?} [fin={:?}]", +/// amount, +/// stream_id, +/// fin, +/// ); +/// } +/// _ => { +/// println!("Unhandled event {:?}", event); +/// } +/// } +/// } +/// } +/// ``` +/// pub struct Http3Client { conn: Connection, base_handler: Http3Connection, @@ -75,7 +301,7 @@ impl Display for Http3Client { impl Http3Client { /// # Errors /// Making a `neqo-transport::connection` may produce an error. This can only be a crypto error if - /// the socket can't be created or configured. + /// the crypto context can't be created or configured. pub fn new( server_name: impl Into, cid_manager: Rc>, @@ -103,6 +329,10 @@ impl Http3Client { )) } + /// This is a similar function to `new`. In this case, `neqo-transport::connection` has been + /// already created. + /// + /// It is recommended to use `new` instead. #[must_use] pub fn new_with_conn(c: Connection, http3_parameters: Http3Parameters) -> Self { let events = Http3ClientEvents::default(); @@ -125,6 +355,7 @@ impl Http3Client { self.conn.role() } + /// The function returns the current state of the connection. #[must_use] pub fn state(&self) -> Http3State { self.base_handler.state() @@ -142,6 +373,10 @@ impl Http3Client { } /// This called when peer certificates have been verified. + /// + /// `Http3ClientEvent::AuthenticationNeeded` event is emitted when peer’s certificates are + /// available and need to be verified. When the verification is completed this function is + /// called. To inform HTTP/3 session of the verification results. pub fn authenticated(&mut self, status: AuthenticationStatus, now: Instant) { self.conn.authenticated(status, now); } @@ -175,12 +410,18 @@ impl Http3Client { }) } - /// Get a resumption token. The correct way to obtain a resumption token is - /// waiting for the `Http3ClientEvent::ResumptionToken` event. However, some - /// servers don't send `NEW_TOKEN` frames and so that event might be slow in - /// arriving. This is especially a problem for short-lived connections, where - /// the connection is closed before any events are released. This retrieves - /// the token, without waiting for the `NEW_TOKEN` frame to arrive. + /// The correct way to obtain a resumption token is to wait for the + /// `Http3ClientEvent::ResumptionToken` event. To emit the event we are waiting for a + /// resumtion token and a `NEW_TOKEN` frame to arrive. Some servers don't send `NEW_TOKEN` + /// frames and in this case, we wait for 3xPTO before emitting an event. This is especially a + /// problem for short-lived connections, where the connection is closed before any events are + /// released. This function retrieves the token, without waiting for a `NEW_TOKEN` frame to + /// arrive. + /// + /// In addition to the token, HTTP/3 settings are encoded into the token before giving it to + /// the application(`encode_resumption_token`). When the resumption token is supplied to a new + /// connection the HTTP/3 setting will be decoded and used until the setting are received from + /// the server. pub fn take_resumption_token(&mut self, now: Instant) -> Option { self.conn .take_resumption_token(now) @@ -188,6 +429,10 @@ impl Http3Client { } /// This may be call if an application has a resumption token. This must be called before connection starts. + /// + /// The resumption token also contains encoded HTTP/3 settings. The settings will be decoded + /// and used until the setting are received from the server. + /// /// # Errors /// An error is return if token cannot be decoded or a connection is is a wrong state. /// # Panics @@ -201,7 +446,7 @@ impl Http3Client { Some(v) => v, None => return Err(Error::InvalidResumptionToken), }; - qtrace!([self], " settings {}", hex_with_len(&settings_slice)); + qtrace!([self], " settings {}", hex_with_len(settings_slice)); let mut dec_settings = Decoder::from(settings_slice); let mut settings = HSettings::default(); Error::map_error( @@ -209,7 +454,7 @@ impl Http3Client { Error::InvalidResumptionToken, )?; let tok = dec.decode_remainder(); - qtrace!([self], " Transport token {}", hex(&tok)); + qtrace!([self], " Transport token {}", hex(tok)); self.conn.enable_resumption(now, tok)?; if self.conn.state().closed() { let state = self.conn.state().clone(); @@ -260,8 +505,9 @@ impl Http3Client { // API: Request/response - /// This is call to make a new http request. Each request can have headers and they are added when request - /// is created. A response body may be added by calling `send_data`. + /// The function fetches a resource using `method`, `target` and `headers`. A response body + /// may be added by calling `send_data`. `stream_close_send` must be sent to finish the request + /// even if request data are not sent. /// # Errors /// If a new stream cannot be created an error will be return. /// # Panics @@ -308,8 +554,8 @@ impl Http3Client { self.base_handler.queue_update_priority(stream_id, priority) } - /// An application may reset a stream(request). - /// Both sides, sending and receiving side, will be closed. + /// An application may cancel a stream(request). + /// Both sides, the receiviing and sending side, sending and receiving side, will be closed. /// # Errors /// An error will be return if a stream does not exist. pub fn cancel_fetch(&mut self, stream_id: StreamId, error: AppError) -> Res<()> { @@ -343,7 +589,10 @@ impl Http3Client { .stream_stop_sending(&mut self.conn, stream_id, error) } - /// To supply a request body this function is called (headers are supplied through the `fetch` function.) + /// This function is used for regular HTTP requests and `WebTransport` streams. + /// In the case of regular HTTP requests, the request body is supplied using this function, and + /// headers are supplied through the `fetch` function. + /// /// # Errors /// `InvalidStreamId` if the stream does not exist, /// `AlreadyClosed` if the stream has already been closed. @@ -478,6 +727,35 @@ impl Http3Client { ) } + /// Send `WebTransport` datagram. + /// # Errors + /// It may return `InvalidStreamId` if a stream does not exist anymore. + /// The function returns `TooMuchData` if the supply buffer is bigger than + /// the allowed remote datagram size. + pub fn webtransport_send_datagram( + &mut self, + session_id: StreamId, + buf: &[u8], + id: impl Into, + ) -> Res<()> { + qtrace!("webtransport_send_datagram session:{:?}", session_id); + self.base_handler + .webtransport_send_datagram(session_id, &mut self.conn, buf, id) + } + + /// Returns the current max size of a datagram that can fit into a packet. + /// The value will change over time depending on the encoded size of the + /// packet number, ack frames, etc. + /// # Errors + /// The function returns `NotAvailable` if datagrams are not enabled. + /// # Panics + /// This cannot panic. The max varint length is 8. + pub fn webtransport_max_datagram_size(&self, session_id: StreamId) -> Res { + Ok(self.conn.max_datagram_size()? + - u64::try_from(Encoder::varint_len(session_id.as_u64())).unwrap()) + } + + /// This function combines `process_input` and `process_output` function. pub fn process(&mut self, dgram: Option, now: Instant) -> Output { qtrace!([self], "Process."); if let Some(d) = dgram { @@ -486,19 +764,34 @@ impl Http3Client { self.process_output(now) } - /// Supply an incoming QUIC packet. + /// The function should be called when there is a new UDP packet available. The function will + /// handle the packet payload. + /// + /// First, the payload will be handled by the QUIC layer. Afterward, `process_http3` will be + /// called to handle new [`ConnectionEvent`][1]s. + /// + /// After this function is called `process_output` should be called to check whether new + /// packets need to be sent or if a timer needs to be updated. + /// + /// [1]: ../neqo_transport/enum.ConnectionEvent.html pub fn process_input(&mut self, dgram: Datagram, now: Instant) { qtrace!([self], "Process input."); self.conn.process_input(dgram, now); self.process_http3(now); } - // Only used by neqo-interop + /// This should not be used because it gives access to functionalities that may disrupt the + /// proper functioning of the HTTP/3 session. + /// Only used by `neqo-interop`. pub fn conn(&mut self) -> &mut Connection { &mut self.conn } /// Process HTTP3 layer. + /// When `process_output`, `process_input`, or `process` is called we must call this function + /// as well. The functions calls `Http3Client::check_connection_events` to handle events from + /// the QUC layer and calls `Http3Connection::process_sending` to ensure that HTTP/3 layer + /// data, e.g. control frames, are sent. fn process_http3(&mut self, now: Instant) { qtrace!([self], "Process http3 internal."); match self.base_handler.state() { @@ -521,8 +814,32 @@ impl Http3Client { } } - /// Get packet that need to be written into a UDP socket or a timer value if there is no data to send. - /// This function should be called repeatedly until timer value is returned. + /// The function should be called to check if there is a new UDP packet to be sent. It should + /// be called after a new packet is received and processed and after a timer expires (QUIC + /// needs timers to handle events like PTO detection and timers are not implemented by the neqo + /// library, but instead must be driven by the application). + /// + /// `process_output` can return: + /// - a [`Output::Datagram(Datagram)`][1]: data that should be sent as a UDP payload, + /// - a [`Output::Callback(Duration)`][1]: the duration of a timer. `process_output` should be called at least after the time expires, + /// - [`Output::None`][1]: this is returned when `Nttp3Client` is done and can be destroyed. + /// + /// The application should call this function repeatedly until a timer value or None is + /// returned. After that, the application should call the function again if a new UDP packet is + /// received and processed or the timer value expires. + /// + /// The HTTP/3 neqo implementation drives the HTTP/3 and QUC layers, therefore this function + /// will call both layers: + /// - First it calls HTTP/3 layer processing (`process_http3`) to make sure the layer writes + /// data to QUIC layer or cancels streams if needed. + /// - Then QUIC layer processing is called - [`Connection::process_output`][3]. This produces a + /// packet or a timer value. It may also produce ned [`ConnectionEvent`][2]s, e.g. connection + /// state-change event. + /// - Therefore the HTTP/3 layer processing (`process_http3`) is called again. + /// + /// [1]: ../neqo_transport/enum.Output.html + /// [2]: ../neqo_transport/struct.ConnectionEvents.html + /// [3]: ../neqo_transport/struct.Connection.html#method.process_output pub fn process_output(&mut self, now: Instant) -> Output { qtrace!([self], "Process output."); @@ -537,8 +854,8 @@ impl Http3Client { out } - // This function takes the provided result and check for an error. - // An error results in closing the connection. + /// This function takes the provided result and check for an error. + /// An error results in closing the connection. fn check_result(&mut self, now: Instant, res: &Res) -> bool { match &res { Err(Error::HttpGoaway) => { @@ -559,13 +876,31 @@ impl Http3Client { } } - // If this return an error the connection must be closed. + /// This function checks [`ConnectionEvent`][2]s emitted by the QUIC layer, e.g. connection change + /// state events, new incoming stream data is available, a stream is was reset, etc. The HTTP/3 + /// layer needs to handle these events. Most of the events are handled by + /// [`Http3Connection`][1] by calling appropriate functions, e.g. `handle_state_change`, + /// `handle_stream_reset`, etc. [`Http3Connection`][1] handle functionalities that are common + /// for the client and server side. Some of the functionalities are specific to the client and + /// they are handled by `Http3Client`. For example, [`ConnectionEvent::RecvStreamReadable`][3] event + /// is handled by `Http3Client::handle_stream_readable`. The function calls + /// `Http3Connection::handle_stream_readable` and then hands the return value as appropriate + /// for the client-side. + /// + /// [1]: https://github.com/mozilla/neqo/blob/main/neqo-http3/src/connection.rs + /// [2]: ../neqo_transport/enum.ConnectionEvent.html + /// [3]: ../neqo_transport/enum.ConnectionEvent.html#variant.RecvStreamReadable fn check_connection_events(&mut self) -> Res<()> { qtrace!([self], "Check connection events."); while let Some(e) = self.conn.next_event() { qdebug!([self], "check_connection_events - event {:?}.", e); match e { ConnectionEvent::NewStream { stream_id } => { + // During this event we only add a new stream to the Http3Connection stream list, + // with NewStreamHeadReader stream handler. + // This function will not read from the stream and try to decode the stream. + // RecvStreamReadable will be emitted after this event and reading, i.e. decoding + // of a stream will happen during that event. self.base_handler.add_new_stream(stream_id); } ConnectionEvent::SendStreamWritable { stream_id } => { @@ -617,8 +952,10 @@ impl Http3Client { self.events.resumption_token(t); } } + ConnectionEvent::Datagram(dgram) => { + self.base_handler.handle_datagram(&dgram); + } ConnectionEvent::SendStreamComplete { .. } - | ConnectionEvent::Datagram { .. } | ConnectionEvent::OutgoingDatagramOutcome { .. } | ConnectionEvent::IncomingDatagramDropped => {} } @@ -626,6 +963,25 @@ impl Http3Client { Ok(()) } + /// This function handled new data available on a stream. It calls + /// `Http3Client::handle_stream_readable` and handles its response. Reading streams are mostly + /// handled by [`Http3Connection`][1] because most part of it is common for the client and + /// server. The following actions need to be handled by the client-specific code: + /// - `ReceiveOutput::NewStream(NewStreamType::Push(_))` - the server cannot receive a push + /// stream, + /// - `ReceiveOutput::NewStream(NewStreamType::Http)` - client cannot receive a + /// server-initiated HTTP request, + /// - `ReceiveOutput::NewStream(NewStreamType::WebTransportStream(_))` - because + /// `Http3ClientEvents`is needed and events handler is specific to the client. + /// - `ReceiveOutput::ControlFrames(control_frames)` - some control frame handling differs + /// between the client and the server: + /// - `HFrame::CancelPush` - only the client-side may receive it, + /// - `HFrame::MaxPushId { .. }`, `HFrame::PriorityUpdateRequest { .. } ` and + /// `HFrame::PriorityUpdatePush` can only be receive on the server side, + /// - `HFrame::Goaway { stream_id }` needs specific handling by the client by the protocol + /// specification. + /// + /// [1]: https://github.com/mozilla/neqo/blob/main/neqo-http3/src/connection.rs fn handle_stream_readable(&mut self, stream_id: StreamId) -> Res<()> { match self .base_handler @@ -4326,7 +4682,7 @@ mod tests { &mut client, &mut server, request_stream_id, - &[0x0, 0x3, 0x61, 0x62, 0x63], // a data frame + [0x0, 0x3, 0x61, 0x62, 0x63], // a data frame false, ); @@ -4351,7 +4707,7 @@ mod tests { &mut client, &mut server, request_stream_id, - &[0x0, 0x0], + [0x0, 0x0], true, ); diff --git a/third_party/rust/neqo-http3/src/connection_server.rs b/third_party/rust/neqo-http3/src/connection_server.rs index b8e42342492a..f3b1bb14128f 100644 --- a/third_party/rust/neqo-http3/src/connection_server.rs +++ b/third_party/rust/neqo-http3/src/connection_server.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::connection::{Http3Connection, Http3State}; +use crate::connection::{Http3Connection, Http3State, WebTransportSessionAcceptAction}; use crate::frames::HFrame; use crate::recv_message::{RecvMessage, RecvMessageInfo}; use crate::send_message::SendMessage; @@ -14,7 +14,9 @@ use crate::{ ReceiveOutput, Res, }; use neqo_common::{event::Provider, qdebug, qinfo, qtrace, Header, MessageType, Role}; -use neqo_transport::{AppError, Connection, ConnectionEvent, StreamId, StreamType}; +use neqo_transport::{ + AppError, Connection, ConnectionEvent, DatagramTracking, StreamId, StreamType, +}; use std::rc::Rc; use std::time::Instant; @@ -140,7 +142,7 @@ impl Http3ServerHandler { &mut self, conn: &mut Connection, stream_id: StreamId, - accept: bool, + accept: &WebTransportSessionAcceptAction, ) -> Res<()> { self.needs_processing = true; self.base_handler.webtransport_session_accept( @@ -185,6 +187,18 @@ impl Http3ServerHandler { ) } + pub fn webtransport_send_datagram( + &mut self, + conn: &mut Connection, + session_id: StreamId, + buf: &[u8], + id: impl Into, + ) -> Res<()> { + self.needs_processing = true; + self.base_handler + .webtransport_send_datagram(session_id, conn, buf, id) + } + /// Process HTTTP3 layer. pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) { qtrace!([self], "Process http3 internal."); @@ -273,13 +287,13 @@ impl Http3ServerHandler { s.stream_writable(); } } + ConnectionEvent::Datagram(dgram) => self.base_handler.handle_datagram(&dgram), ConnectionEvent::AuthenticationNeeded | ConnectionEvent::EchFallbackAuthenticationNeeded { .. } | ConnectionEvent::ZeroRttRejected | ConnectionEvent::ResumptionToken(..) => return Err(Error::HttpInternal(4)), ConnectionEvent::SendStreamComplete { .. } | ConnectionEvent::SendStreamCreatable { .. } - | ConnectionEvent::Datagram { .. } | ConnectionEvent::OutgoingDatagramOutcome { .. } | ConnectionEvent::IncomingDatagramDropped => {} } diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/mod.rs b/third_party/rust/neqo-http3/src/features/extended_connect/mod.rs index cc0a661ed98e..7fa1241f9b36 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/mod.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/mod.rs @@ -6,8 +6,8 @@ #![allow(clippy::module_name_repetitions)] -pub mod webtransport_session; -pub mod webtransport_streams; +pub(crate) mod webtransport_session; +pub(crate) mod webtransport_streams; use crate::client_events::Http3ClientEvents; use crate::features::NegotiationState; @@ -15,7 +15,7 @@ use crate::settings::{HSettingType, HSettings}; use crate::{CloseType, Http3StreamInfo, Http3StreamType}; use neqo_transport::{AppError, StreamId}; use std::fmt::Debug; -pub use webtransport_session::WebTransportSession; +pub(crate) use webtransport_session::WebTransportSession; #[derive(Debug, PartialEq, Eq, Clone)] pub enum SessionCloseReason { @@ -32,13 +32,13 @@ impl From for SessionCloseReason { } CloseType::Done => SessionCloseReason::Clean { error: 0, - message: "".to_string(), + message: String::new(), }, } } } -pub trait ExtendedConnectEvents: Debug { +pub(crate) trait ExtendedConnectEvents: Debug { fn session_start(&self, connect_type: ExtendedConnectType, stream_id: StreamId, status: u16); fn session_end( &self, @@ -47,10 +47,11 @@ pub trait ExtendedConnectEvents: Debug { reason: SessionCloseReason, ); fn extended_connect_new_stream(&self, stream_info: Http3StreamInfo); + fn new_datagram(&self, session_id: StreamId, datagram: Vec); } #[derive(Debug, PartialEq, Copy, Clone, Eq)] -pub enum ExtendedConnectType { +pub(crate) enum ExtendedConnectType { WebTransport, } @@ -61,12 +62,6 @@ impl ExtendedConnectType { "webtransport" } - #[must_use] - #[allow(clippy::unused_self)] // this will change when there is more types of the extended CONNECT. - pub fn setting_type(self) -> HSettingType { - HSettingType::EnableWebTransport - } - #[allow(clippy::unused_self)] // This will change when we have more features using ExtendedConnectType. #[must_use] pub fn get_stream_type(self, session_id: StreamId) -> Http3StreamType { @@ -82,7 +77,7 @@ impl From for HSettingType { } #[derive(Debug)] -pub struct ExtendedConnectFeature { +pub(crate) struct ExtendedConnectFeature { feature_negotiation: NegotiationState, } @@ -107,3 +102,5 @@ impl ExtendedConnectFeature { self.feature_negotiation.enabled() } } +#[cfg(test)] +mod tests; diff --git a/third_party/rust/neqo-http3/tests/mod.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/mod.rs similarity index 100% rename from third_party/rust/neqo-http3/tests/mod.rs rename to third_party/rust/neqo-http3/src/features/extended_connect/tests/mod.rs diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/datagrams.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/datagrams.rs new file mode 100644 index 000000000000..2750f0f80991 --- /dev/null +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/datagrams.rs @@ -0,0 +1,128 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::features::extended_connect::tests::webtransport::{ + wt_default_parameters, WtTest, DATAGRAM_SIZE, +}; +use crate::{Error, Http3Parameters}; +use neqo_common::Encoder; +use neqo_transport::Error as TransportError; +use std::convert::TryFrom; + +const DGRAM: &[u8] = &[0, 100]; + +#[test] +fn no_datagrams() { + let mut wt = WtTest::new_with_params( + Http3Parameters::default().webtransport(true), + Http3Parameters::default().webtransport(true), + ); + let mut wt_session = wt.create_wt_session(); + + assert_eq!( + wt_session.max_datagram_size(), + Err(Error::TransportError(TransportError::NotAvailable)) + ); + assert_eq!( + wt.max_datagram_size(wt_session.stream_id()), + Err(Error::TransportError(TransportError::NotAvailable)) + ); + + assert_eq!( + wt_session.send_datagram(DGRAM, None), + Err(Error::TransportError(TransportError::TooMuchData)) + ); + assert_eq!( + wt.send_datagram(wt_session.stream_id(), DGRAM), + Err(Error::TransportError(TransportError::TooMuchData)) + ); + + wt.exchange_packets(); + wt.check_no_datagram_received_client(); + wt.check_no_datagram_received_server(); +} + +#[test] +fn datagrams() { + let mut wt = WtTest::new(); + let mut wt_session = wt.create_wt_session(); + + assert_eq!( + wt_session.max_datagram_size(), + Ok(DATAGRAM_SIZE + - u64::try_from(Encoder::varint_len(wt_session.stream_id().as_u64())).unwrap()) + ); + assert_eq!( + wt.max_datagram_size(wt_session.stream_id()), + Ok(DATAGRAM_SIZE + - u64::try_from(Encoder::varint_len(wt_session.stream_id().as_u64())).unwrap()) + ); + + assert_eq!(wt_session.send_datagram(DGRAM, None), Ok(())); + assert_eq!(wt.send_datagram(wt_session.stream_id(), DGRAM), Ok(())); + + wt.exchange_packets(); + wt.check_datagram_received_client(wt_session.stream_id(), DGRAM); + wt.check_datagram_received_server(&wt_session, DGRAM); +} + +#[test] +fn datagrams_server_only() { + let mut wt = WtTest::new_with_params( + Http3Parameters::default().webtransport(true), + wt_default_parameters(), + ); + let mut wt_session = wt.create_wt_session(); + + assert_eq!( + wt_session.max_datagram_size(), + Err(Error::TransportError(TransportError::NotAvailable)) + ); + assert_eq!( + wt.max_datagram_size(wt_session.stream_id()), + Ok(DATAGRAM_SIZE + - u64::try_from(Encoder::varint_len(wt_session.stream_id().as_u64())).unwrap()) + ); + + assert_eq!( + wt_session.send_datagram(DGRAM, None), + Err(Error::TransportError(TransportError::TooMuchData)) + ); + assert_eq!(wt.send_datagram(wt_session.stream_id(), DGRAM), Ok(())); + + wt.exchange_packets(); + wt.check_datagram_received_server(&wt_session, DGRAM); + wt.check_no_datagram_received_client(); +} + +#[test] +fn datagrams_client_only() { + let mut wt = WtTest::new_with_params( + wt_default_parameters(), + Http3Parameters::default().webtransport(true), + ); + let mut wt_session = wt.create_wt_session(); + + assert_eq!( + wt_session.max_datagram_size(), + Ok(DATAGRAM_SIZE + - u64::try_from(Encoder::varint_len(wt_session.stream_id().as_u64())).unwrap()) + ); + assert_eq!( + wt.max_datagram_size(wt_session.stream_id()), + Err(Error::TransportError(TransportError::NotAvailable)) + ); + + assert_eq!(wt_session.send_datagram(DGRAM, None), Ok(())); + assert_eq!( + wt.send_datagram(wt_session.stream_id(), DGRAM), + Err(Error::TransportError(TransportError::TooMuchData)) + ); + + wt.exchange_packets(); + wt.check_datagram_received_client(wt_session.stream_id(), DGRAM); + wt.check_no_datagram_received_server(); +} diff --git a/third_party/rust/neqo-http3/tests/webtransport/mod.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs similarity index 82% rename from third_party/rust/neqo-http3/tests/webtransport/mod.rs rename to third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs index 95266b5b7b9a..2e073f665046 100644 --- a/third_party/rust/neqo-http3/tests/webtransport/mod.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs @@ -4,46 +4,57 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +mod datagrams; mod negotiation; mod sessions; mod streams; use neqo_common::event::Provider; -use neqo_crypto::AuthenticationStatus; -use neqo_http3::{ +use crate::{ features::extended_connect::SessionCloseReason, Error, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, Http3State, WebTransportEvent, WebTransportRequest, WebTransportServerEvent, + WebTransportSessionAcceptAction, }; -use neqo_transport::{StreamId, StreamType}; +use neqo_crypto::AuthenticationStatus; +use neqo_transport::{ConnectionParameters, StreamId, StreamType}; use std::cell::RefCell; use std::rc::Rc; + use test_fixture::{ addr, anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ALPN_H3, DEFAULT_KEYS, DEFAULT_SERVER_NAME, }; -pub fn default_http3_client(webtransport: bool) -> Http3Client { +const DATAGRAM_SIZE: u64 = 1200; + +pub fn wt_default_parameters() -> Http3Parameters { + Http3Parameters::default() + .webtransport(true) + .connection_parameters(ConnectionParameters::default().datagram_size(DATAGRAM_SIZE)) +} + +pub fn default_http3_client(client_params: Http3Parameters) -> Http3Client { fixture_init(); Http3Client::new( DEFAULT_SERVER_NAME, Rc::new(RefCell::new(CountingConnectionIdGenerator::default())), addr(), addr(), - Http3Parameters::default().webtransport(webtransport), + client_params, now(), ) .expect("create a default client") } -pub fn default_http3_server(webtransport: bool) -> Http3Server { +pub fn default_http3_server(server_params: Http3Parameters) -> Http3Server { Http3Server::new( now(), DEFAULT_KEYS, DEFAULT_ALPN_H3, anti_replay(), Rc::new(RefCell::new(CountingConnectionIdGenerator::default())), - Http3Parameters::default().webtransport(webtransport), + server_params, None, ) .expect("create a server") @@ -86,12 +97,15 @@ fn connect_with(client: &mut Http3Client, server: &mut Http3Server) { let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); - let _ = server.process(out.dgram(), now()); + std::mem::drop(server.process(out.dgram(), now())); } -fn connect(wt_enable_client: bool, wt_enable_server: bool) -> (Http3Client, Http3Server) { - let mut client = default_http3_client(wt_enable_client); - let mut server = default_http3_server(wt_enable_server); +fn connect( + client_params: Http3Parameters, + server_params: Http3Parameters, +) -> (Http3Client, Http3Server) { + let mut client = default_http3_client(client_params); + let mut server = default_http3_server(server_params); connect_with(&mut client, &mut server); (client, server) } @@ -103,7 +117,12 @@ struct WtTest { impl WtTest { pub fn new() -> Self { - let (client, server) = connect(true, true); + let (client, server) = connect(wt_default_parameters(), wt_default_parameters()); + Self { client, server } + } + + pub fn new_with_params(client_params: Http3Parameters, server_params: Http3Parameters) -> Self { + let (client, server) = connect(client_params, server_params); Self { client, server } } @@ -111,7 +130,10 @@ impl WtTest { connect_with(&mut client, &mut server); Self { client, server } } - fn negotiate_wt_session(&mut self, accept: bool) -> (StreamId, Option) { + fn negotiate_wt_session( + &mut self, + accept: &WebTransportSessionAcceptAction, + ) -> (StreamId, Option) { let wt_session_id = self .client .webtransport_create_session(now(), &("https", "something.com", "/"), &[]) @@ -148,7 +170,8 @@ impl WtTest { } fn create_wt_session(&mut self) -> WebTransportRequest { - let (wt_session_id, wt_server_session) = self.negotiate_wt_session(true); + let (wt_session_id, wt_server_session) = + self.negotiate_wt_session(&WebTransportSessionAcceptAction::Accept); let wt_session_negotiated_event = |e| { matches!( e, @@ -202,12 +225,12 @@ impl WtTest { pub fn check_session_closed_event_client( &mut self, wt_session_id: StreamId, - expected_reason: SessionCloseReason, + expected_reason: &SessionCloseReason, ) { let mut event_found = false; while let Some(event) = self.client.next_event() { - event_found = WtTest::session_closed_client(&event, wt_session_id, &expected_reason); + event_found = WtTest::session_closed_client(&event, wt_session_id, expected_reason); if event_found { break; } @@ -239,13 +262,13 @@ impl WtTest { pub fn check_session_closed_event_server( &mut self, wt_session: &mut WebTransportRequest, - expected_reeason: SessionCloseReason, + expected_reeason: &SessionCloseReason, ) { let event = self.server.next_event().unwrap(); assert!(WtTest::session_closed_server( &event, wt_session.stream_id(), - &expected_reeason + expected_reeason )); } @@ -353,7 +376,7 @@ impl WtTest { expected_stop_sending_ids: &[StreamId], expected_error_stream_stop_sending: Option, expected_local: bool, - expected_session_close: Option<(StreamId, SessionCloseReason)>, + expected_session_close: &Option<(StreamId, SessionCloseReason)>, ) { let mut reset_ids_count = 0; let mut stop_sending_ids_count = 0; @@ -392,7 +415,6 @@ impl WtTest { } fn create_wt_stream_server( - &mut self, wt_server_session: &mut WebTransportRequest, stream_type: StreamType, ) -> Http3OrWebTransportStream { @@ -494,7 +516,7 @@ impl WtTest { expected_error_stream_reset: Option, expected_stop_sending_ids: &[StreamId], expected_error_stream_stop_sending: Option, - expected_session_close: Option<(StreamId, SessionCloseReason)>, + expected_session_close: &Option<(StreamId, SessionCloseReason)>, ) { let mut reset_ids_count = 0; let mut stop_sending_ids_count = 0; @@ -537,11 +559,72 @@ impl WtTest { } pub fn session_close_frame_server( - &mut self, wt_session: &mut WebTransportRequest, error: u32, message: &str, ) { wt_session.close_session(error, message).unwrap(); } + + fn max_datagram_size(&self, stream_id: StreamId) -> Result { + self.client.webtransport_max_datagram_size(stream_id) + } + + fn send_datagram(&mut self, stream_id: StreamId, buf: &[u8]) -> Result<(), Error> { + self.client.webtransport_send_datagram(stream_id, buf, None) + } + + fn check_datagram_received_client( + &mut self, + expected_stream_id: StreamId, + expected_dgram: &[u8], + ) { + let wt_datagram_event = |e| { + matches!( + e, + Http3ClientEvent::WebTransport(WebTransportEvent::Datagram { + session_id, + datagram + }) if session_id == expected_stream_id && datagram == expected_dgram + ) + }; + assert!(self.client.events().any(wt_datagram_event)); + } + + fn check_datagram_received_server( + &mut self, + expected_session: &WebTransportRequest, + expected_dgram: &[u8], + ) { + let wt_datagram_event = |e| { + matches!( + e, + Http3ServerEvent::WebTransport(WebTransportServerEvent::Datagram { + session, + datagram + }) if session.stream_id() == expected_session.stream_id() && datagram == expected_dgram + ) + }; + assert!(self.server.events().any(wt_datagram_event)); + } + + fn check_no_datagram_received_client(&mut self) { + let wt_datagram_event = |e| { + matches!( + e, + Http3ClientEvent::WebTransport(WebTransportEvent::Datagram { .. }) + ) + }; + assert!(!self.client.events().any(wt_datagram_event)); + } + + fn check_no_datagram_received_server(&mut self) { + let wt_datagram_event = |e| { + matches!( + e, + Http3ServerEvent::WebTransport(WebTransportServerEvent::Datagram { .. }) + ) + }; + assert!(!self.server.events().any(wt_datagram_event)); + } } diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs new file mode 100644 index 000000000000..49893294c8ab --- /dev/null +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs @@ -0,0 +1,290 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{connect, default_http3_client, default_http3_server, exchange_packets}; +use crate::{ + settings::{HSetting, HSettingType, HSettings}, + Error, HFrame, Http3Client, Http3ClientEvent, Http3Parameters, Http3Server, Http3State, + WebTransportEvent, +}; +use neqo_common::{event::Provider, Encoder}; +use neqo_crypto::AuthenticationStatus; +use neqo_transport::{Connection, ConnectionError, StreamType}; +use std::time::Duration; +use test_fixture::{default_server_h3, now}; + +fn check_wt_event(client: &mut Http3Client, wt_enable_client: bool, wt_enable_server: bool) { + let wt_event = client.events().find_map(|e| { + if let Http3ClientEvent::WebTransport(WebTransportEvent::Negotiated(neg)) = e { + Some(neg) + } else { + None + } + }); + + assert_eq!(wt_event.is_some(), wt_enable_client); + if let Some(wt) = wt_event { + assert_eq!(wt, wt_enable_client && wt_enable_server); + } +} + +fn connect_wt(wt_enabled_client: bool, wt_enabled_server: bool) -> (Http3Client, Http3Server) { + connect( + Http3Parameters::default().webtransport(wt_enabled_client), + Http3Parameters::default().webtransport(wt_enabled_server), + ) +} + +#[test] +fn negotiate_wt() { + let (mut client, _server) = connect_wt(true, true); + assert!(client.webtransport_enabled()); + check_wt_event(&mut client, true, true); + + let (mut client, _server) = connect_wt(true, false); + assert!(!client.webtransport_enabled()); + check_wt_event(&mut client, true, false); + + let (mut client, _server) = connect_wt(false, true); + assert!(!client.webtransport_enabled()); + check_wt_event(&mut client, false, true); + + let (mut client, _server) = connect_wt(false, false); + assert!(!client.webtransport_enabled()); + check_wt_event(&mut client, false, false); +} + +#[derive(PartialEq, Eq)] +enum ClientState { + ClientEnabled, + ClientDisabled, +} + +#[derive(PartialEq, Eq)] +enum ClientResumedState { + ClientResumed, + ClientSuspended, +} + +#[derive(PartialEq, Eq)] +enum ServerState { + ServerEnabled, + ServerDisabled, +} + +#[derive(PartialEq, Eq)] +enum ServerResumedState { + ServerResumed, + ServerSuspended, +} + +fn zero_rtt( + client_state: &ClientState, + server_state: &ServerState, + client_resumed: &ClientResumedState, + server_resumed: &ServerResumedState, +) { + let (mut client, mut server) = connect_wt( + ClientState::ClientEnabled.eq(client_state), + ServerState::ServerEnabled.eq(server_state), + ); + assert_eq!( + client.webtransport_enabled(), + ClientState::ClientEnabled.eq(client_state) && ServerState::ServerEnabled.eq(server_state) + ); + + // exchane token + let out = server.process(None, now()); + // We do not have a token so we need to wait for a resumption token timer to trigger. + std::mem::drop(client.process(out.dgram(), now() + Duration::from_millis(250))); + assert_eq!(client.state(), Http3State::Connected); + let token = client + .events() + .find_map(|e| { + if let Http3ClientEvent::ResumptionToken(token) = e { + Some(token) + } else { + None + } + }) + .unwrap(); + + let mut client = default_http3_client( + Http3Parameters::default() + .webtransport(ClientResumedState::ClientResumed.eq(client_resumed)), + ); + let mut server = default_http3_server( + Http3Parameters::default() + .webtransport(ServerResumedState::ServerResumed.eq(server_resumed)), + ); + client + .enable_resumption(now(), &token) + .expect("Set resumption token."); + assert_eq!(client.state(), Http3State::ZeroRtt); + + exchange_packets(&mut client, &mut server); + + assert_eq!(&client.state(), &Http3State::Connected); + assert_eq!( + client.webtransport_enabled(), + ClientResumedState::ClientResumed.eq(client_resumed) + && ServerResumedState::ServerResumed.eq(server_resumed) + ); + check_wt_event( + &mut client, + ClientResumedState::ClientResumed.eq(client_resumed), + ServerResumedState::ServerResumed.eq(server_resumed), + ); +} + +#[test] +fn zero_rtt_wt_settings() { + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerResumed, + ); + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerResumed, + ); + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerSuspended, + ); + + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerResumed, + ); + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientEnabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerResumed, + ); + + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerResumed, + ); + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerDisabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerResumed, + ); + + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerResumed, + ); + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientSuspended, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerSuspended, + ); + zero_rtt( + &ClientState::ClientDisabled, + &ServerState::ServerEnabled, + &ClientResumedState::ClientResumed, + &ServerResumedState::ServerResumed, + ); +} + +fn exchange_packets2(client: &mut Http3Client, server: &mut Connection) { + let mut out = None; + loop { + out = client.process(out, now()).dgram(); + out = server.process(out, now()).dgram(); + if out.is_none() { + break; + } + } +} + +#[test] +fn wrong_setting_value() { + const CONTROL_STREAM_TYPE: &[u8] = &[0x0]; + let mut client = default_http3_client(Http3Parameters::default()); + let mut server = default_server_h3(); + + exchange_packets2(&mut client, &mut server); + client.authenticated(AuthenticationStatus::Ok, now()); + exchange_packets2(&mut client, &mut server); + + let control = server.stream_create(StreamType::UniDi).unwrap(); + server.stream_send(control, CONTROL_STREAM_TYPE).unwrap(); + // Encode a settings frame and send it. + let mut enc = Encoder::default(); + let settings = HFrame::Settings { + settings: HSettings::new(&[HSetting::new(HSettingType::EnableWebTransport, 2)]), + }; + settings.encode(&mut enc); + assert_eq!( + server.stream_send(control, enc.as_ref()).unwrap(), + enc.as_ref().len() + ); + + exchange_packets2(&mut client, &mut server); + match client.state() { + Http3State::Closing(err) | Http3State::Closed(err) => { + assert_eq!( + err, + ConnectionError::Application(Error::HttpSettings.code()) + ); + } + _ => panic!("Wrong state {:?}", client.state()), + }; +} diff --git a/third_party/rust/neqo-http3/tests/webtransport/sessions.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs similarity index 81% rename from third_party/rust/neqo-http3/tests/webtransport/sessions.rs rename to third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs index 222638323228..5d7c87baffb7 100644 --- a/third_party/rust/neqo-http3/tests/webtransport/sessions.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs @@ -4,16 +4,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::webtransport::{default_http3_server, WtTest}; -use neqo_common::{event::Provider, Encoder}; -use neqo_http3::{ - features::extended_connect::SessionCloseReason, frames::WebTransportFrame, Error, Header, - Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, - Http3State, Priority, WebTransportEvent, WebTransportServerEvent, +use crate::features::extended_connect::tests::webtransport::{ + default_http3_client, default_http3_server, wt_default_parameters, WtTest, }; -use neqo_transport::{ConnectionParameters, StreamType}; +use crate::{ + features::extended_connect::SessionCloseReason, frames::WebTransportFrame, Error, Header, + Http3ClientEvent, Http3OrWebTransportStream, Http3Server, Http3ServerEvent, Http3State, + Priority, WebTransportEvent, WebTransportServerEvent, WebTransportSessionAcceptAction, +}; +use neqo_common::{event::Provider, Encoder}; +use neqo_transport::StreamType; use std::mem; -use test_fixture::{http3_client_with_params, now}; +use test_fixture::now; #[test] fn wt_session() { @@ -24,9 +26,11 @@ fn wt_session() { #[test] fn wt_session_reject() { let mut wt = WtTest::new(); - let (wt_session_id, _wt_session) = wt.negotiate_wt_session(false); + let accept_res = + WebTransportSessionAcceptAction::Reject([Header::new(":status", "404")].to_vec()); + let (wt_session_id, _wt_session) = wt.negotiate_wt_session(&accept_res); - wt.check_session_closed_event_client(wt_session_id, SessionCloseReason::Status(404)); + wt.check_session_closed_event_client(wt_session_id, &SessionCloseReason::Status(404)); } #[test] @@ -37,7 +41,7 @@ fn wt_session_close_client() { wt.cancel_session_client(wt_session.stream_id()); wt.check_session_closed_event_server( &mut wt_session, - SessionCloseReason::Error(Error::HttpNoError.code()), + &SessionCloseReason::Error(Error::HttpNoError.code()), ); } @@ -49,7 +53,7 @@ fn wt_session_close_server() { wt.cancel_session_server(&mut wt_session); wt.check_session_closed_event_client( wt_session.stream_id(), - SessionCloseReason::Error(Error::HttpNoError.code()), + &SessionCloseReason::Error(Error::HttpNoError.code()), ); } @@ -62,9 +66,9 @@ fn wt_session_close_server_close_send() { wt.exchange_packets(); wt.check_session_closed_event_client( wt_session.stream_id(), - SessionCloseReason::Clean { + &SessionCloseReason::Clean { error: 0, - message: "".to_string(), + message: String::new(), }, ); } @@ -80,7 +84,7 @@ fn wt_session_close_server_stop_sending() { wt.exchange_packets(); wt.check_session_closed_event_client( wt_session.stream_id(), - SessionCloseReason::Error(Error::HttpNoError.code()), + &SessionCloseReason::Error(Error::HttpNoError.code()), ); } @@ -95,12 +99,12 @@ fn wt_session_close_server_reset() { wt.exchange_packets(); wt.check_session_closed_event_client( wt_session.stream_id(), - SessionCloseReason::Error(Error::HttpNoError.code()), + &SessionCloseReason::Error(Error::HttpNoError.code()), ); } #[test] -fn wt_session_respone_with_1xx() { +fn wt_session_response_with_1xx() { let mut wt = WtTest::new(); let wt_session_id = wt @@ -134,7 +138,9 @@ fn wt_session_respone_with_1xx() { wt_server_session .send_headers(&[Header::new(":status", "111")]) .unwrap(); - wt_server_session.response(true).unwrap(); + wt_server_session + .response(&WebTransportSessionAcceptAction::Accept) + .unwrap(); wt.exchange_packets(); @@ -152,6 +158,19 @@ fn wt_session_respone_with_1xx() { assert_eq!(wt_session_id, wt_server_session.stream_id()); } +#[test] +fn wt_session_response_with_redirect() { + let mut wt = WtTest::new(); + + let accept_res = WebTransportSessionAcceptAction::Reject( + [Header::new(":status", "302"), Header::new("location", "/")].to_vec(), + ); + + let (wt_session_id, _wt_session) = wt.negotiate_wt_session(&accept_res); + + wt.check_session_closed_event_client(wt_session_id, &SessionCloseReason::Status(302)); +} + #[test] fn wt_session_respone_200_with_fin() { let mut wt = WtTest::new(); @@ -181,7 +200,9 @@ fn wt_session_respone_200_with_fin() { } let mut wt_server_session = wt_server_session.unwrap(); - wt_server_session.response(true).unwrap(); + wt_server_session + .response(&WebTransportSessionAcceptAction::Accept) + .unwrap(); wt_server_session.stream_close_send().unwrap(); wt.exchange_packets(); @@ -192,7 +213,7 @@ fn wt_session_respone_200_with_fin() { Http3ClientEvent::WebTransport(WebTransportEvent::SessionClosed{ stream_id, reason - }) if stream_id == wt_session_id && reason == SessionCloseReason::Clean{ error: 0, message: "".to_string()} + }) if stream_id == wt_session_id && reason == SessionCloseReason::Clean{ error: 0, message: String::new()} ) }; assert!(wt.client.events().any(wt_session_close_event)); @@ -212,7 +233,7 @@ fn wt_session_close_frame_client() { wt.check_session_closed_event_server( &mut wt_session, - SessionCloseReason::Clean { + &SessionCloseReason::Clean { error: ERROR_NUM, message: ERROR_MESSAGE.to_string(), }, @@ -226,12 +247,12 @@ fn wt_session_close_frame_server() { let mut wt = WtTest::new(); let mut wt_session = wt.create_wt_session(); - wt.session_close_frame_server(&mut wt_session, ERROR_NUM, ERROR_MESSAGE); + WtTest::session_close_frame_server(&mut wt_session, ERROR_NUM, ERROR_MESSAGE); wt.exchange_packets(); wt.check_session_closed_event_client( wt_session.stream_id(), - SessionCloseReason::Clean { + &SessionCloseReason::Clean { error: ERROR_NUM, message: ERROR_MESSAGE.to_string(), }, @@ -257,7 +278,7 @@ fn wt_unknown_session_frame_client() { wt.exchange_packets(); // The session is still active - let mut unidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi); + let mut unidi_server = WtTest::create_wt_stream_server(&mut wt_session, StreamType::UniDi); wt.send_data_server(&mut unidi_server, BUF); wt.receive_data_client(unidi_server.stream_id(), true, BUF, false); @@ -271,14 +292,14 @@ fn wt_unknown_session_frame_client() { &[], None, false, - None, + &None, ); wt.check_events_after_closing_session_server( &[], None, &[unidi_server.stream_id()], Some(Error::HttpRequestCancelled.code()), - Some(( + &Some(( wt_session.stream_id(), SessionCloseReason::Clean { error: ERROR_NUM, @@ -309,11 +330,11 @@ fn wt_close_session_frame_broken_client() { // check that the webtransport session is closed. wt.check_session_closed_event_client( wt_session.stream_id(), - SessionCloseReason::Error(Error::HttpGeneralProtocolStream.code()), + &SessionCloseReason::Error(Error::HttpGeneralProtocolStream.code()), ); wt.check_session_closed_event_server( &mut wt_session, - SessionCloseReason::Error(Error::HttpGeneralProtocolStream.code()), + &SessionCloseReason::Error(Error::HttpGeneralProtocolStream.code()), ); // The Http3 session is still working. @@ -331,18 +352,16 @@ fn receive_request(server: &mut Http3Server) -> Option, control_stream_send: Box, stream_event_listener: Rc>, @@ -209,14 +209,13 @@ impl WebTransportSession { } qtrace!("ExtendedConnect close the session"); self.state = SessionState::Done; - if let CloseType::ResetApp(_) = close_type { - return; + if !close_type.locally_initiated() { + self.events.session_end( + ExtendedConnectType::WebTransport, + self.session_id, + SessionCloseReason::from(close_type), + ); } - self.events.session_end( - ExtendedConnectType::WebTransport, - self.session_id, - SessionCloseReason::from(close_type), - ); } /// # Panics @@ -241,7 +240,7 @@ impl WebTransportSession { self.session_id, SessionCloseReason::Clean { error: 0, - message: "".to_string(), + message: String::new(), }, ); self.state = SessionState::Done; @@ -265,7 +264,7 @@ impl WebTransportSession { self.session_id, SessionCloseReason::Clean { error: 0, - message: "".to_string(), + message: String::new(), }, ); SessionState::Done @@ -323,11 +322,11 @@ impl WebTransportSession { matches!(self.state, SessionState::Active) } - pub fn take_sub_streams(&mut self) -> Option<(BTreeSet, BTreeSet)> { - Some(( + pub fn take_sub_streams(&mut self) -> (BTreeSet, BTreeSet) { + ( mem::take(&mut self.recv_streams), mem::take(&mut self.send_streams), - )) + ) } /// # Errors @@ -358,7 +357,7 @@ impl WebTransportSession { self.session_id, SessionCloseReason::Clean { error: 0, - message: "".to_string(), + message: String::new(), }, ); self.state = SessionState::Done; @@ -391,6 +390,33 @@ impl WebTransportSession { fn send_data(&mut self, conn: &mut Connection, buf: &[u8]) -> Res { self.control_stream_send.send_data(conn, buf) } + + /// # Errors + /// Returns an error if the datagram exceeds the remote datagram size limit. + pub fn send_datagram( + &self, + conn: &mut Connection, + buf: &[u8], + id: impl Into, + ) -> Res<()> { + qtrace!([self], "send_datagram state={:?}", self.state); + if let SessionState::Active = self.state { + let mut dgram_data = Encoder::default(); + dgram_data.encode_varint(self.session_id.as_u64() / 4); + dgram_data.encode(buf); + conn.send_datagram(dgram_data.as_ref(), id)?; + } else { + debug_assert!(false); + return Err(Error::Unavailable); + } + Ok(()) + } + + pub fn datagram(&mut self, datagram: Vec) { + if let SessionState::Active = self.state { + self.events.new_datagram(self.session_id, datagram); + } + } } impl Stream for Rc> { diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_streams.rs b/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_streams.rs index 6a560f36485d..f08f8047d724 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_streams.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_streams.rs @@ -18,7 +18,7 @@ pub const WEBTRANSPORT_UNI_STREAM: u64 = 0x54; pub const WEBTRANSPORT_STREAM: u64 = 0x41; #[derive(Debug)] -pub struct WebTransportRecvStream { +pub(crate) struct WebTransportRecvStream { stream_id: StreamId, events: Box, session: Rc>, @@ -85,7 +85,7 @@ enum WebTransportSenderStreamState { } #[derive(Debug)] -pub struct WebTransportSendStream { +pub(crate) struct WebTransportSendStream { stream_id: StreamId, state: WebTransportSenderStreamState, events: Box, diff --git a/third_party/rust/neqo-http3/src/frames/mod.rs b/third_party/rust/neqo-http3/src/frames/mod.rs index 109b29e77bb1..8b615fad0144 100644 --- a/third_party/rust/neqo-http3/src/frames/mod.rs +++ b/third_party/rust/neqo-http3/src/frames/mod.rs @@ -4,13 +4,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub mod hframe; -pub mod reader; -pub mod wtframe; +pub(crate) mod hframe; +pub(crate) mod reader; +pub(crate) mod wtframe; -pub use hframe::{HFrame, H3_FRAME_TYPE_HEADERS, H3_FRAME_TYPE_SETTINGS, H3_RESERVED_FRAME_TYPES}; -pub use reader::{FrameReader, StreamReaderConnectionWrapper, StreamReaderRecvStreamWrapper}; -pub use wtframe::WebTransportFrame; +#[allow(unused_imports)] +pub(crate) use hframe::{ + HFrame, H3_FRAME_TYPE_HEADERS, H3_FRAME_TYPE_SETTINGS, H3_RESERVED_FRAME_TYPES, +}; +pub(crate) use reader::{ + FrameReader, StreamReaderConnectionWrapper, StreamReaderRecvStreamWrapper, +}; +pub(crate) use wtframe::WebTransportFrame; #[cfg(test)] mod tests; diff --git a/third_party/rust/neqo-http3/src/frames/reader.rs b/third_party/rust/neqo-http3/src/frames/reader.rs index fb74d82037df..9d81f2c1c12e 100644 --- a/third_party/rust/neqo-http3/src/frames/reader.rs +++ b/third_party/rust/neqo-http3/src/frames/reader.rs @@ -17,7 +17,7 @@ use std::fmt::Debug; const MAX_READ_SIZE: usize = 4096; -pub trait FrameDecoder { +pub(crate) trait FrameDecoder { fn is_known_type(frame_type: u64) -> bool; /// # Errors /// Returns `HttpFrameUnexpected` if frames is not alowed, i.e. is a `H3_RESERVED_FRAME_TYPES`. @@ -29,7 +29,7 @@ pub trait FrameDecoder { fn decode(frame_type: u64, frame_len: u64, data: Option<&[u8]>) -> Res>; } -pub trait StreamReader { +pub(crate) trait StreamReader { /// # Errors /// An error may happen while reading a stream, e.g. early close, protocol error, etc. /// Return an error if the stream was closed on the transport layer, but that information is not yet @@ -37,7 +37,7 @@ pub trait StreamReader { fn read_data(&mut self, buf: &mut [u8]) -> Res<(usize, bool)>; } -pub struct StreamReaderConnectionWrapper<'a> { +pub(crate) struct StreamReaderConnectionWrapper<'a> { conn: &'a mut Connection, stream_id: StreamId, } @@ -57,7 +57,7 @@ impl<'a> StreamReader for StreamReaderConnectionWrapper<'a> { } } -pub struct StreamReaderRecvStreamWrapper<'a> { +pub(crate) struct StreamReaderRecvStreamWrapper<'a> { recv_stream: &'a mut Box, conn: &'a mut Connection, } @@ -86,7 +86,7 @@ enum FrameReaderState { #[allow(clippy::module_name_repetitions)] #[derive(Debug)] -pub struct FrameReader { +pub(crate) struct FrameReader { state: FrameReaderState, frame_type: u64, frame_len: u64, diff --git a/third_party/rust/neqo-http3/src/frames/tests/mod.rs b/third_party/rust/neqo-http3/src/frames/tests/mod.rs index e1465037f118..092b3039ec2e 100644 --- a/third_party/rust/neqo-http3/src/frames/tests/mod.rs +++ b/third_party/rust/neqo-http3/src/frames/tests/mod.rs @@ -14,7 +14,7 @@ use std::mem; use test_fixture::{default_client, default_server, now}; #[allow(clippy::many_single_char_names)] -pub fn enc_dec>(d: &Encoder, st: &str, remaining: usize) -> T { +pub(crate) fn enc_dec>(d: &Encoder, st: &str, remaining: usize) -> T { // For data, headers and push_promise we do not read all bytes from the buffer let d2 = Encoder::from_hex(st); assert_eq!(d.as_ref(), &d2.as_ref()[..d.as_ref().len()]); diff --git a/third_party/rust/neqo-http3/src/lib.rs b/third_party/rust/neqo-http3/src/lib.rs index 0639f4dd0097..c3cda393ade7 100644 --- a/third_party/rust/neqo-http3/src/lib.rs +++ b/third_party/rust/neqo-http3/src/lib.rs @@ -7,16 +7,144 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(clippy::pedantic)] +/*! + +# The HTTP/3 protocol + +This crate implements [RFC9114](https://datatracker.ietf.org/doc/html/rfc9114). + +The implementation depends on: + - [neqo-transport](../neqo_transport/index.html) --- implements the QUIC protocol + ([RFC9000](https://www.rfc-editor.org/info/rfc9000)) and + - [neqo-qpack](../neqo_qpack/index.html) --- implements QPACK + ([RFC9204](https://www.rfc-editor.org/info/rfc9204)); + +## Features + +Both client and server-side HTTP/3 protocols are implemented, although the server-side +implementation is not meant to be used in production and its only purpose is to facilitate testing +of the client-side code. + +__`WebTransport`__ +([draft version 2](https://datatracker.ietf.org/doc/html/draft-vvv-webtransport-http3-02)) is +supported and can be enabled using [`Http3Parameters`](struct.Http3Parameters.html). + +## Interaction with an application + +### Driving HTTP/3 session + +The crate does not create an OS level UDP socket, it produces, i.e. encodes, data that should be +sent as a payload in a UDP packet and consumes data received on the UDP socket. For example, +[`std::net::UdpSocket`](std::net::UdpSocket) or [`mio::net::UdpSocket`](https://crates.io/crates/mio) +could be used for creating UDP sockets. + +The application is responsible for creating a socket, polling the socket, and sending and receiving +data from the socket. + +In addition to receiving data HTTP/3 session’s actions may be triggered when a certain amount of +time passes, e.g. after a certain amount of time data may be considered lost and should be +retransmitted, packet pacing requires a timer, etc. The implementation does not use timers, but +instead informs the application when processing needs to be triggered. + + +The core functions for driving HTTP/3 sessions are: + - __On the client-side__ : + - [`process_output`](struct.Http3Client.html#method.process_output) used for producing UDP +payload. If a payload is not produced this function returns a callback time, e.g. the time when +[`process_output`](struct.Http3Client.html#method.process_output) should be called again. + - [`process_input`](struct.Http3Client.html#method.process_input) used consuming UDP payload. + - [`process`](struct.Http3Client.html#method.process) combines the 2 functions into one, i.e. it +consumes UDP payload if available and produces some UDP payload to be sent or returns a +callback time. +- __On the server-side__ only [`process`](struct.Http3Server.html#method.process) is +available. + +An example interaction with a socket: + +```ignore +let socket = match UdpSocket::bind(local_addr) { + Err(e) => { + eprintln!("Unable to bind UDP socket: {}", e); + } + Ok(s) => s, +}; +let mut client = Http3Client::new(...); + +... + +// process_output can return 3 values, data to be sent, time duration when process_output should +// be called, and None when Http3Client is done. +match client.process_output(Instant::now()) { + Output::Datagram(dgram) => { + // Send dgram on a socket. + socket.send_to(&dgram[..], dgram.destination()) + + } + Output::Callback(duration) => { + // the client is idle for “duration”, set read timeout on the socket to this value and + // poll the socket for reading in the meantime. + socket.set_read_timeout(Some(duration)).unwrap(); + } + Output::None => { + // client is done. + } +}; + +... + +// Reading new data coming for the network. +match socket.recv_from(&mut buf[..]) { + Ok((sz, remote)) => { + let d = Datagram::new(remote, *local_addr, &buf[..sz]); + client.process_input(d, Instant::now()); + } + Err(err) => { + eprintln!("UDP error: {}", err); + } +} + ``` + +### HTTP/3 session events + +[`Http3Client`](struct.Http3Client.html) and [`Http3Server`](struct.Http3Server.html) produce +events that can be obtain by calling +[`next_event`](neqo_common/event/trait.Provider.html#tymethod.next_event). The events are of type +[`Http3ClientEvent`](enum.Http3ClientEvent.html) and +[`Http3ServerEvent`](enum.Http3ServerEvent.html) respectively. They are informing the application +when the connection changes state, when new data is received on a stream, etc. + +```ignore +... + +while let Some(event) = client.next_event() { + match event { + Http3ClientEvent::DataReadable { stream_id } => { + println!("New data available on stream {}", stream_id); + } + Http3ClientEvent::StateChange(Http3State::Connected) => { + println!("Http3 session is in state Connected now"); + } + _ => { + println!("Unhandled event {:?}", event); + } + } +} +``` + + + +*/ + mod buffered_send_stream; mod client_events; mod conn_params; mod connection; -pub mod connection_client; +mod connection_client; mod connection_server; mod control_stream_local; mod control_stream_remote; pub mod features; -pub mod frames; +mod frames; mod headers_checks; mod priority; mod push_controller; @@ -24,12 +152,12 @@ mod qlog; mod qpack_decoder_receiver; mod qpack_encoder_receiver; mod recv_message; -pub mod request_target; +mod request_target; mod send_message; -pub mod server; +mod server; mod server_connection_events; mod server_events; -pub mod settings; +mod settings; mod stream_type_reader; use neqo_qpack::Error as QpackError; @@ -38,24 +166,24 @@ pub use neqo_transport::{Output, StreamId}; use std::fmt::Debug; use crate::priority::PriorityHandler; -pub use buffered_send_stream::BufferedStream; +use buffered_send_stream::BufferedStream; pub use client_events::{Http3ClientEvent, WebTransportEvent}; pub use conn_params::Http3Parameters; -pub use connection::Http3State; +pub use connection::{Http3State, WebTransportSessionAcceptAction}; pub use connection_client::Http3Client; use features::extended_connect::WebTransportSession; -pub use frames::HFrame; -pub use neqo_common::{Header, MessageType}; +use frames::HFrame; +pub use neqo_common::Header; +use neqo_common::MessageType; pub use priority::Priority; pub use server::Http3Server; pub use server_events::{ Http3OrWebTransportStream, Http3ServerEvent, WebTransportRequest, WebTransportServerEvent, }; -pub use settings::HttpZeroRttChecker; use std::any::Any; use std::cell::RefCell; use std::rc::Rc; -pub use stream_type_reader::NewStreamType; +use stream_type_reader::NewStreamType; type Res = Result; @@ -299,9 +427,8 @@ pub enum Http3StreamType { #[must_use] #[derive(PartialEq, Eq, Debug)] -pub enum ReceiveOutput { +enum ReceiveOutput { NoOutput, - PushStream, ControlFrames(Vec), UnblockedStreams(Vec), NewStream(NewStreamType), @@ -313,11 +440,11 @@ impl Default for ReceiveOutput { } } -pub trait Stream: Debug { +trait Stream: Debug { fn stream_type(&self) -> Http3StreamType; } -pub trait RecvStream: Stream { +trait RecvStream: Stream { /// The stream reads data from the corresponding quic stream and returns `ReceiveOutput`. /// The function also returns true as the second parameter if the stream is done and /// could be forgotten, i.e. removed from all records. @@ -345,7 +472,7 @@ pub trait RecvStream: Stream { } } -pub trait HttpRecvStream: RecvStream { +trait HttpRecvStream: RecvStream { /// This function is similar to the receive function and has the same output, i.e. /// a `ReceiveOutput` enum and bool. The bool is true if the stream is completely done /// and can be forgotten, i.e. removed from all records. @@ -400,12 +527,12 @@ impl Http3StreamInfo { } } -pub trait RecvStreamEvents: Debug { +trait RecvStreamEvents: Debug { fn data_readable(&self, _stream_info: Http3StreamInfo) {} fn recv_closed(&self, _stream_info: Http3StreamInfo, _close_type: CloseType) {} } -pub trait HttpRecvStreamEvents: RecvStreamEvents { +trait HttpRecvStreamEvents: RecvStreamEvents { fn header_ready( &self, stream_info: Http3StreamInfo, @@ -416,7 +543,7 @@ pub trait HttpRecvStreamEvents: RecvStreamEvents { fn extended_connect_new_session(&self, _stream_id: StreamId, _headers: Vec
) {} } -pub trait SendStream: Stream { +trait SendStream: Stream { /// # Errors /// Error my occure during sending data, e.g. protocol error, etc. fn send(&mut self, conn: &mut Connection) -> Res<()>; @@ -454,7 +581,7 @@ pub trait SendStream: Stream { } } -pub trait HttpSendStream: SendStream { +trait HttpSendStream: SendStream { /// This function is used to supply headers to a http message. The /// function is used for request headers, response headers, 1xx response and /// trailers. @@ -465,7 +592,7 @@ pub trait HttpSendStream: SendStream { fn any(&self) -> &dyn Any; } -pub trait SendStreamEvents: Debug { +trait SendStreamEvents: Debug { fn send_closed(&self, _stream_info: Http3StreamInfo, _close_type: CloseType) {} fn data_writable(&self, _stream_info: Http3StreamInfo) {} } @@ -477,7 +604,7 @@ pub trait SendStreamEvents: Debug { /// that do not close the complete connection, e.g. unallowed headers. /// `Done` - the stream was closed without an error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum CloseType { +enum CloseType { ResetApp(AppError), ResetRemote(AppError), LocalError(AppError), @@ -494,4 +621,9 @@ impl CloseType { Self::Done => None, } } + + #[must_use] + pub fn locally_initiated(&self) -> bool { + matches!(self, CloseType::ResetApp(_)) + } } diff --git a/third_party/rust/neqo-http3/src/qpack_decoder_receiver.rs b/third_party/rust/neqo-http3/src/qpack_decoder_receiver.rs index ab1e24702dae..3cdfdf74cd17 100644 --- a/third_party/rust/neqo-http3/src/qpack_decoder_receiver.rs +++ b/third_party/rust/neqo-http3/src/qpack_decoder_receiver.rs @@ -11,7 +11,7 @@ use std::cell::RefCell; use std::rc::Rc; #[derive(Debug)] -pub struct DecoderRecvStream { +pub(crate) struct DecoderRecvStream { stream_id: StreamId, decoder: Rc>, } diff --git a/third_party/rust/neqo-http3/src/qpack_encoder_receiver.rs b/third_party/rust/neqo-http3/src/qpack_encoder_receiver.rs index 986929311532..efe234173f64 100644 --- a/third_party/rust/neqo-http3/src/qpack_encoder_receiver.rs +++ b/third_party/rust/neqo-http3/src/qpack_encoder_receiver.rs @@ -11,7 +11,7 @@ use std::cell::RefCell; use std::rc::Rc; #[derive(Debug)] -pub struct EncoderRecvStream { +pub(crate) struct EncoderRecvStream { stream_id: StreamId, encoder: Rc>, } diff --git a/third_party/rust/neqo-http3/src/recv_message.rs b/third_party/rust/neqo-http3/src/recv_message.rs index 7b170a55d3dc..dd27c513373e 100644 --- a/third_party/rust/neqo-http3/src/recv_message.rs +++ b/third_party/rust/neqo-http3/src/recv_message.rs @@ -24,7 +24,7 @@ use std::fmt::Debug; use std::rc::Rc; #[allow(clippy::module_name_repetitions)] -pub struct RecvMessageInfo { +pub(crate) struct RecvMessageInfo { pub message_type: MessageType, pub stream_type: Http3StreamType, pub stream_id: StreamId, diff --git a/third_party/rust/neqo-http3/src/server.rs b/third_party/rust/neqo-http3/src/server.rs index 71f001afe851..d27e8356508f 100644 --- a/third_party/rust/neqo-http3/src/server.rs +++ b/third_party/rust/neqo-http3/src/server.rs @@ -229,6 +229,13 @@ impl Http3Server { handler.clone(), stream_info, )), + Http3ServerConnEvent::ExtendedConnectDatagram { + session_id, + datagram, + } => self.events.webtransport_datagram( + WebTransportRequest::new(conn.clone(), handler.clone(), session_id), + datagram, + ), } } } diff --git a/third_party/rust/neqo-http3/src/server_connection_events.rs b/third_party/rust/neqo-http3/src/server_connection_events.rs index 7a56e041c051..bc1f1b03761a 100644 --- a/third_party/rust/neqo-http3/src/server_connection_events.rs +++ b/third_party/rust/neqo-http3/src/server_connection_events.rs @@ -55,6 +55,10 @@ pub(crate) enum Http3ServerConnEvent { reason: SessionCloseReason, }, ExtendedConnectNewStream(Http3StreamInfo), + ExtendedConnectDatagram { + session_id: StreamId, + datagram: Vec, + }, } #[derive(Debug, Default, Clone)] @@ -140,6 +144,13 @@ impl ExtendedConnectEvents for Http3ServerConnEvents { fn extended_connect_new_stream(&self, stream_info: Http3StreamInfo) { self.insert(Http3ServerConnEvent::ExtendedConnectNewStream(stream_info)); } + + fn new_datagram(&self, session_id: StreamId, datagram: Vec) { + self.insert(Http3ServerConnEvent::ExtendedConnectDatagram { + session_id, + datagram, + }); + } } impl Http3ServerConnEvents { diff --git a/third_party/rust/neqo-http3/src/server_events.rs b/third_party/rust/neqo-http3/src/server_events.rs index 410f47981afd..7f3d9ac5dd20 100644 --- a/third_party/rust/neqo-http3/src/server_events.rs +++ b/third_party/rust/neqo-http3/src/server_events.rs @@ -6,17 +6,18 @@ #![allow(clippy::module_name_repetitions)] -use crate::connection::Http3State; +use crate::connection::{Http3State, WebTransportSessionAcceptAction}; use crate::connection_server::Http3ServerHandler; use crate::{ features::extended_connect::SessionCloseReason, Http3StreamInfo, Http3StreamType, Priority, Res, }; -use neqo_common::{qdebug, qinfo, Header}; +use neqo_common::{qdebug, qinfo, Encoder, Header}; use neqo_transport::server::ActiveConnectionRef; -use neqo_transport::{AppError, Connection, StreamId, StreamType}; +use neqo_transport::{AppError, Connection, DatagramTracking, StreamId, StreamType}; use std::cell::RefCell; use std::collections::VecDeque; +use std::convert::TryFrom; use std::ops::{Deref, DerefMut}; use std::rc::Rc; @@ -244,7 +245,7 @@ impl WebTransportRequest { /// Respond to a `WebTransport` session request. /// # Errors /// It may return `InvalidStreamId` if a stream does not exist anymore. - pub fn response(&mut self, accept: bool) -> Res<()> { + pub fn response(&mut self, accept: &WebTransportSessionAcceptAction) -> Res<()> { qinfo!([self], "Set a response for a WebTransport session."); self.stream_handler .handler @@ -298,6 +299,45 @@ impl WebTransportRequest { Http3StreamInfo::new(id, Http3StreamType::WebTransport(session_id)), )) } + + /// Send `WebTransport` datagram. + /// # Errors + /// It may return `InvalidStreamId` if a stream does not exist anymore. + /// The function returns `TooMuchData` if the supply buffer is bigger than + /// the allowed remote datagram size. + pub fn send_datagram(&mut self, buf: &[u8], id: impl Into) -> Res<()> { + let session_id = self.stream_handler.stream_id(); + self.stream_handler + .handler + .borrow_mut() + .webtransport_send_datagram( + &mut self.stream_handler.conn.borrow_mut(), + session_id, + buf, + id, + ) + } + + #[must_use] + pub fn remote_datagram_size(&self) -> u64 { + self.stream_handler.conn.borrow().remote_datagram_size() + } + + /// Returns the current max size of a datagram that can fit into a packet. + /// The value will change over time depending on the encoded size of the + /// packet number, ack frames, etc. + /// # Errors + /// The function returns `NotAvailable` if datagrams are not enabled. + /// # Panics + /// This cannot panic. The max varint length is 8. + pub fn max_datagram_size(&self) -> Res { + let max_size = self.stream_handler.conn.borrow().max_datagram_size()?; + Ok(max_size + - u64::try_from(Encoder::varint_len( + self.stream_handler.stream_id().as_u64(), + )) + .unwrap()) + } } impl Deref for WebTransportRequest { @@ -340,6 +380,10 @@ pub enum WebTransportServerEvent { reason: SessionCloseReason, }, NewStream(Http3OrWebTransportStream), + Datagram { + session: WebTransportRequest, + datagram: Vec, + }, } #[derive(Debug, Clone)] @@ -508,4 +552,10 @@ impl Http3ServerEvents { WebTransportServerEvent::NewStream(stream), )); } + + pub(crate) fn webtransport_datagram(&self, session: WebTransportRequest, datagram: Vec) { + self.insert(Http3ServerEvent::WebTransport( + WebTransportServerEvent::Datagram { session, datagram }, + )); + } } diff --git a/third_party/rust/neqo-http3/src/stream_type_reader.rs b/third_party/rust/neqo-http3/src/stream_type_reader.rs index f4422a9a1b77..be5d94adeb73 100644 --- a/third_party/rust/neqo-http3/src/stream_type_reader.rs +++ b/third_party/rust/neqo-http3/src/stream_type_reader.rs @@ -14,12 +14,12 @@ use neqo_qpack::decoder::QPACK_UNI_STREAM_TYPE_DECODER; use neqo_qpack::encoder::QPACK_UNI_STREAM_TYPE_ENCODER; use neqo_transport::{Connection, StreamId, StreamType}; -pub const HTTP3_UNI_STREAM_TYPE_PUSH: u64 = 0x1; -pub const WEBTRANSPORT_UNI_STREAM: u64 = 0x54; -pub const WEBTRANSPORT_STREAM: u64 = 0x41; +pub(crate) const HTTP3_UNI_STREAM_TYPE_PUSH: u64 = 0x1; +pub(crate) const WEBTRANSPORT_UNI_STREAM: u64 = 0x54; +pub(crate) const WEBTRANSPORT_STREAM: u64 = 0x41; #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum NewStreamType { +pub(crate) enum NewStreamType { Control, Decoder, Encoder, @@ -74,7 +74,7 @@ impl NewStreamType { /// the `ReadType` state, `NewStreamHeadReader` changes to `ReadId` state and from there /// to `Done` state #[derive(Debug)] -pub enum NewStreamHeadReader { +pub(crate) enum NewStreamHeadReader { ReadType { role: Role, reader: IncrementalDecoderUint, diff --git a/third_party/rust/neqo-http3/tests/httpconn.rs b/third_party/rust/neqo-http3/tests/httpconn.rs index 8d6144550f36..c78b3f0be8b5 100644 --- a/third_party/rust/neqo-http3/tests/httpconn.rs +++ b/third_party/rust/neqo-http3/tests/httpconn.rs @@ -6,14 +6,15 @@ #![allow(unused_assignments)] -use neqo_common::{event::Provider, Datagram}; +use neqo_common::{event::Provider, qtrace, Datagram}; use neqo_crypto::{AuthenticationStatus, ResumptionToken}; use neqo_http3::{ Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, Http3State, Priority, }; -use neqo_transport::{ConnectionParameters, StreamType}; +use neqo_transport::{ConnectionError, ConnectionParameters, Error, Output, StreamType}; use std::mem; +use std::time::{Duration, Instant}; use test_fixture::*; const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63]; @@ -111,6 +112,39 @@ fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option out.dgram() } +fn connect_peers_with_network_propagation_delay( + hconn_c: &mut Http3Client, + hconn_s: &mut Http3Server, + net_delay: u64, +) -> (Option, Instant) { + let net_delay = Duration::from_millis(net_delay); + assert_eq!(hconn_c.state(), Http3State::Initializing); + let mut now = now(); + let out = hconn_c.process(None, now); // Initial + now += net_delay; + let out = hconn_s.process(out.dgram(), now); // Initial + Handshake + now += net_delay; + let out = hconn_c.process(out.dgram(), now); // ACK + now += net_delay; + let out = hconn_s.process(out.dgram(), now); //consume ACK + assert!(out.dgram().is_none()); + let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded); + assert!(hconn_c.events().any(authentication_needed)); + now += net_delay; + hconn_c.authenticated(AuthenticationStatus::Ok, now); + let out = hconn_c.process(None, now); // Handshake + assert_eq!(hconn_c.state(), Http3State::Connected); + now += net_delay; + let out = hconn_s.process(out.dgram(), now); // HANDSHAKE_DONE + now += net_delay; + let out = hconn_c.process(out.dgram(), now); // Consume HANDSHAKE_DONE, send control streams. + now += net_delay; + let out = hconn_s.process(out.dgram(), now); // consume and send control streams. + now += net_delay; + let out = hconn_c.process(out.dgram(), now); // consume control streams. + (out.dgram(), now) +} + fn connect() -> (Http3Client, Http3Server, Option) { let mut hconn_c = default_http3_client(); let mut hconn_s = default_http3_server(); @@ -139,7 +173,7 @@ fn test_connect() { fn test_fetch() { let (mut hconn_c, mut hconn_s, dgram) = connect(); - eprintln!("-----client"); + qtrace!("-----client"); let req = hconn_c .fetch( now(), @@ -152,13 +186,13 @@ fn test_fetch() { assert_eq!(req, 0); hconn_c.stream_close_send(req).unwrap(); let out = hconn_c.process(dgram, now()); - eprintln!("-----server"); + qtrace!("-----server"); let out = hconn_s.process(out.dgram(), now()); mem::drop(hconn_c.process(out.dgram(), now())); process_server_events(&mut hconn_s); let out = hconn_s.process(None, now()); - eprintln!("-----client"); + qtrace!("-----client"); mem::drop(hconn_c.process(out.dgram(), now())); let out = hconn_s.process(None, now()); mem::drop(hconn_c.process(out.dgram(), now())); @@ -379,3 +413,48 @@ fn zerortt() { exchange_packets(&mut hconn_c, &mut hconn_s, out.dgram()); process_client_events(&mut hconn_c); } + +#[test] +/// When a client has an outstanding fetch, it will send keepalives. +/// Test that it will successfully run until the connection times out. +fn fetch_noresponse_will_idletimeout() { + let mut hconn_c = default_http3_client(); + let mut hconn_s = default_http3_server(); + + let (dgram, mut now) = + connect_peers_with_network_propagation_delay(&mut hconn_c, &mut hconn_s, 10); + + qtrace!("-----client"); + let req = hconn_c + .fetch( + now, + "GET", + &("https", "something.com", "/"), + &[], + Priority::default(), + ) + .unwrap(); + assert_eq!(req, 0); + hconn_c.stream_close_send(req).unwrap(); + let _out = hconn_c.process(dgram, now); + qtrace!("-----server"); + + let mut done = false; + while !done { + while let Some(event) = hconn_c.next_event() { + if let Http3ClientEvent::StateChange(state) = event { + match state { + Http3State::Closing(error_code) | Http3State::Closed(error_code) => { + assert_eq!(error_code, ConnectionError::Transport(Error::IdleTimeout)); + done = true; + } + _ => {} + } + } + } + + if let Output::Callback(t) = hconn_c.process_output(now) { + now += t; + } + } +} diff --git a/third_party/rust/neqo-http3/tests/webtransport.rs b/third_party/rust/neqo-http3/tests/webtransport.rs new file mode 100644 index 000000000000..f5ba76ced836 --- /dev/null +++ b/third_party/rust/neqo-http3/tests/webtransport.rs @@ -0,0 +1,315 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use neqo_common::event::Provider; +use neqo_crypto::AuthenticationStatus; +use neqo_http3::{ + Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, + Http3ServerEvent, Http3State, WebTransportEvent, WebTransportRequest, WebTransportServerEvent, + WebTransportSessionAcceptAction, +}; +use neqo_transport::{StreamId, StreamType}; +use std::cell::RefCell; +use std::rc::Rc; +use test_fixture::{ + addr, anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ALPN_H3, + DEFAULT_KEYS, DEFAULT_SERVER_NAME, +}; + +fn connect() -> (Http3Client, Http3Server) { + fixture_init(); + let mut client = Http3Client::new( + DEFAULT_SERVER_NAME, + Rc::new(RefCell::new(CountingConnectionIdGenerator::default())), + addr(), + addr(), + Http3Parameters::default().webtransport(true), + now(), + ) + .expect("create a default client"); + let mut server = Http3Server::new( + now(), + DEFAULT_KEYS, + DEFAULT_ALPN_H3, + anti_replay(), + Rc::new(RefCell::new(CountingConnectionIdGenerator::default())), + Http3Parameters::default().webtransport(true), + None, + ) + .expect("create a server"); + assert_eq!(client.state(), Http3State::Initializing); + let out = client.process(None, now()); + assert_eq!(client.state(), Http3State::Initializing); + + let out = server.process(out.dgram(), now()); + let out = client.process(out.dgram(), now()); + let out = server.process(out.dgram(), now()); + assert!(out.as_dgram_ref().is_none()); + + let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded); + assert!(client.events().any(authentication_needed)); + client.authenticated(AuthenticationStatus::Ok, now()); + + let mut out = client.process(out.dgram(), now()).dgram(); + let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected)); + assert!(client.events().any(connected)); + + assert_eq!(client.state(), Http3State::Connected); + + // Exchange H3 setttings + loop { + out = server.process(out, now()).dgram(); + let dgram_present = out.is_some(); + out = client.process(out, now()).dgram(); + if out.is_none() && !dgram_present { + break; + } + } + (client, server) +} + +fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) { + let mut out = None; + loop { + out = client.process(out, now()).dgram(); + out = server.process(out, now()).dgram(); + if out.is_none() { + break; + } + } +} + +fn create_wt_session(client: &mut Http3Client, server: &mut Http3Server) -> WebTransportRequest { + let wt_session_id = client + .webtransport_create_session(now(), &("https", "something.com", "/"), &[]) + .unwrap(); + exchange_packets(client, server); + + let mut wt_server_session = None; + while let Some(event) = server.next_event() { + match event { + Http3ServerEvent::WebTransport(WebTransportServerEvent::NewSession { + mut session, + headers, + }) => { + assert!( + headers + .iter() + .any(|h| h.name() == ":method" && h.value() == "CONNECT") + && headers + .iter() + .any(|h| h.name() == ":protocol" && h.value() == "webtransport") + ); + session + .response(&WebTransportSessionAcceptAction::Accept) + .unwrap(); + wt_server_session = Some(session); + } + Http3ServerEvent::Data { .. } => { + panic!("There should not be any data events!"); + } + _ => {} + } + } + + exchange_packets(client, server); + + let wt_session_negotiated_event = |e| { + matches!( + e, + Http3ClientEvent::WebTransport(WebTransportEvent::Session{ + stream_id, + status + }) if stream_id == wt_session_id && status == 200 + ) + }; + assert!(client.events().any(wt_session_negotiated_event)); + + let wt_server_session = wt_server_session.unwrap(); + assert_eq!(wt_session_id, wt_server_session.stream_id()); + wt_server_session +} + +fn send_data_client( + client: &mut Http3Client, + server: &mut Http3Server, + wt_stream_id: StreamId, + data: &[u8], +) { + assert_eq!(client.send_data(wt_stream_id, data).unwrap(), data.len()); + exchange_packets(client, server); +} + +fn send_data_server( + client: &mut Http3Client, + server: &mut Http3Server, + wt_stream: &mut Http3OrWebTransportStream, + data: &[u8], +) { + assert_eq!(wt_stream.send_data(data).unwrap(), data.len()); + exchange_packets(client, server); +} + +fn receive_data_client( + client: &mut Http3Client, + expected_stream_id: StreamId, + new_stream: bool, + expected_data: &[u8], + expected_fin: bool, +) { + let mut new_stream_received = false; + let mut data_received = false; + while let Some(event) = client.next_event() { + match event { + Http3ClientEvent::WebTransport(WebTransportEvent::NewStream { stream_id, .. }) => { + assert_eq!(stream_id, expected_stream_id); + new_stream_received = true; + } + Http3ClientEvent::DataReadable { stream_id } => { + assert_eq!(stream_id, expected_stream_id); + let mut buf = [0; 100]; + let (amount, fin) = client.read_data(now(), stream_id, &mut buf).unwrap(); + assert_eq!(fin, expected_fin); + assert_eq!(amount, expected_data.len()); + assert_eq!(&buf[..amount], expected_data); + data_received = true; + } + _ => {} + } + } + assert!(data_received); + assert_eq!(new_stream, new_stream_received); +} + +fn receive_data_server( + client: &mut Http3Client, + server: &mut Http3Server, + stream_id: StreamId, + new_stream: bool, + expected_data: &[u8], + expected_fin: bool, +) -> Http3OrWebTransportStream { + exchange_packets(client, server); + let mut new_stream_received = false; + let mut data_received = false; + let mut wt_stream = None; + let mut stream_closed = false; + let mut recv_data = Vec::new(); + while let Some(event) = server.next_event() { + match event { + Http3ServerEvent::WebTransport(WebTransportServerEvent::NewStream(request)) => { + assert_eq!(stream_id, request.stream_id()); + new_stream_received = true; + } + Http3ServerEvent::Data { + mut data, + fin, + stream, + } => { + recv_data.append(&mut data); + stream_closed = fin; + data_received = true; + wt_stream = Some(stream); + } + _ => {} + } + } + assert_eq!(&recv_data[..], expected_data); + assert!(data_received); + assert_eq!(new_stream, new_stream_received); + assert_eq!(stream_closed, expected_fin); + wt_stream.unwrap() +} + +#[test] +fn wt_client_stream_uni() { + const BUF_CLIENT: &[u8] = &[0; 10]; + + let (mut client, mut server) = connect(); + let wt_session = create_wt_session(&mut client, &mut server); + let wt_stream = client + .webtransport_create_stream(wt_session.stream_id(), StreamType::UniDi) + .unwrap(); + send_data_client(&mut client, &mut server, wt_stream, BUF_CLIENT); + exchange_packets(&mut client, &mut server); + receive_data_server(&mut client, &mut server, wt_stream, true, BUF_CLIENT, false); +} + +#[test] +fn wt_client_stream_bidi() { + const BUF_CLIENT: &[u8] = &[0; 10]; + const BUF_SERVER: &[u8] = &[1; 20]; + + let (mut client, mut server) = connect(); + let wt_session = create_wt_session(&mut client, &mut server); + let wt_client_stream = client + .webtransport_create_stream(wt_session.stream_id(), StreamType::BiDi) + .unwrap(); + send_data_client(&mut client, &mut server, wt_client_stream, BUF_CLIENT); + let mut wt_server_stream = receive_data_server( + &mut client, + &mut server, + wt_client_stream, + true, + BUF_CLIENT, + false, + ); + send_data_server(&mut client, &mut server, &mut wt_server_stream, BUF_SERVER); + receive_data_client(&mut client, wt_client_stream, false, BUF_SERVER, false); +} + +#[test] +fn wt_server_stream_uni() { + const BUF_SERVER: &[u8] = &[2; 30]; + + let (mut client, mut server) = connect(); + let mut wt_session = create_wt_session(&mut client, &mut server); + let mut wt_server_stream = wt_session.create_stream(StreamType::UniDi).unwrap(); + send_data_server(&mut client, &mut server, &mut wt_server_stream, BUF_SERVER); + receive_data_client( + &mut client, + wt_server_stream.stream_id(), + true, + BUF_SERVER, + false, + ); +} + +#[test] +fn wt_server_stream_bidi() { + const BUF_CLIENT: &[u8] = &[0; 10]; + const BUF_SERVER: &[u8] = &[1; 20]; + + let (mut client, mut server) = connect(); + let mut wt_session = create_wt_session(&mut client, &mut server); + let mut wt_server_stream = wt_session.create_stream(StreamType::BiDi).unwrap(); + send_data_server(&mut client, &mut server, &mut wt_server_stream, BUF_SERVER); + receive_data_client( + &mut client, + wt_server_stream.stream_id(), + true, + BUF_SERVER, + false, + ); + send_data_client( + &mut client, + &mut server, + wt_server_stream.stream_id(), + BUF_CLIENT, + ); + assert_eq!( + receive_data_server( + &mut client, + &mut server, + wt_server_stream.stream_id(), + false, + BUF_CLIENT, + false + ) + .stream_id(), + wt_server_stream.stream_id() + ); +} diff --git a/third_party/rust/neqo-http3/tests/webtransport/negotiation.rs b/third_party/rust/neqo-http3/tests/webtransport/negotiation.rs deleted file mode 100644 index b13bc5a4ae18..000000000000 --- a/third_party/rust/neqo-http3/tests/webtransport/negotiation.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{connect, default_http3_client, default_http3_server, exchange_packets}; -use neqo_common::{event::Provider, Encoder}; -use neqo_crypto::AuthenticationStatus; -use neqo_http3::{ - settings::{HSetting, HSettingType, HSettings}, - Error, HFrame, Http3Client, Http3ClientEvent, Http3State, WebTransportEvent, -}; -use neqo_transport::{Connection, ConnectionError, StreamType}; -use std::time::Duration; -use test_fixture::*; - -fn check_wt_event(client: &mut Http3Client, wt_enable_client: bool, wt_enable_server: bool) { - let wt_event = client.events().find_map(|e| { - if let Http3ClientEvent::WebTransport(WebTransportEvent::Negotiated(neg)) = e { - Some(neg) - } else { - None - } - }); - - assert_eq!(wt_event.is_some(), wt_enable_client); - if let Some(wt) = wt_event { - assert_eq!(wt, wt_enable_client && wt_enable_server); - } -} - -#[test] -fn negotiate_wt() { - let (mut client, _server) = connect(true, true); - assert!(client.webtransport_enabled()); - check_wt_event(&mut client, true, true); - - let (mut client, _server) = connect(true, false); - assert!(!client.webtransport_enabled()); - check_wt_event(&mut client, true, false); - - let (mut client, _server) = connect(false, true); - assert!(!client.webtransport_enabled()); - check_wt_event(&mut client, false, true); - - let (mut client, _server) = connect(false, false); - assert!(!client.webtransport_enabled()); - check_wt_event(&mut client, false, false); -} - -fn zero_rtt(client_org: bool, server_org: bool, client_resumed: bool, server_resumed: bool) { - let (mut client, mut server) = connect(client_org, server_org); - assert_eq!(client.webtransport_enabled(), client_org && server_org); - - // exchane token - let out = server.process(None, now()); - // We do not have a token so we need to wait for a resumption token timer to trigger. - let _ = client.process(out.dgram(), now() + Duration::from_millis(250)); - assert_eq!(client.state(), Http3State::Connected); - let token = client - .events() - .find_map(|e| { - if let Http3ClientEvent::ResumptionToken(token) = e { - Some(token) - } else { - None - } - }) - .unwrap(); - - let mut client = default_http3_client(client_resumed); - let mut server = default_http3_server(server_resumed); - client - .enable_resumption(now(), &token) - .expect("Set resumption token."); - assert_eq!(client.state(), Http3State::ZeroRtt); - - exchange_packets(&mut client, &mut server); - - assert_eq!(&client.state(), &Http3State::Connected); - assert_eq!( - client.webtransport_enabled(), - client_resumed && server_resumed - ); - check_wt_event(&mut client, client_resumed, server_resumed); -} - -#[test] -fn zero_rtt_wt_settings() { - zero_rtt(true, true, true, true); - zero_rtt(true, true, true, false); - zero_rtt(true, true, false, true); - zero_rtt(true, true, false, false); - - zero_rtt(true, false, true, false); - zero_rtt(true, false, true, true); - zero_rtt(true, false, false, false); - zero_rtt(true, false, false, true); - - zero_rtt(false, false, false, false); - zero_rtt(false, false, false, true); - zero_rtt(false, false, true, false); - zero_rtt(false, false, true, true); - - zero_rtt(false, true, false, true); - zero_rtt(false, true, false, false); - zero_rtt(false, true, true, false); - zero_rtt(false, true, true, true); -} - -fn exchange_packets2(client: &mut Http3Client, server: &mut Connection) { - let mut out = None; - loop { - out = client.process(out, now()).dgram(); - out = server.process(out, now()).dgram(); - if out.is_none() { - break; - } - } -} - -#[test] -fn wrong_setting_value() { - const CONTROL_STREAM_TYPE: &[u8] = &[0x0]; - let mut client = default_http3_client(false); - let mut server = default_server_h3(); - - exchange_packets2(&mut client, &mut server); - client.authenticated(AuthenticationStatus::Ok, now()); - exchange_packets2(&mut client, &mut server); - - let control = server.stream_create(StreamType::UniDi).unwrap(); - server.stream_send(control, CONTROL_STREAM_TYPE).unwrap(); - // Encode a settings frame and send it. - let mut enc = Encoder::default(); - let settings = HFrame::Settings { - settings: HSettings::new(&[HSetting::new(HSettingType::EnableWebTransport, 2)]), - }; - settings.encode(&mut enc); - assert_eq!( - server.stream_send(control, enc.as_ref()).unwrap(), - enc.as_ref().len() - ); - - exchange_packets2(&mut client, &mut server); - match client.state() { - Http3State::Closing(err) | Http3State::Closed(err) => { - assert_eq!( - err, - ConnectionError::Application(Error::HttpSettings.code()) - ); - } - _ => panic!("Wrong state {:?}", client.state()), - }; -} diff --git a/third_party/rust/neqo-qpack/.cargo-checksum.json b/third_party/rust/neqo-qpack/.cargo-checksum.json index 81a1edc36e40..5fa989ca5ff1 100644 --- a/third_party/rust/neqo-qpack/.cargo-checksum.json +++ b/third_party/rust/neqo-qpack/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"9c7bc0f5de79c42f0957ab114f8a4ca38c276cc9f90e3823dc3b5e3a85226b66","src/decoder.rs":"8bd336c91cca989883106a9d0bf26b117d224e0e7643960c3e97d0168d1853c4","src/decoder_instructions.rs":"2205c7635b8f0c568f6fe9a63c17028eaf8d29a9b5ac7136b6554cc7fbf35038","src/encoder.rs":"b888a819595fec47037d508b943f5ff04ed52ea376bef1f90e08edc6576e773c","src/encoder_instructions.rs":"1eb4f6eee2d9ff16f96dc5bf80dae9bc04316126f6eca933fb51dbd9218a439c","src/header_block.rs":"76f4c8fad6a13d4d24530cf067d20622cdbd345f7d9779b0be9691a77fa8fb63","src/huffman.rs":"3a9edaf827343ec6e43cfd50fcc0d0077287947160ae630da5c3ddaaefedd010","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"6e25612bb30f0e4361566662da1e5353131ae12f97938c6ac3b2dafbf6a8bc86","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"49ded6607ec0859cb3edc5a38ff48f4d2d292f0721673d4e20700d07ac324557","src/reader.rs":"be265cc8c317512f266fafdcc835d0e413caf5280a7cc945bfe6e7e849529d67","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"880cdcddc73dceafa69773ae482a1eaaced927504856130b0cc15ec91ac31e59","src/decoder.rs":"8bd336c91cca989883106a9d0bf26b117d224e0e7643960c3e97d0168d1853c4","src/decoder_instructions.rs":"2205c7635b8f0c568f6fe9a63c17028eaf8d29a9b5ac7136b6554cc7fbf35038","src/encoder.rs":"b888a819595fec47037d508b943f5ff04ed52ea376bef1f90e08edc6576e773c","src/encoder_instructions.rs":"1eb4f6eee2d9ff16f96dc5bf80dae9bc04316126f6eca933fb51dbd9218a439c","src/header_block.rs":"9ee3bc4189ae36ae0a926295f6f8b3a1169463a19ccbc65e6d588c8b317020ad","src/huffman.rs":"3a9edaf827343ec6e43cfd50fcc0d0077287947160ae630da5c3ddaaefedd010","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"6e25612bb30f0e4361566662da1e5353131ae12f97938c6ac3b2dafbf6a8bc86","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"bc86cce786b6c8a468aed8d436ec4a8a86b3d4a917495fff7931ba4026c36c47","src/reader.rs":"be265cc8c317512f266fafdcc835d0e413caf5280a7cc945bfe6e7e849529d67","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-qpack/Cargo.toml b/third_party/rust/neqo-qpack/Cargo.toml index f98aa7557e60..daa1bf8029e0 100644 --- a/third_party/rust/neqo-qpack/Cargo.toml +++ b/third_party/rust/neqo-qpack/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neqo-qpack" -version = "0.6.1" +version = "0.6.3" authors = ["Dragana Damjanovic "] edition = "2018" rust-version = "1.57.0" diff --git a/third_party/rust/neqo-qpack/src/header_block.rs b/third_party/rust/neqo-qpack/src/header_block.rs index 052f0b08a718..38f8738df943 100644 --- a/third_party/rust/neqo-qpack/src/header_block.rs +++ b/third_party/rust/neqo-qpack/src/header_block.rs @@ -161,7 +161,7 @@ impl HeaderEncoder { impl Deref for HeaderEncoder { type Target = [u8]; fn deref(&self) -> &Self::Target { - &*self.buf + &self.buf } } diff --git a/third_party/rust/neqo-qpack/src/qpack_send_buf.rs b/third_party/rust/neqo-qpack/src/qpack_send_buf.rs index e83424f421c6..4fbdbf12bd5b 100644 --- a/third_party/rust/neqo-qpack/src/qpack_send_buf.rs +++ b/third_party/rust/neqo-qpack/src/qpack_send_buf.rs @@ -99,7 +99,7 @@ impl QpackData { impl Deref for QpackData { type Target = [u8]; fn deref(&self) -> &Self::Target { - &*self.buf + &self.buf } } diff --git a/third_party/rust/neqo-transport/.cargo-checksum.json b/third_party/rust/neqo-transport/.cargo-checksum.json index 02697e1fb80d..1cb240328780 100644 --- a/third_party/rust/neqo-transport/.cargo-checksum.json +++ b/third_party/rust/neqo-transport/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0b92e2fa806cbbe034c260112b5bc523ad6ee8e52fd7ce9b8385e3e74f6a6d13","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/ackrate.rs":"cd288796a35329761f8da8963e83fca3083d08e813ec741e7f3f37c8465a60ce","src/addr_valid.rs":"d6008b0af47276b1ff3747ebbfa6fabe72aa4002116ae24c4b4de60090dc78e6","src/cc/classic_cc.rs":"b29e1c2cf6b0d2a9e43993d98c74b36245cde423152863186f876abec1f79c3b","src/cc/cubic.rs":"6da1b24f5253ee05f66efd8c7ee4ceeb0922c219982db1ebeb7a955180e395ee","src/cc/mod.rs":"7a7eeecebdbe2ea610c41fe1ae77083070f26158d60c0d32fd49e63302568e73","src/cc/new_reno.rs":"f4c93ccb5a132eafcff5f358b80efda31ab1aa5667c79b351d4cadefc33bbb7f","src/cc/tests/cubic.rs":"88ed30285c3fb7bfb55ed3ec127210d805982fca9b5882fb3a28f1302567f9fe","src/cc/tests/mod.rs":"1567bf0ddaff5cb679217f2fd65f01e15a302b9b9e68b69f3e617dcaf7b3e5ec","src/cc/tests/new_reno.rs":"6068715ace20d831718a5b5a4e7e1d37f83c02a5b870dc6c2289166407d741db","src/cid.rs":"674d046c200b5cb2d1c1caa629bf06e7bc148fb0f6454e3d0f984aaee4450d97","src/connection/idle.rs":"f674cf04c925792299d37a25bca0ecc39572410667f1dad908d18efa2562cfec","src/connection/mod.rs":"58a505a782e71f066653ba333b82a0834ba81848521abb19d5984ce7e75a387a","src/connection/params.rs":"08c7f3685e4b86738486e4a0e43337cc85e124533e4282492ec0517f6f18aa8e","src/connection/saved.rs":"f611ab477541262ac7605fa481a92c4b4d3bcd54fff58a4b97f51df86c752563","src/connection/state.rs":"3bf306b97ff009f8c490c34940fb38562d2bff63953f6913e06b135e39b77ed0","src/connection/test_internal.rs":"f3ebfe97b25c9c716d41406066295e5aff4e96a3051ef4e2b5fb258282bbc14c","src/connection/tests/ackrate.rs":"6530705d78fa86eb257195337979e35ce0186ccbced15ecd3ebbf730ff16f100","src/connection/tests/cc.rs":"c36d724dbc2aeb4d40b89d7e822382e6711db34b0f7226dfc906966730f46610","src/connection/tests/close.rs":"f02522c5a525a24601227904c9f176f884114d7b23a3db04cb38e0694a21672a","src/connection/tests/datagram.rs":"dcf4d9f2b1561f02adccb877a626b8155490b669e5baf6ab166928042e476684","src/connection/tests/fuzzing.rs":"ef96fb5c3af63fbc44da70bdbc73a16234443332ba812282db6da876b07db861","src/connection/tests/handshake.rs":"462780dd1b8872b7bce4dca87fa8884bc034f84c84b774bcb4fee8f63a8b4c0c","src/connection/tests/idle.rs":"60916e37b7560f29a7ef7eabe8777444d224ebe068e3f5b0d30978958603f5e4","src/connection/tests/keys.rs":"c63bf6cd6996e5d7ea54528045ec98f2172cfe9886bdeeec659c1401ead2579c","src/connection/tests/migration.rs":"d2b47367fc491bb3b4b9475a628c3546512f9515a4b06ee5b6800ee916a59285","src/connection/tests/mod.rs":"2d8c0fb96a5167eaf44d8c34fcdb0e538be7c08761e7c524fb7e9d57fa3b627d","src/connection/tests/priority.rs":"791855027134056ee5a2c19a4713650ae643253ed77a2e7fa4d935bec56bade4","src/connection/tests/recovery.rs":"0e8ad02b8262405d86300a96b657cafea60fce3d169980d60633ea0fe47b0bb1","src/connection/tests/resumption.rs":"985d9573bcb097d12e717841cbc32e3433bb60e206e1daf7264878008e9983fe","src/connection/tests/stream.rs":"f6ae8524d611f78cc1ee80c314953120ff15cfce63291d7ee11856b79d69a7fb","src/connection/tests/vn.rs":"01e56a2ced51d84492c98592d40ed1eab2a158f7577589fa2e92f649d38075f8","src/connection/tests/zerortt.rs":"14578e0dad2def5a9542423c1a34f9c9e3d453fe9dd158defcae347c6c14da27","src/crypto.rs":"4787edffde30c05ba93e698489133a00ea933a355bdaaa57e845fba17a9aa84c","src/dump.rs":"d08f15a2ef4cfd61ed34e1fd3a0937f0334c3c1a074fb76c5f004cf515154e5c","src/events.rs":"5373063c64581e9a06cd7aa42b0a84a152ef7441067499183bd9bd253bf1f32a","src/fc.rs":"a90cd52727484901ecbc692525086f4a205f4eafef252cbb991b5b33dcda7014","src/frame.rs":"61f1f83152ce78e4cbd548414fd4eadba1b5dd0a83012bdfacf9e5a6e37d7c2c","src/lib.rs":"bafdfbce59ee2c49435ef3756969c671e196ea0b5f6c93f36045f39f826d75e1","src/pace.rs":"6c6a67ae4300f0af3670bae76478741348e56d2090245ce6c014fa85f066fe01","src/packet/mod.rs":"22e822794ea5cdcf93ecb8411c388ab782fa65572dfa3328f662ab6343f97512","src/packet/retry.rs":"b4822094d283225eb8944e0ba4abf286eb76a161b8379c8efbc93c4bceabc111","src/path.rs":"8e96755424c9c9413f30c72f02539d83a3af1aadb132a4f1a62a9b8c5b57c635","src/qlog.rs":"e0352ebb864a8bccf34be853484b316f061e46d71146c61891b3395b81e3db2e","src/quic_datagrams.rs":"b65fafd57550a87a311b4e2706cde5a153040689d73b5eb2bf9ba28e9ef8f2c6","src/recovery.rs":"b94a1118dc3ac71e3068b2c6ffb467fad016ddb6936e21f60f41dd68e698f1c5","src/recv_stream.rs":"998b60826b9f396131c180b715b19917152804b64a8064519ca4dabf0fd5cab7","src/rtt.rs":"688bccee574b9782399882c6a9e34058d75f2ac7c31008bcd1f36fed12676299","src/send_stream.rs":"ce92994082622fba94486bed9b673f79fc7e454878b5cfb1bd2ba10907b740b9","src/sender.rs":"07f8030e2a341ac0496016d46a06b2b1778f268c8b9abc8ae66c1482fdc72653","src/server.rs":"55d9ee515337b016cfcbbaab07501a661fc95c6147b8360c19cf6a6655142721","src/stats.rs":"14829dfeb76c5e031e06384757ee65a2144008e05b850a5e6b0fed0b6a62c98d","src/stream_id.rs":"dc776de915bfe8af022492b1de7ba9b2105b7825af47c952703937502ca9bc77","src/streams.rs":"c1ec5c68e79e62c0d5c0f1e74e533272f78cfc7ec62355384c11f23b28476cb6","src/tparams.rs":"28d19d43e8de3909f4c6796e254e18dec43ad8bb4d7cd93d9d16c0eea4be596d","src/tracking.rs":"02bc36533bcb5a974d1bfc68b9dab9ea2578cc17e2015f4387e3bea6994a9897","src/version.rs":"3f5ae26db18fcfac719efc1a68ee2d6f2aaec74ccd75c82d20976ba96cadc136","tests/common/mod.rs":"0450c287c44594e812bfd98faedd2f9f3c7bc8591baa24cca025cdfe20836450","tests/conn_vectors.rs":"72d8d5132b0468facc58d764e52a29fbfc0004f2272df6087b73b53c018591a6","tests/connection.rs":"565a8b3f37fa22a95b42fe5248c3bd78d13271f24f68ccac83429c89916cdfe8","tests/network.rs":"a986c22da7132ec843a44c4bcb5a7d2726132aa27a47a8ea91634cd88e1b763b","tests/retry.rs":"a35853cb4c9443c5e84352bb56e1aed6ce423c4456a3e68f547d9bf0d8ea4181","tests/server.rs":"c7784351e9e9ab8bb11ea9af034d3cc2d8086ab278c6ad3dea5c6bb5e7a59265","tests/sim/connection.rs":"4c0e2310d9410f806ff746f86257e174bf326baf237ab6d3bb75c0ce43a36efd","tests/sim/delay.rs":"9efa722adb89e37262369e9f3c67405f0acc8c24997271811e48df9e856e5a8d","tests/sim/drop.rs":"bd89e5c71cdd1b27cd755faaedd87d5feadf2f424df721a7df41a51bcebcbb58","tests/sim/mod.rs":"357b96b519fedbda8f5f930066a64709f6cc15872843358e8d5fd62e66583bb5","tests/sim/net.rs":"597f4d37bc26c3d82eeeaa6d14dd03bc2be3930686df2b293748b43c07c497d7","tests/sim/rng.rs":"2c90b0bbaf0c952ebee232deb3594f7a86af387737b15474de3e97ee6b623d90","tests/sim/taildrop.rs":"5c505d150f0071e8cc2d540b3a817a6942fdf13df32f1fbc6822952f2e146176"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"62778649ca4c301c956736b7f3a6986aa4b756d2c4b0f9c06a90d1d131ffb8c3","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/ackrate.rs":"cd288796a35329761f8da8963e83fca3083d08e813ec741e7f3f37c8465a60ce","src/addr_valid.rs":"d6008b0af47276b1ff3747ebbfa6fabe72aa4002116ae24c4b4de60090dc78e6","src/cc/classic_cc.rs":"b29e1c2cf6b0d2a9e43993d98c74b36245cde423152863186f876abec1f79c3b","src/cc/cubic.rs":"6da1b24f5253ee05f66efd8c7ee4ceeb0922c219982db1ebeb7a955180e395ee","src/cc/mod.rs":"7a7eeecebdbe2ea610c41fe1ae77083070f26158d60c0d32fd49e63302568e73","src/cc/new_reno.rs":"f4c93ccb5a132eafcff5f358b80efda31ab1aa5667c79b351d4cadefc33bbb7f","src/cc/tests/cubic.rs":"88ed30285c3fb7bfb55ed3ec127210d805982fca9b5882fb3a28f1302567f9fe","src/cc/tests/mod.rs":"1567bf0ddaff5cb679217f2fd65f01e15a302b9b9e68b69f3e617dcaf7b3e5ec","src/cc/tests/new_reno.rs":"6068715ace20d831718a5b5a4e7e1d37f83c02a5b870dc6c2289166407d741db","src/cid.rs":"a3e82bbd720e477447a0b458fe9fc89138e8c2855559fce4f0caf2329556e7a1","src/connection/idle.rs":"935d3420952bf9fb10ed4bc74f9b062cb83725835012deed42123037480b2618","src/connection/mod.rs":"18c3ecc78e1dfcd6fb1551d5b118469be7e7a0becad654ce6e3f10290c47914c","src/connection/params.rs":"08c7f3685e4b86738486e4a0e43337cc85e124533e4282492ec0517f6f18aa8e","src/connection/saved.rs":"f611ab477541262ac7605fa481a92c4b4d3bcd54fff58a4b97f51df86c752563","src/connection/state.rs":"3bf306b97ff009f8c490c34940fb38562d2bff63953f6913e06b135e39b77ed0","src/connection/test_internal.rs":"f3ebfe97b25c9c716d41406066295e5aff4e96a3051ef4e2b5fb258282bbc14c","src/connection/tests/ackrate.rs":"6530705d78fa86eb257195337979e35ce0186ccbced15ecd3ebbf730ff16f100","src/connection/tests/cc.rs":"c36d724dbc2aeb4d40b89d7e822382e6711db34b0f7226dfc906966730f46610","src/connection/tests/close.rs":"c55788c917ce6c2345651bc6527254e5579ae917c816a12b64756fa366a343f7","src/connection/tests/datagram.rs":"dcf4d9f2b1561f02adccb877a626b8155490b669e5baf6ab166928042e476684","src/connection/tests/fuzzing.rs":"ef96fb5c3af63fbc44da70bdbc73a16234443332ba812282db6da876b07db861","src/connection/tests/handshake.rs":"462780dd1b8872b7bce4dca87fa8884bc034f84c84b774bcb4fee8f63a8b4c0c","src/connection/tests/idle.rs":"dcdcc20d0358bc125c2d8be8d4efc18aa29dbaf67cd81eac3328e78a8741b888","src/connection/tests/keys.rs":"c63bf6cd6996e5d7ea54528045ec98f2172cfe9886bdeeec659c1401ead2579c","src/connection/tests/migration.rs":"d2b47367fc491bb3b4b9475a628c3546512f9515a4b06ee5b6800ee916a59285","src/connection/tests/mod.rs":"2d8c0fb96a5167eaf44d8c34fcdb0e538be7c08761e7c524fb7e9d57fa3b627d","src/connection/tests/priority.rs":"791855027134056ee5a2c19a4713650ae643253ed77a2e7fa4d935bec56bade4","src/connection/tests/recovery.rs":"0e8ad02b8262405d86300a96b657cafea60fce3d169980d60633ea0fe47b0bb1","src/connection/tests/resumption.rs":"985d9573bcb097d12e717841cbc32e3433bb60e206e1daf7264878008e9983fe","src/connection/tests/stream.rs":"435ed6f4024d8ae8f592f6c2671871c05b266a4173b1d75a3db911867197252f","src/connection/tests/vn.rs":"01e56a2ced51d84492c98592d40ed1eab2a158f7577589fa2e92f649d38075f8","src/connection/tests/zerortt.rs":"14578e0dad2def5a9542423c1a34f9c9e3d453fe9dd158defcae347c6c14da27","src/crypto.rs":"4787edffde30c05ba93e698489133a00ea933a355bdaaa57e845fba17a9aa84c","src/dump.rs":"d08f15a2ef4cfd61ed34e1fd3a0937f0334c3c1a074fb76c5f004cf515154e5c","src/events.rs":"5373063c64581e9a06cd7aa42b0a84a152ef7441067499183bd9bd253bf1f32a","src/fc.rs":"7246481b981838ee7c1adad564220462a1c88697e5920a14eabf1d37d748d824","src/frame.rs":"61f1f83152ce78e4cbd548414fd4eadba1b5dd0a83012bdfacf9e5a6e37d7c2c","src/lib.rs":"22e8a05eb6504ed27500747920560d3ffdf546ee7d85ace866bef1404582fb18","src/pace.rs":"6c6a67ae4300f0af3670bae76478741348e56d2090245ce6c014fa85f066fe01","src/packet/mod.rs":"22e822794ea5cdcf93ecb8411c388ab782fa65572dfa3328f662ab6343f97512","src/packet/retry.rs":"b4822094d283225eb8944e0ba4abf286eb76a161b8379c8efbc93c4bceabc111","src/path.rs":"8f39bd9fc138bac6263655b1b487eef1b42f03347f5f5aa35979c8b32da70cdf","src/qlog.rs":"19148fdf205f56835189e41aaa316138f62f830978bf52b872007f7b9a6705e4","src/quic_datagrams.rs":"b65fafd57550a87a311b4e2706cde5a153040689d73b5eb2bf9ba28e9ef8f2c6","src/recovery.rs":"14c664bc803ad060856d8e28d1bcc3cc454c2167a4ab79e012548329b1eb6072","src/recv_stream.rs":"69c5a595195512a7b9c7a4000982826c57f668f5f70529987ae30747b5dbc3ad","src/rtt.rs":"688bccee574b9782399882c6a9e34058d75f2ac7c31008bcd1f36fed12676299","src/send_stream.rs":"4e5137c1826e4e33dda026b68021490ed4bc17893dad7f4eab26c83eed9a6951","src/sender.rs":"07f8030e2a341ac0496016d46a06b2b1778f268c8b9abc8ae66c1482fdc72653","src/server.rs":"55d9ee515337b016cfcbbaab07501a661fc95c6147b8360c19cf6a6655142721","src/stats.rs":"e60d71411e66a2e354ed18bf1cf527ff35bc12d8fb51e47a9ffd178d18351d59","src/stream_id.rs":"dc776de915bfe8af022492b1de7ba9b2105b7825af47c952703937502ca9bc77","src/streams.rs":"c1ec5c68e79e62c0d5c0f1e74e533272f78cfc7ec62355384c11f23b28476cb6","src/tparams.rs":"28d19d43e8de3909f4c6796e254e18dec43ad8bb4d7cd93d9d16c0eea4be596d","src/tracking.rs":"91afc219df9bf2f68be5702c7b18fac8cb39cabc7ca06466ba7f7cab83bbb9b7","src/version.rs":"3f5ae26db18fcfac719efc1a68ee2d6f2aaec74ccd75c82d20976ba96cadc136","tests/common/mod.rs":"0450c287c44594e812bfd98faedd2f9f3c7bc8591baa24cca025cdfe20836450","tests/conn_vectors.rs":"72d8d5132b0468facc58d764e52a29fbfc0004f2272df6087b73b53c018591a6","tests/connection.rs":"565a8b3f37fa22a95b42fe5248c3bd78d13271f24f68ccac83429c89916cdfe8","tests/network.rs":"a986c22da7132ec843a44c4bcb5a7d2726132aa27a47a8ea91634cd88e1b763b","tests/retry.rs":"a35853cb4c9443c5e84352bb56e1aed6ce423c4456a3e68f547d9bf0d8ea4181","tests/server.rs":"c7784351e9e9ab8bb11ea9af034d3cc2d8086ab278c6ad3dea5c6bb5e7a59265","tests/sim/connection.rs":"4c0e2310d9410f806ff746f86257e174bf326baf237ab6d3bb75c0ce43a36efd","tests/sim/delay.rs":"9efa722adb89e37262369e9f3c67405f0acc8c24997271811e48df9e856e5a8d","tests/sim/drop.rs":"bd89e5c71cdd1b27cd755faaedd87d5feadf2f424df721a7df41a51bcebcbb58","tests/sim/mod.rs":"5f29310329c74c85c73bafd29742e781011d2607fed59873b342ab3f8ca3b8dd","tests/sim/net.rs":"597f4d37bc26c3d82eeeaa6d14dd03bc2be3930686df2b293748b43c07c497d7","tests/sim/rng.rs":"2c90b0bbaf0c952ebee232deb3594f7a86af387737b15474de3e97ee6b623d90","tests/sim/taildrop.rs":"5c505d150f0071e8cc2d540b3a817a6942fdf13df32f1fbc6822952f2e146176"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-transport/Cargo.toml b/third_party/rust/neqo-transport/Cargo.toml index 6df03d626910..93ef93fa8740 100644 --- a/third_party/rust/neqo-transport/Cargo.toml +++ b/third_party/rust/neqo-transport/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neqo-transport" -version = "0.6.1" +version = "0.6.3" authors = ["EKR ", "Andy Grover "] edition = "2018" rust-version = "1.57.0" diff --git a/third_party/rust/neqo-transport/src/cid.rs b/third_party/rust/neqo-transport/src/cid.rs index d21bd4291994..38157419de39 100644 --- a/third_party/rust/neqo-transport/src/cid.rs +++ b/third_party/rust/neqo-transport/src/cid.rs @@ -127,13 +127,13 @@ pub struct ConnectionIdRef<'a> { impl<'a> ::std::fmt::Debug for ConnectionIdRef<'a> { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "CID {}", hex_with_len(&self.cid)) + write!(f, "CID {}", hex_with_len(self.cid)) } } impl<'a> ::std::fmt::Display for ConnectionIdRef<'a> { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", hex(&self.cid)) + write!(f, "{}", hex(self.cid)) } } diff --git a/third_party/rust/neqo-transport/src/connection/idle.rs b/third_party/rust/neqo-transport/src/connection/idle.rs index fe9173dc9df3..5b1bd857dc4e 100644 --- a/third_party/rust/neqo-transport/src/connection/idle.rs +++ b/third_party/rust/neqo-transport/src/connection/idle.rs @@ -46,7 +46,7 @@ impl IdleTimeout { IdleTimeoutState::Init => now, IdleTimeoutState::PacketReceived(t) | IdleTimeoutState::AckElicitingPacketSent(t) => t, }; - let delay = if keep_alive { + let delay = if keep_alive && !self.keep_alive_outstanding { // For a keep-alive timer, wait for half the timeout interval, but be sure // not to wait too little or we will send many unnecessary probes. max(self.timeout / 2, pto) diff --git a/third_party/rust/neqo-transport/src/connection/mod.rs b/third_party/rust/neqo-transport/src/connection/mod.rs index 9227ce08b7e7..483a4c0fb6a7 100644 --- a/third_party/rust/neqo-transport/src/connection/mod.rs +++ b/third_party/rust/neqo-transport/src/connection/mod.rs @@ -251,7 +251,7 @@ pub struct Connection { received_untracked: bool, /// This is responsible for the QuicDatagrams' handling: - /// https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram + /// quic_datagrams: QuicDatagrams, pub(crate) crypto: Crypto, @@ -607,13 +607,13 @@ impl Connection { } } - /// Get a resumption token. The correct way to obtain a resumption token is - /// waiting for the `ConnectionEvent::ResumptionToken` event. However, some - /// servers don't send `NEW_TOKEN` frames and so that event might be slow in - /// arriving. This is especially a problem for short-lived connections, where - /// the connection is closed before any events are released. This retrieves - /// the token, without waiting for the `NEW_TOKEN` frame to arrive. - /// + /// The correct way to obtain a resumption token is to wait for the + /// `ConnectionEvent::ResumptionToken` event. To emit the event we are waiting for a + /// resumption token and a `NEW_TOKEN` frame to arrive. Some servers don't send `NEW_TOKEN` + /// frames and in this case, we wait for 3xPTO before emitting an event. This is especially a + /// problem for short-lived connections, where the connection is closed before any events are + /// released. This function retrieves the token, without waiting for a `NEW_TOKEN` frame to + /// arrive. /// # Panics /// If this is called on a server. pub fn take_resumption_token(&mut self, now: Instant) -> Option { @@ -661,20 +661,20 @@ impl Connection { qtrace!([self], " RTT {:?}", rtt); let tp_slice = dec.decode_vvec().ok_or(Error::InvalidResumptionToken)?; - qtrace!([self], " transport parameters {}", hex(&tp_slice)); + qtrace!([self], " transport parameters {}", hex(tp_slice)); let mut dec_tp = Decoder::from(tp_slice); let tp = TransportParameters::decode(&mut dec_tp).map_err(|_| Error::InvalidResumptionToken)?; let init_token = dec.decode_vvec().ok_or(Error::InvalidResumptionToken)?; - qtrace!([self], " Initial token {}", hex(&init_token)); + qtrace!([self], " Initial token {}", hex(init_token)); let tok = dec.decode_remainder(); - qtrace!([self], " TLS token {}", hex(&tok)); + qtrace!([self], " TLS token {}", hex(tok)); match self.crypto.tls { Agent::Client(ref mut c) => { - let res = c.enable_resumption(&tok); + let res = c.enable_resumption(tok); if let Err(e) = res { self.absorb_error::(now, Err(Error::from(e))); return Ok(()); @@ -2101,7 +2101,7 @@ impl Connection { // Determine how we are sending packets (PTO, etc..). let mtu = path.borrow().mtu(); - let profile = self.loss_recovery.send_profile(&*path.borrow(), now); + let profile = self.loss_recovery.send_profile(&path.borrow(), now); qdebug!([self], "output_path send_profile {:?}", profile); // Frames for different epochs must go in different packets, but then these @@ -2222,7 +2222,12 @@ impl Connection { let mut packets: Vec = encoder.into(); if let Some(mut initial) = initial_sent.take() { if needs_padding { - qdebug!([self], "pad Initial to path MTU {}", mtu); + qdebug!( + [self], + "pad Initial from {} to path MTU {}", + packets.len(), + mtu + ); initial.size += mtu - packets.len(); packets.resize(mtu, 0); } @@ -2357,7 +2362,7 @@ impl Connection { self.cid_manager.set_limit(max_active_cids); } self.set_initial_limits(); - qlog::connection_tparams_set(&mut self.qlog, &*self.tps.borrow()); + qlog::connection_tparams_set(&mut self.qlog, &self.tps.borrow()); Ok(()) } diff --git a/third_party/rust/neqo-transport/src/connection/tests/close.rs b/third_party/rust/neqo-transport/src/connection/tests/close.rs index bf3f4c938b15..a9f1fafa2577 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/close.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/close.rs @@ -71,7 +71,7 @@ fn early_application_close() { let dgram = server.process(dgram, now()).dgram(); assert!(dgram.is_some()); - server.close(now(), 77, String::from("")); + server.close(now(), 77, String::new()); assert!(server.state().closed()); let dgram = server.process(None, now()).dgram(); assert!(dgram.is_some()); diff --git a/third_party/rust/neqo-transport/src/connection/tests/idle.rs b/third_party/rust/neqo-transport/src/connection/tests/idle.rs index 5fe17701306b..22e9c65ac3e7 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/idle.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/idle.rs @@ -6,9 +6,9 @@ use super::super::{Connection, ConnectionParameters, IdleTimeout, Output, State}; use super::{ - connect, connect_force_idle, connect_with_rtt, default_client, default_server, - maybe_authenticate, new_client, new_server, send_and_receive, send_something, AT_LEAST_PTO, - DEFAULT_STREAM_DATA, + connect, connect_force_idle, connect_rtt_idle, connect_with_rtt, default_client, + default_server, maybe_authenticate, new_client, new_server, send_and_receive, send_something, + AT_LEAST_PTO, DEFAULT_STREAM_DATA, }; use crate::packet::PacketBuilder; use crate::stats::FrameStats; @@ -272,7 +272,7 @@ fn idle_caching() { let mut client = default_client(); let mut server = default_server(); let start = now(); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); // Perform the first round trip, but drop the Initial from the server. // The client then caches the Handshake packet. @@ -657,3 +657,78 @@ fn keep_alive_uni() { server.process_input(dgram.unwrap(), now()); server.stream_keep_alive(stream, true).unwrap(); } + +/// Test a keep-alive ping is send if there are outstading ack-eliciting packets and that +/// the connection is closed after the idle timeout passes. +#[test] +fn keep_alive_with_ack_eliciting_packet_lost() { + const RTT: Duration = Duration::from_millis(500); // PTO will be ~1.1125s + + // The idle time out will be set to ~ 5 * PTO. (IDLE_TIMEOUT/2 > pto and IDLE_TIMEOUT/2 < pto + 2pto) + // After handshake all packets will be lost. The following steps will happen after the handshake: + // - data will be sent on a stream that is marked for keep-alive, (at start time) + // - PTO timer will trigger first, and the data will be retransmited toghether with a PING, (at the start time + pto) + // - keep-alive timer will trigger and a keep-alive PING will be sent, (at the start time + IDLE_TIMEOUT / 2) + // - PTO timer will trigger again. (at the start time + pto + 2*pto) + // - Idle time out will trigger (at the timeout + IDLE_TIMEOUT) + const IDLE_TIMEOUT: Duration = Duration::from_millis(6000); + + let mut client = new_client(ConnectionParameters::default().idle_timeout(IDLE_TIMEOUT)); + let mut server = default_server(); + let mut now = connect_rtt_idle(&mut client, &mut server, RTT); + // connect_rtt_idle increase now by RTT / 2; + now -= RTT / 2; + assert_idle(&mut client, now, IDLE_TIMEOUT); + + // Create a stream. + let stream = client.stream_create(StreamType::BiDi).unwrap(); + // Marking the stream for keep-alive changes the idle timeout. + client.stream_keep_alive(stream, true).unwrap(); + assert_idle(&mut client, now, IDLE_TIMEOUT / 2); + + // Send data on the stream that will be lost. + let _ = client.stream_send(stream, DEFAULT_STREAM_DATA).unwrap(); + let _lost_packet = client.process_output(now).dgram(); + + let pto = client.process_output(now).callback(); + // Wait for packet to be marked lost. + assert!(pto < IDLE_TIMEOUT / 2); + now += pto; + let retransmit = client.process_output(now).dgram(); + assert!(retransmit.is_some()); + let retransmit = client.process_output(now).dgram(); + assert!(retransmit.is_some()); + + // The next callback should be for an idle PING. + assert_eq!( + client.process_output(now).callback(), + IDLE_TIMEOUT / 2 - pto + ); + + // Wait that long and the client should send a PING frame. + now += IDLE_TIMEOUT / 2 - pto; + let pings_before = client.stats().frame_tx.ping; + let ping = client.process_output(now).dgram(); + assert!(ping.is_some()); + assert_eq!(client.stats().frame_tx.ping, pings_before + 1); + + // The next callback is for a PTO, the PTO timer is 2 * pto now. + assert_eq!(client.process_output(now).callback(), pto * 2); + now += pto * 2; + // Now we will retransmit stream data. + let retransmit = client.process_output(now).dgram(); + assert!(retransmit.is_some()); + let retransmit = client.process_output(now).dgram(); + assert!(retransmit.is_some()); + + // The next callback will be an idle timeout. + assert_eq!( + client.process_output(now).callback(), + IDLE_TIMEOUT / 2 - 2 * pto + ); + + now += IDLE_TIMEOUT / 2 - 2 * pto; + let out = client.process_output(now); + assert!(matches!(out, Output::None)); + assert!(matches!(client.state(), State::Closed(_))); +} diff --git a/third_party/rust/neqo-transport/src/connection/tests/stream.rs b/third_party/rust/neqo-transport/src/connection/tests/stream.rs index 58f0d7663c19..2968d96d4ad2 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/stream.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/stream.rs @@ -674,7 +674,7 @@ fn change_flow_control(stream_type: StreamType, new_fc: u64) { // server should receive a MAX_SREAM_DATA frame if the flow control window is updated. let out2 = client.process(None, now()); let out3 = server.process(out2.dgram(), now()); - let expected = if RECV_BUFFER_START < new_fc { 1 } else { 0 }; + let expected = usize::from(RECV_BUFFER_START < new_fc); assert_eq!(server.stats().frame_rx.max_stream_data, expected); // If the flow control window has been increased, server can write more data. diff --git a/third_party/rust/neqo-transport/src/fc.rs b/third_party/rust/neqo-transport/src/fc.rs index c4ae5fce852f..0afa828adaa5 100644 --- a/third_party/rust/neqo-transport/src/fc.rs +++ b/third_party/rust/neqo-transport/src/fc.rs @@ -803,7 +803,7 @@ mod test { fc[StreamType::BiDi].add_retired(1); fc[StreamType::BiDi].send_flowc_update(); // consume the frame - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut tokens = Vec::new(); fc[StreamType::BiDi].write_frames(&mut builder, &mut tokens, &mut FrameStats::default()); assert_eq!(tokens.len(), 1); diff --git a/third_party/rust/neqo-transport/src/lib.rs b/third_party/rust/neqo-transport/src/lib.rs index 9358af93fa36..b8a94e0226e4 100644 --- a/third_party/rust/neqo-transport/src/lib.rs +++ b/third_party/rust/neqo-transport/src/lib.rs @@ -48,6 +48,7 @@ pub use self::connection::{ }; pub use self::events::{ConnectionEvent, ConnectionEvents}; pub use self::frame::CloseError; +pub use self::quic_datagrams::DatagramTracking; pub use self::stats::Stats; pub use self::stream_id::{StreamId, StreamType}; pub use self::version::Version; diff --git a/third_party/rust/neqo-transport/src/path.rs b/third_party/rust/neqo-transport/src/path.rs index a24b19ae040f..3a25a1bea9ae 100644 --- a/third_party/rust/neqo-transport/src/path.rs +++ b/third_party/rust/neqo-transport/src/path.rs @@ -767,7 +767,7 @@ impl Path { // Send PATH_RESPONSE. let resp_sent = if let Some(challenge) = self.challenge.take() { - qtrace!([self], "Responding to path challenge {}", hex(&challenge)); + qtrace!([self], "Responding to path challenge {}", hex(challenge)); builder.encode_varint(FRAME_TYPE_PATH_RESPONSE); builder.encode(&challenge[..]); if builder.len() > builder.limit() { diff --git a/third_party/rust/neqo-transport/src/qlog.rs b/third_party/rust/neqo-transport/src/qlog.rs index d79128568727..ad86ec2b2e32 100644 --- a/third_party/rust/neqo-transport/src/qlog.rs +++ b/third_party/rust/neqo-transport/src/qlog.rs @@ -338,7 +338,7 @@ fn frame_to_qlogframe(frame: &Frame) -> QuicFrame { Frame::Crypto { offset, data } => { QuicFrame::crypto(offset.to_string(), data.len().to_string()) } - Frame::NewToken { token } => QuicFrame::new_token(token.len().to_string(), hex(&token)), + Frame::NewToken { token } => QuicFrame::new_token(token.len().to_string(), hex(token)), Frame::Stream { fin, stream_id, @@ -397,7 +397,7 @@ fn frame_to_qlogframe(frame: &Frame) -> QuicFrame { sequence_number.to_string(), retire_prior.to_string(), connection_id.len() as u64, - hex(&connection_id), + hex(connection_id), hex(stateless_reset_token), ), Frame::RetireConnectionId { sequence_number } => { diff --git a/third_party/rust/neqo-transport/src/recovery.rs b/third_party/rust/neqo-transport/src/recovery.rs index f50aac3c8f26..9b68187dabd4 100644 --- a/third_party/rust/neqo-transport/src/recovery.rs +++ b/third_party/rust/neqo-transport/src/recovery.rs @@ -679,7 +679,7 @@ impl LossRecovery { }; let (acked_packets, any_ack_eliciting) = - space.remove_acked(acked_ranges, &mut *self.stats.borrow_mut()); + space.remove_acked(acked_ranges, &mut self.stats.borrow_mut()); if acked_packets.is_empty() { // No new information. return (Vec::new(), Vec::new()); @@ -887,7 +887,7 @@ impl LossRecovery { self.pto_state .as_mut() .unwrap() - .count_pto(&mut *self.stats.borrow_mut()); + .count_pto(&mut self.stats.borrow_mut()); qlog::metrics_updated( &mut self.qlog, diff --git a/third_party/rust/neqo-transport/src/recv_stream.rs b/third_party/rust/neqo-transport/src/recv_stream.rs index 86df8bb6842b..19e233f8caa0 100644 --- a/third_party/rust/neqo-transport/src/recv_stream.rs +++ b/third_party/rust/neqo-transport/src/recv_stream.rs @@ -1248,7 +1248,7 @@ mod tests { assert!(s.has_frames_to_write()); // consume it - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut token = Vec::new(); s.write_frame(&mut builder, &mut token, &mut FrameStats::default()); @@ -1361,7 +1361,7 @@ mod tests { s.read(&mut buf).unwrap(); assert!(session_fc.borrow().frame_needed()); // consume it - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut token = Vec::new(); session_fc .borrow_mut() @@ -1382,7 +1382,7 @@ mod tests { s.read(&mut buf).unwrap(); assert!(session_fc.borrow().frame_needed()); // consume it - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut token = Vec::new(); session_fc .borrow_mut() @@ -1630,7 +1630,7 @@ mod tests { assert!(s.fc().unwrap().frame_needed()); // Write the fc update frame - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut token = Vec::new(); let mut stats = FrameStats::default(); fc.borrow_mut() diff --git a/third_party/rust/neqo-transport/src/send_stream.rs b/third_party/rust/neqo-transport/src/send_stream.rs index 9c220331401b..f63fd6db5553 100644 --- a/third_party/rust/neqo-transport/src/send_stream.rs +++ b/third_party/rust/neqo-transport/src/send_stream.rs @@ -1586,7 +1586,7 @@ mod tests { ss.insert(StreamId::from(0), s); let mut tokens = Vec::new(); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); // Write a small frame: no fin. let written = builder.len(); @@ -1675,7 +1675,7 @@ mod tests { ss.insert(StreamId::from(0), s); let mut tokens = Vec::new(); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); ss.write_frames( TransmissionPriority::default(), &mut builder, @@ -1753,7 +1753,7 @@ mod tests { assert_eq!(s.next_bytes(false), Some((0, &b"ab"[..]))); // This doesn't report blocking yet. - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut tokens = Vec::new(); let mut stats = FrameStats::default(); s.write_blocked_frame( @@ -1806,7 +1806,7 @@ mod tests { assert_eq!(s.send_atomic(b"abc").unwrap(), 0); // Assert that STREAM_DATA_BLOCKED is sent. - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut tokens = Vec::new(); let mut stats = FrameStats::default(); s.write_blocked_frame( @@ -1893,7 +1893,7 @@ mod tests { s.mark_as_lost(len_u64, 0, true); // No frame should be sent here. - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut tokens = Vec::new(); let mut stats = FrameStats::default(); s.write_stream_frame( @@ -1954,7 +1954,7 @@ mod tests { s.close(); } - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let header_len = builder.len(); builder.set_limit(header_len + space); @@ -2055,7 +2055,7 @@ mod tests { s.send(data).unwrap(); s.close(); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let header_len = builder.len(); // Add 2 for the frame type and stream ID, then add the extra. builder.set_limit(header_len + data.len() + 2 + extra); diff --git a/third_party/rust/neqo-transport/src/stats.rs b/third_party/rust/neqo-transport/src/stats.rs index 1042e6e9fe4f..dd8f8d4db527 100644 --- a/third_party/rust/neqo-transport/src/stats.rs +++ b/third_party/rust/neqo-transport/src/stats.rs @@ -216,7 +216,7 @@ pub struct StatsCell { impl Deref for StatsCell { type Target = RefCell; fn deref(&self) -> &Self::Target { - &*self.stats + &self.stats } } diff --git a/third_party/rust/neqo-transport/src/tracking.rs b/third_party/rust/neqo-transport/src/tracking.rs index d50cc8968a96..ad928ac0b064 100644 --- a/third_party/rust/neqo-transport/src/tracking.rs +++ b/third_party/rust/neqo-transport/src/tracking.rs @@ -880,7 +880,7 @@ mod tests { } fn write_frame(rp: &mut RecvdPackets) { - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); let mut stats = FrameStats::default(); let mut tokens = Vec::new(); rp.write_frame(*NOW, &mut builder, &mut tokens, &mut stats); @@ -1013,7 +1013,7 @@ mod tests { #[test] fn drop_spaces() { let mut tracker = AckTracker::default(); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); tracker .get_mut(PacketNumberSpace::Initial) .unwrap() @@ -1072,7 +1072,7 @@ mod tests { .set_received(*NOW, 0, true); assert!(tracker.ack_time(*NOW - Duration::from_millis(1)).is_some()); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); builder.set_limit(10); let mut stats = FrameStats::default(); @@ -1102,7 +1102,7 @@ mod tests { .set_received(*NOW, 2, true); assert!(tracker.ack_time(*NOW - Duration::from_millis(1)).is_some()); - let mut builder = PacketBuilder::short(Encoder::new(), false, &[]); + let mut builder = PacketBuilder::short(Encoder::new(), false, []); builder.set_limit(32); let mut stats = FrameStats::default(); diff --git a/third_party/rust/neqo-transport/tests/sim/mod.rs b/third_party/rust/neqo-transport/tests/sim/mod.rs index edd4b1463766..f7646aac5646 100644 --- a/third_party/rust/neqo-transport/tests/sim/mod.rs +++ b/third_party/rust/neqo-transport/tests/sim/mod.rs @@ -205,7 +205,7 @@ impl Simulator { } if self.nodes.iter().all(|n| n.node.done()) { - let real_elapsed = Instant::now() - real_start; + let real_elapsed = real_start.elapsed(); println!("{}: real elapsed time: {:?}", self.name, real_elapsed); let elapsed = now - start; println!("{}: simulated elapsed time: {:?}", self.name, elapsed);