Bug 1743378 - Update to neqo version 0.5.5 r=necko-reviewers,kershaw

Differential Revision: https://phabricator.services.mozilla.com/D132562
This commit is contained in:
Dragana Damjanovic 2021-12-02 08:23:20 +00:00
Родитель 58551a6795
Коммит 6fe5130c63
72 изменённых файлов: 6711 добавлений и 2163 удалений

Просмотреть файл

@ -10,7 +10,7 @@ rev = "029ac0d54b237f27dc7d8d4e51bc0fb076e5e852"
[source."https://github.com/mozilla/neqo"]
git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"
tag = "v0.5.3"
tag = "v0.5.5"
[source."https://github.com/mozilla/mp4parse-rust"]
git = "https://github.com/mozilla/mp4parse-rust"

21
Cargo.lock сгенерированный
Просмотреть файл

@ -3243,8 +3243,8 @@ dependencies = [
[[package]]
name = "neqo-common"
version = "0.5.3"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.3#ad9439a0c90422745c326c2147edf0997f614aac"
version = "0.5.5"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.5#cf161a560a245acd19d631cdad00ca4ffa01e1b5"
dependencies = [
"chrono",
"env_logger",
@ -3256,8 +3256,8 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.5.3"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.3#ad9439a0c90422745c326c2147edf0997f614aac"
version = "0.5.5"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.5#cf161a560a245acd19d631cdad00ca4ffa01e1b5"
dependencies = [
"bindgen",
"log",
@ -3269,9 +3269,10 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.5.3"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.3#ad9439a0c90422745c326c2147edf0997f614aac"
version = "0.5.5"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.5#cf161a560a245acd19d631cdad00ca4ffa01e1b5"
dependencies = [
"lazy_static",
"log",
"neqo-common",
"neqo-crypto",
@ -3285,8 +3286,8 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.5.3"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.3#ad9439a0c90422745c326c2147edf0997f614aac"
version = "0.5.5"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.5#cf161a560a245acd19d631cdad00ca4ffa01e1b5"
dependencies = [
"lazy_static",
"log",
@ -3299,8 +3300,8 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.5.3"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.3#ad9439a0c90422745c326c2147edf0997f614aac"
version = "0.5.5"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.5#cf161a560a245acd19d631cdad00ca4ffa01e1b5"
dependencies = [
"indexmap",
"lazy_static",

Просмотреть файл

@ -8,10 +8,10 @@ edition = "2018"
name = "neqo_glue"
[dependencies]
neqo-http3 = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }
@ -25,7 +25,7 @@ static_prefs = { path = "../../../modules/libpref/init/static_prefs", optional =
winapi = {version = "0.3", features = ["ws2def"] }
[dependencies.neqo-crypto]
tag = "v0.5.3"
tag = "v0.5.5"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

Просмотреть файл

@ -5,17 +5,17 @@ authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
[dependencies]
neqo-transport = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.5.3", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.5.5", git = "https://github.com/mozilla/neqo" }
mio = "0.6.17"
mio-extras = "2.0.5"
log = "0.4.0"
base64 = "0.10"
[dependencies.neqo-crypto]
tag = "v0.5.3"
tag = "v0.5.5"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"23080873a43e8e60a60ef58bff3c8ce330cb6bd21a9714b34a129d74655f28da","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"ee422054b6f330d303a150223fd498dc2277c70663b0c3c0dcb7f0fc14fee7d8","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"45a608ce9f00e2666ce95422a278c6dc0ff4e229b114e7bcf0b4c0d9dc61ad56","src/incrdecoder.rs":"91dab6f99073b1a6c88ff2f2625315dadb0b00d7bb0704e13b186155fbf496e8","src/lib.rs":"e19efc395a902d1584e66cddf1c3beedbfd1a0487457ba6a18e60bcd84132be4","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"ca323c91d61810ebef2ebeb967836dda384a60a9fb492c2b8d1b235a98f2e4bf","src/timer.rs":"e63af7e7df968bf702583f263cfb63e6dca4e599bacffa2de0a6383d85333636","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
{"files":{"Cargo.toml":"e669215a2bf5fa9ea28d92c2e61323a5cecb0ebc4107b7dd78b049de2a9214df","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"ee422054b6f330d303a150223fd498dc2277c70663b0c3c0dcb7f0fc14fee7d8","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"45a608ce9f00e2666ce95422a278c6dc0ff4e229b114e7bcf0b4c0d9dc61ad56","src/incrdecoder.rs":"91dab6f99073b1a6c88ff2f2625315dadb0b00d7bb0704e13b186155fbf496e8","src/lib.rs":"0a3679ab0bc67817097701010881e1c2f48ad1ab0700f12babc46cc59c5c788b","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"ca323c91d61810ebef2ebeb967836dda384a60a9fb492c2b8d1b235a98f2e4bf","src/timer.rs":"e63af7e7df968bf702583f263cfb63e6dca4e599bacffa2de0a6383d85333636","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}

2
third_party/rust/neqo-common/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-common"
version = "0.5.3"
version = "0.5.5"
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

6
third_party/rust/neqo-common/src/lib.rs поставляемый
Просмотреть файл

@ -98,3 +98,9 @@ impl ::std::fmt::Display for Role {
write!(f, "{:?}", self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageType {
Request,
Response,
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"366920694e669ddce1b78bcc73f64d9081f988f635a250ef6d24eb60bf91721f","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"d136f82a333b0ee1499e7858fdfc3d630f7ff37501a3c51028a4eeb7e2f136b4","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":"4bc26650fa85150c1a377f030e681576f92005a14f14fd8818e7ceb95c2c2a1a","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"4e60d5a2ee6dedfd08602fa36318239e731244825df2cb801ca1d88f5f2a41c1","src/agent.rs":"f83ec6be81a39f52383bec7a1fec2069055088788a989ecfd7fd155f0d5cb788","src/agentio.rs":"85a1f5295e98fcec0e884fb11e21cbc4c64de0f2ad5b6d78464ed9ac064fb495","src/auth.rs":"e821dac1511691151a6e64b7c7130a07d941dffad4529b2631f20ddd07d3f20c","src/cert.rs":"94450b248eed218b9227861ed81e557a543c0c88868fe1a434dc9c9f0f9651ae","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"1b6ee298855d34310a0d65367b21fdc38678a9c37fc7e1d9579c3c8dfd753377","src/err.rs":"d4dbe63e2faba3a1f08dca015549c32550cb18907592abc3831e05e330f0a93b","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"3ff432cc9d40e1dc56e9f983b54b593647c4063a5ae0f16de0a64d033ac9bd94","src/hp.rs":"46a2023c421d89fda8d09b356b648272857fd20ee5cf5829143ac88402b32e4b","src/lib.rs":"4a4aacab783b2e21d9f2f33891bc75c5a8018894c3cdf828848ccb59bf5b2d41","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"ae054861719fdead8227220dd5a28b92882756683a436676470b672ee26b9a4e","src/prio.rs":"4224a65f25d7de9bf7d6cb18b15597a39650b3c4fcf7d184a4e4bd7f65cebccd","src/replay.rs":"c9bc0261fe1ae22e7212774c315a2669784e57762ca975a15250d4a33dbf3ea3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"48790a330994d892742048000bd12460b7eee2c3daaa444481b8527406d0a4c7","src/selfencrypt.rs":"4a9af42ccefbc77c65baedf00ef389de4fa7ed855d7ab3b60542b5931050667d","src/ssl.rs":"32e934e6dc5df4e4b4cbe96bae53921cf09a684959cb5ad3469cd65965f3164c","src/time.rs":"ddecb9f6cb6b3367852943d27fc89fd36d3c0ca0c9b5c9797494b74de2d8b5c7","tests/aead.rs":"a0fe826aa3bfcce22dbe1b06b74823cb2334331ffe6ce6152952613e9e1ccae5","tests/agent.rs":"edda258896324f0a950427fd625594bd31d772fe968a29097d6dbd76523c39c4","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"6ea3e5b3bc889d201b55f959b658a848c0ada54c956bda087b2ac8897a24a786","tests/hkdf.rs":"47830c1ea58a02d100522bdde6fabc02bb447ccb85affa0cdc44bc25da1be32a","tests/hp.rs":"92e062538c01fa7a474225714ed238d846ceb8c8feb9d79eb05be6111b00fb1e","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null}
{"files":{"Cargo.toml":"bc1c5e7a9a21903b5eb76c81420b9700828e0798544f2727e0d3a5be407fc06f","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"d136f82a333b0ee1499e7858fdfc3d630f7ff37501a3c51028a4eeb7e2f136b4","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":"4bc26650fa85150c1a377f030e681576f92005a14f14fd8818e7ceb95c2c2a1a","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"4e60d5a2ee6dedfd08602fa36318239e731244825df2cb801ca1d88f5f2a41c1","src/agent.rs":"db620f07e2c0f441ce0a30a249a18ab699affb43d8209c63c4f1e5eae9f9f688","src/agentio.rs":"85a1f5295e98fcec0e884fb11e21cbc4c64de0f2ad5b6d78464ed9ac064fb495","src/auth.rs":"e821dac1511691151a6e64b7c7130a07d941dffad4529b2631f20ddd07d3f20c","src/cert.rs":"04d7328ab59a5268f2f48b3f880192bf28d42c09c362ef5906ee66e087c754d1","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"1b6ee298855d34310a0d65367b21fdc38678a9c37fc7e1d9579c3c8dfd753377","src/err.rs":"d4dbe63e2faba3a1f08dca015549c32550cb18907592abc3831e05e330f0a93b","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"3ff432cc9d40e1dc56e9f983b54b593647c4063a5ae0f16de0a64d033ac9bd94","src/hp.rs":"46a2023c421d89fda8d09b356b648272857fd20ee5cf5829143ac88402b32e4b","src/lib.rs":"4a4aacab783b2e21d9f2f33891bc75c5a8018894c3cdf828848ccb59bf5b2d41","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"ae054861719fdead8227220dd5a28b92882756683a436676470b672ee26b9a4e","src/prio.rs":"4224a65f25d7de9bf7d6cb18b15597a39650b3c4fcf7d184a4e4bd7f65cebccd","src/replay.rs":"c9bc0261fe1ae22e7212774c315a2669784e57762ca975a15250d4a33dbf3ea3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"48790a330994d892742048000bd12460b7eee2c3daaa444481b8527406d0a4c7","src/selfencrypt.rs":"4a9af42ccefbc77c65baedf00ef389de4fa7ed855d7ab3b60542b5931050667d","src/ssl.rs":"32e934e6dc5df4e4b4cbe96bae53921cf09a684959cb5ad3469cd65965f3164c","src/time.rs":"ddecb9f6cb6b3367852943d27fc89fd36d3c0ca0c9b5c9797494b74de2d8b5c7","tests/aead.rs":"a0fe826aa3bfcce22dbe1b06b74823cb2334331ffe6ce6152952613e9e1ccae5","tests/agent.rs":"edda258896324f0a950427fd625594bd31d772fe968a29097d6dbd76523c39c4","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"6ea3e5b3bc889d201b55f959b658a848c0ada54c956bda087b2ac8897a24a786","tests/hkdf.rs":"47830c1ea58a02d100522bdde6fabc02bb447ccb85affa0cdc44bc25da1be32a","tests/hp.rs":"92e062538c01fa7a474225714ed238d846ceb8c8feb9d79eb05be6111b00fb1e","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null}

2
third_party/rust/neqo-crypto/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-crypto"
version = "0.5.3"
version = "0.5.5"
authors = ["Martin Thomson <mt@lowentropy.net>"]
edition = "2018"
build = "build.rs"

1
third_party/rust/neqo-crypto/src/agent.rs поставляемый
Просмотреть файл

@ -710,6 +710,7 @@ impl SecretAgent {
Ok(*Pin::into_inner(records))
}
#[allow(unknown_lints, clippy::branches_sharing_code)]
pub fn close(&mut self) {
// It should be safe to close multiple times.
if self.fd.is_null() {

12
third_party/rust/neqo-crypto/src/cert.rs поставляемый
Просмотреть файл

@ -65,10 +65,14 @@ fn signed_cert_timestamp(fd: *mut PRFileDesc) -> Option<Vec<u8>> {
let sct_nss = unsafe { SSL_PeerSignedCertTimestamps(fd) };
match NonNull::new(sct_nss as *mut SECItem) {
Some(sct_ptr) => {
let sct_slice = unsafe {
slice::from_raw_parts(sct_ptr.as_ref().data, sct_ptr.as_ref().len as usize)
};
Some(sct_slice.to_owned())
if unsafe { sct_ptr.as_ref().len == 0 || sct_ptr.as_ref().data.is_null() } {
Some(Vec::new())
} else {
let sct_slice = unsafe {
slice::from_raw_parts(sct_ptr.as_ref().data, sct_ptr.as_ref().len as usize)
};
Some(sct_slice.to_owned())
}
}
None => None,
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"af86a7fb67c995de07b728ec49076a265dd5d49ad34d475b1e965679d869e28c","src/client_events.rs":"2ea0ff9757e6772a18e8f85c007ba443baf83ffe8ce890f5325b1528df2d7e37","src/connection.rs":"1f32ef2e87a190c1dd040d7050673d6f1c9a82613864e946a2cbd38bd65279f8","src/connection_client.rs":"d2f8444e198b9c22cea7cc17bf57068d882ff9a16ab5bfd35f5a8af89dff306d","src/connection_server.rs":"5038c9d3a6d65fdde8a1550e9e7bd0ed465a4896e04dfa2857fa26a9b760f215","src/control_stream_local.rs":"cfb97fb2ee55edb7d3b6fde2c68f2386d32d797b1c43405af226bad740ca4fc1","src/control_stream_remote.rs":"e48df6d739971450b6aac1f7a0725f61828dc0d13c1ad5c31ac7ff331d1afedd","src/hframe.rs":"60c93883b345aec9403b41a6a651b22579d61eff9cb4e650ed92237e2d75b5b3","src/lib.rs":"297aea64fed5561e89a2e27f6f2cd5b495a157ae2385dffc22f91d9a1a09c52b","src/priority.rs":"9384efb1353c05408aa40f34eaa99ee31e995eab04011586f1748b34b370a215","src/push_controller.rs":"35c5688e053157830c55b9133f6190349826143590f13a6b55768a79320313a7","src/push_stream.rs":"281b25b7044ba876700ca713b873ff83aac688e952c21881a715390452f64005","src/qlog.rs":"7444919d5955557ade447f9457a536d9294f5bbb8a09f8fac8bbaf24c8bbad8b","src/qpack_decoder_receiver.rs":"c8e1b84b52c097a798d6fb03c8321f676f31d68bc4000041b5dcb5797f8d66ac","src/qpack_encoder_receiver.rs":"11f6bc3e9170e952d92b583659c48764c375fa66cfa97fb115298a6021e84cfb","src/recv_message.rs":"ed02ebde63a1b0fb6f5522f1be50dfa417decda1d1320149c1b437dfbeb5a06f","src/request_target.rs":"9182b641f7a7b55272e0e2e872d24a35b1207f35399221b08b899857c3e873ab","src/send_message.rs":"f3fc46e03236ddce83841734ef97f2c4b5f25b5939186ff3e8ca40d6b467e341","src/server.rs":"6b9d0254df18cc04699899f8ff5a096fe153588a56fbcc214fc5ce9eb8f6b9eb","src/server_connection_events.rs":"c53853d36f872ef624fbfcc67e4a54d364159a2c80ca273f4f87ffdf38ec04ad","src/server_events.rs":"31585865c111eb8ce031b1664cc32e221aee312dc70b96a93a32924a142e0a0e","src/settings.rs":"467bd6991ec30e483195855f997f0bea3671a15b1a5b82e271f62ae424e0b2c3","src/stream_type_reader.rs":"94014849b86fa5700d661819370f4c010ba5235a58343c2895753218c5cab999","tests/httpconn.rs":"e8e3d090aa9e28040b0f8cde39d1f3e4b7aaa56db3b741fc75fe416450047787","tests/priority.rs":"b14a7b7ee25e7b5085756f7eeac592d5641482546ffd3ca04445ffdcd79d3378"},"package":null}
{"files":{"Cargo.toml":"f37b88a9e0ab0de81c27f5e3013b733beed9f5a2af83146275e2122a55a3de31","src/buffered_send_stream.rs":"0e4ad4914451943e49c88565661d88475ab2bbd8756e200e2a19312bafd64847","src/client_events.rs":"3dab2de2ec5fac43ff30470e0e8167fdbfede4bc467c0fcd027d809692b7465b","src/conn_params.rs":"00e3f42636f482f91cd6b86d7bebaa85a9f0407143503767fffb66a3cdfbbe43","src/connection.rs":"8d9abfc187866310244758238430efbe4c68c3db12e6edd9b746963143744766","src/connection_client.rs":"30c6d5fa8f982237a37d19097c94a664a65174fb567210824ee6154cd3fad577","src/connection_server.rs":"1e9bca9a0a8ac4532015032b1444b23f67007b8c6b3f138900f0b142cf5625d1","src/control_stream_local.rs":"49bc3b8d2da81477fa5914d80e32657e215e84ba2c40411eb18ae170ccddecd0","src/control_stream_remote.rs":"b6c4b96e0b35d54a5fee9297945c2dc6458729af2566323b13e44a621b214d72","src/features/extended_connect/mod.rs":"95e8468e62e2e7680989b6d85397775d3a99ce68390dc68708c3fb3450932e03","src/features/extended_connect/session.rs":"5f1035082891554194c89d80338ccd0991db0085bdf8be358a2c3a7ac2b52dbc","src/features/extended_connect/webtransport.rs":"721497ea16aaf55a3be4b685afe23fdbcb2c19603042898f12d93ea4e5d8aac7","src/features/mod.rs":"a981ebbd03e7bb7ea2313e883452e44f052c48f28edb7fd53a0825911b490230","src/headers_checks.rs":"4d8ce4ba54a989ecc257a26d47111ab4583cf78a3ae6c60ad106f3ad3e77ac8f","src/hframe.rs":"79311512aafe7ac5cbda068352bbce573ee99205baa06fc75db95cc3dbbf0780","src/lib.rs":"ed19bb708b711d0b69430a632d5524e93a115239d63de094ae78611e0c2af026","src/priority.rs":"89d25666fb3b35e16c58055e51d25ff746fc420820db9f30fdecfd1ed70ac020","src/push_controller.rs":"7db0c4c1e065372d3adba90662ff20c4e36adade25f64d2168616339cc5bf47d","src/qlog.rs":"44b6cdbb1d9d6ca47b793e9dbe531b8fdbd40147375f7e4c89aeab536c5d286b","src/qpack_decoder_receiver.rs":"75008d8ea5d538ee34aca4df72e58489417604ccafb61b064280782d6754dd0d","src/qpack_encoder_receiver.rs":"f95cc7d49e4d442b93d522f14ddfc581629664d84d6e13d03a520e855bbe442d","src/recv_message.rs":"3d1556087aecae432589ce55459430a19c1d35c4c819ff4b2e2869a12e6a7b3d","src/request_target.rs":"9182b641f7a7b55272e0e2e872d24a35b1207f35399221b08b899857c3e873ab","src/send_message.rs":"7a676b0f6f34f7c52e98f346d7009345fec84e7db03d11dbe2a50ae95d433369","src/server.rs":"0b3775863339f8ea9d363b83f2c667bda4b62de177bb2e93caef3830ba7c46a8","src/server_connection_events.rs":"5f3eadceb0c555ab13f68ec49af0eaa7a1ebf1fdd14e1132d77583ecd76cabbb","src/server_events.rs":"42c79731c5168df35ebd3cef448d9e38e64770b31363b2b4965679582db9f61e","src/settings.rs":"8f7e3ddd807c3d5667dad93f5b902b0e00a3bcf85e41404e1e0e5dfd2c3d5dd6","src/stream_type_reader.rs":"62fb15a5b64b9777ddfcb16c3d43031797336dca39dd70340776022431b79d77","tests/httpconn.rs":"33538bb3597e23787880f85df1a13e2942549cffdbbdbd8a8822a64f716c7620","tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","tests/priority.rs":"e3258878d4b692c5d80612c1d275972a99808168ccc33fdd966822a0c8776bb9","tests/send_message.rs":"673ae1d0bf2dce46c21ee8353f45f189d2cb64a2f6e137ae38da6b2262ad066e","tests/webtransport/mod.rs":"ef8f83789925502b5121fa6285bfcf6c09e2299a9360bf0ed2c8329ea0c25fc4","tests/webtransport/negotiation.rs":"866cec03df0643fa0f28a160a97112a4ab3c1ca337d8e00e81eb7eb42f67d41b","tests/webtransport/sessions.rs":"af6a336cac13bc4be1be329e9f18d48dd23c99975d20f719e3e59be6214aa9f4","tests/webtransport/streams.rs":"560b86ea59c92159b16099c26b6f042b5e8c0fc3f21983a00da677987670c4f9"},"package":null}

3
third_party/rust/neqo-http3/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-http3"
version = "0.5.3"
version = "0.5.5"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
license = "MIT/Apache-2.0"
@ -15,6 +15,7 @@ smallvec = "1.0.0"
qlog = "0.4.0"
sfv = "0.9.1"
url = "2.0"
lazy_static = "1.3.0"
[dev-dependencies]
test-fixture = { path = "../test-fixture" }

113
third_party/rust/neqo-http3/src/buffered_send_stream.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,113 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::Res;
use neqo_common::qtrace;
use neqo_transport::{Connection, StreamId};
#[derive(Debug, PartialEq)]
pub enum BufferedStream {
Uninitialized,
Initialized { stream_id: StreamId, buf: Vec<u8> },
}
impl Default for BufferedStream {
fn default() -> Self {
Self::Uninitialized
}
}
impl ::std::fmt::Display for BufferedStream {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "BufferedStream {:?}", Option::<StreamId>::from(self))
}
}
impl BufferedStream {
#[must_use]
pub fn new(stream_id: StreamId) -> Self {
Self::Initialized {
stream_id,
buf: Vec::new(),
}
}
/// # Panics
/// If the `BufferedStream` is initialized more than one it will panic.
pub fn init(&mut self, stream_id: StreamId) {
debug_assert!(&Self::Uninitialized == self);
*self = Self::Initialized {
stream_id,
buf: Vec::new(),
};
}
/// # Panics
/// This functon cannot be called before the `BufferedStream` is initialized.
pub fn buffer(&mut self, to_buf: &[u8]) {
if let Self::Initialized { buf, .. } = self {
buf.extend_from_slice(to_buf);
} else {
debug_assert!(false, "Do not buffer date before the stream is initialized");
}
}
/// # Errors
/// Returns `neqo_transport` errors.
pub fn send_buffer(&mut self, conn: &mut Connection) -> Res<usize> {
let label = ::neqo_common::log_subject!(::log::Level::Debug, self);
let mut sent = 0;
if let Self::Initialized { stream_id, buf } = self {
if !buf.is_empty() {
qtrace!([label], "sending data.");
sent = conn.stream_send(*stream_id, &buf[..])?;
if sent == buf.len() {
buf.clear();
} else {
let b = buf.split_off(sent);
*buf = b;
}
}
}
Ok(sent)
}
/// # Errors
/// Returns `neqo_transport` errors.
pub fn send_atomic(&mut self, conn: &mut Connection, to_send: &[u8]) -> Res<bool> {
// First try to send anything that is in the buffer.
self.send_buffer(conn)?;
if let Self::Initialized { stream_id, buf } = self {
if buf.is_empty() {
let res = conn.stream_send_atomic(*stream_id, to_send)?;
Ok(res)
} else {
Ok(false)
}
} else {
Ok(false)
}
}
#[must_use]
pub fn has_buffered_data(&self) -> bool {
if let Self::Initialized { buf, .. } = self {
!buf.is_empty()
} else {
false
}
}
}
impl From<&BufferedStream> for Option<StreamId> {
fn from(stream: &BufferedStream) -> Option<StreamId> {
if let BufferedStream::Initialized { stream_id, .. } = stream {
Some(*stream_id)
} else {
None
}
}
}

Просмотреть файл

@ -7,43 +7,61 @@
#![allow(clippy::module_name_repetitions)]
use crate::connection::Http3State;
use crate::send_message::SendMessageEvents;
use crate::Header;
use crate::RecvMessageEvents;
use neqo_common::event::Provider as EventProvider;
use crate::settings::HSettingType;
use crate::{
features::extended_connect::{ExtendedConnectEvents, ExtendedConnectType},
CloseType, Http3StreamInfo, HttpRecvStreamEvents, RecvStreamEvents, SendStreamEvents,
};
use neqo_common::{event::Provider as EventProvider, Header};
use neqo_crypto::ResumptionToken;
use neqo_transport::{AppError, StreamType};
use neqo_transport::{AppError, StreamId, StreamType};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum WebTransportEvent {
Negotiated(bool),
Session(StreamId),
SessionClosed {
stream_id: StreamId,
error: Option<AppError>,
},
NewStream {
stream_id: StreamId,
session_id: StreamId,
},
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Http3ClientEvent {
/// Response headers are received.
HeaderReady {
stream_id: u64,
stream_id: StreamId,
headers: Vec<Header>,
interim: bool,
fin: bool,
},
/// A stream can accept new data.
DataWritable { stream_id: u64 },
DataWritable { stream_id: StreamId },
/// New bytes available for reading.
DataReadable { stream_id: u64 },
DataReadable { stream_id: StreamId },
/// Peer reset the stream or there was an parsing error.
Reset {
stream_id: u64,
stream_id: StreamId,
error: AppError,
local: bool,
},
/// Peer has sent a STOP_SENDING.
StopSending { stream_id: u64, error: AppError },
StopSending {
stream_id: StreamId,
error: AppError,
},
/// A new push promise.
PushPromise {
push_id: u64,
request_stream_id: u64,
request_stream_id: StreamId,
headers: Vec<Header>,
},
/// A push response headers are ready.
@ -76,6 +94,8 @@ pub enum Http3ClientEvent {
GoawayReceived,
/// Connection state change.
StateChange(Http3State),
/// WebTransport events
WebTransport(WebTransportEvent),
}
#[derive(Debug, Default, Clone)]
@ -83,31 +103,33 @@ pub struct Http3ClientEvents {
events: Rc<RefCell<VecDeque<Http3ClientEvent>>>,
}
impl RecvMessageEvents for Http3ClientEvents {
/// Add a new `HeaderReady` event.
fn header_ready(&self, stream_id: u64, headers: Vec<Header>, interim: bool, fin: bool) {
self.insert(Http3ClientEvent::HeaderReady {
stream_id,
headers,
interim,
fin,
});
}
impl RecvStreamEvents for Http3ClientEvents {
/// Add a new `DataReadable` event
fn data_readable(&self, stream_id: u64) {
self.insert(Http3ClientEvent::DataReadable { stream_id });
fn data_readable(&self, stream_info: Http3StreamInfo) {
self.insert(Http3ClientEvent::DataReadable {
stream_id: stream_info.stream_id(),
});
}
/// Add a new `Reset` event.
fn reset(&self, stream_id: u64, error: AppError, local: bool) {
self.remove(|evt| {
matches!(evt,
Http3ClientEvent::HeaderReady { stream_id: x, .. }
| Http3ClientEvent::DataReadable { stream_id: x }
| Http3ClientEvent::PushPromise { request_stream_id: x, .. }
| Http3ClientEvent::Reset { stream_id: x, .. } if *x == stream_id)
});
fn recv_closed(&self, stream_info: Http3StreamInfo, close_type: CloseType) {
let stream_id = stream_info.stream_id();
let (local, error) = match close_type {
CloseType::ResetApp(_) => {
self.remove_recv_stream_events(stream_id);
return;
}
CloseType::Done => return,
CloseType::ResetRemote(e) => {
self.remove_recv_stream_events(stream_id);
(false, e)
}
CloseType::LocalError(e) => {
self.remove_recv_stream_events(stream_id);
(true, e)
}
};
self.insert(Http3ClientEvent::Reset {
stream_id,
error,
@ -116,30 +138,79 @@ impl RecvMessageEvents for Http3ClientEvents {
}
}
impl SendMessageEvents for Http3ClientEvents {
/// Add a new `DataWritable` event.
fn data_writable(&self, stream_id: u64) {
self.insert(Http3ClientEvent::DataWritable { stream_id });
impl HttpRecvStreamEvents for Http3ClientEvents {
/// Add a new `HeaderReady` event.
fn header_ready(
&self,
stream_info: Http3StreamInfo,
headers: Vec<Header>,
interim: bool,
fin: bool,
) {
self.insert(Http3ClientEvent::HeaderReady {
stream_id: stream_info.stream_id(),
headers,
interim,
fin,
});
}
}
fn remove_send_side_event(&self, stream_id: u64) {
self.remove(|evt| {
matches!(evt,
Http3ClientEvent::DataWritable { stream_id: x }
| Http3ClientEvent::StopSending { stream_id: x, .. } if *x == stream_id)
impl SendStreamEvents for Http3ClientEvents {
/// Add a new `DataWritable` event.
fn data_writable(&self, stream_info: Http3StreamInfo) {
self.insert(Http3ClientEvent::DataWritable {
stream_id: stream_info.stream_id(),
});
}
/// Add a new `StopSending` event
fn stop_sending(&self, stream_id: u64, error: AppError) {
// The stream has received a STOP_SENDING frame, we should remove any DataWritable event.
self.remove_send_side_event(stream_id);
self.insert(Http3ClientEvent::StopSending { stream_id, error });
fn send_closed(&self, stream_info: Http3StreamInfo, close_type: CloseType) {
let stream_id = stream_info.stream_id();
self.remove_send_stream_events(stream_id);
if let CloseType::ResetRemote(error) = close_type {
self.insert(Http3ClientEvent::StopSending { stream_id, error });
}
}
}
impl ExtendedConnectEvents for Http3ClientEvents {
fn session_start(&self, connect_type: ExtendedConnectType, stream_id: StreamId) {
if connect_type == ExtendedConnectType::WebTransport {
self.insert(Http3ClientEvent::WebTransport(WebTransportEvent::Session(
stream_id,
)));
} else {
unreachable!("There is only ExtendedConnectType::WebTransport.");
}
}
fn session_end(
&self,
connect_type: ExtendedConnectType,
stream_id: StreamId,
error: Option<AppError>,
) {
if connect_type == ExtendedConnectType::WebTransport {
self.insert(Http3ClientEvent::WebTransport(
WebTransportEvent::SessionClosed { stream_id, error },
));
} else {
unreachable!("There are no other types.");
}
}
fn extended_connect_new_stream(&self, stream_info: Http3StreamInfo) {
self.insert(Http3ClientEvent::WebTransport(
WebTransportEvent::NewStream {
stream_id: stream_info.stream_id(),
session_id: stream_info.session_id().unwrap(),
},
));
}
}
impl Http3ClientEvents {
pub fn push_promise(&self, push_id: u64, request_stream_id: u64, headers: Vec<Header>) {
pub fn push_promise(&self, push_id: u64, request_stream_id: StreamId, headers: Vec<Header>) {
self.insert(Http3ClientEvent::PushPromise {
push_id,
request_stream_id,
@ -217,14 +288,20 @@ impl Http3ClientEvents {
}
/// Remove all events for a stream
pub(crate) fn remove_events_for_stream_id(&self, stream_id: u64) {
fn remove_recv_stream_events(&self, stream_id: StreamId) {
self.remove(|evt| {
matches!(evt,
Http3ClientEvent::HeaderReady { stream_id: x, .. }
| Http3ClientEvent::DataWritable { stream_id: x }
| Http3ClientEvent::DataReadable { stream_id: x }
| Http3ClientEvent::PushPromise { request_stream_id: x, .. }
| Http3ClientEvent::Reset { stream_id: x, .. }
| Http3ClientEvent::Reset { stream_id: x, .. } if *x == stream_id)
});
}
fn remove_send_stream_events(&self, stream_id: StreamId) {
self.remove(|evt| {
matches!(evt,
Http3ClientEvent::DataWritable { stream_id: x }
| Http3ClientEvent::StopSending { stream_id: x, .. } if *x == stream_id)
});
}
@ -247,6 +324,14 @@ impl Http3ClientEvents {
| Http3ClientEvent::PushCanceled{ push_id: x, .. } if *x == push_id)
});
}
pub fn negotiation_done(&self, feature_type: HSettingType, negotiated: bool) {
if feature_type == HSettingType::EnableWebTransport {
self.insert(Http3ClientEvent::WebTransport(
WebTransportEvent::Negotiated(negotiated),
));
}
}
}
impl EventProvider for Http3ClientEvents {

119
third_party/rust/neqo-http3/src/conn_params.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,119 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use neqo_qpack::QpackSettings;
use neqo_transport::ConnectionParameters;
use std::cmp::min;
const QPACK_MAX_TABLE_SIZE_DEFAULT: u64 = 65536;
const QPACK_TABLE_SIZE_LIMIT: u64 = (1 << 30) - 1;
const QPACK_MAX_BLOCKED_STREAMS_DEFAULT: u16 = 20;
const MAX_PUSH_STREAM_DEFAULT: u64 = 0;
const WEBTRANSPORT_DEFAULT: bool = false;
#[derive(Debug, Clone, Copy)]
pub struct Http3Parameters {
conn_params: ConnectionParameters,
qpack_settings: QpackSettings,
max_concurrent_push_streams: u64,
webtransport: bool,
}
impl Default for Http3Parameters {
fn default() -> Self {
Self {
conn_params: ConnectionParameters::default(),
qpack_settings: QpackSettings {
max_table_size_encoder: QPACK_MAX_TABLE_SIZE_DEFAULT,
max_table_size_decoder: QPACK_MAX_TABLE_SIZE_DEFAULT,
max_blocked_streams: QPACK_MAX_BLOCKED_STREAMS_DEFAULT,
},
max_concurrent_push_streams: MAX_PUSH_STREAM_DEFAULT,
webtransport: WEBTRANSPORT_DEFAULT,
}
}
}
impl Http3Parameters {
#[must_use]
pub fn get_connection_parameters(&self) -> &ConnectionParameters {
&self.conn_params
}
#[must_use]
pub fn connection_parameters(mut self, conn_params: ConnectionParameters) -> Self {
self.conn_params = conn_params;
self
}
/// # Panics
/// The table size must be smaller than 1 << 30 by the spec.
#[must_use]
pub fn max_table_size_encoder(mut self, mut max_table: u64) -> Self {
assert!(max_table <= QPACK_TABLE_SIZE_LIMIT);
max_table = min(max_table, QPACK_TABLE_SIZE_LIMIT);
self.qpack_settings.max_table_size_encoder = max_table;
self
}
#[must_use]
pub fn get_max_table_size_encoder(&self) -> u64 {
self.qpack_settings.max_table_size_encoder
}
/// # Panics
/// The table size must be smaller than 1 << 30 by the spec.
#[must_use]
pub fn max_table_size_decoder(mut self, mut max_table: u64) -> Self {
assert!(max_table <= QPACK_TABLE_SIZE_LIMIT);
max_table = min(max_table, QPACK_TABLE_SIZE_LIMIT);
self.qpack_settings.max_table_size_decoder = max_table;
self
}
#[must_use]
pub fn get_max_table_size_decoder(&self) -> u64 {
self.qpack_settings.max_table_size_decoder
}
#[must_use]
pub fn max_blocked_streams(mut self, max_blocked: u16) -> Self {
self.qpack_settings.max_blocked_streams = max_blocked;
self
}
#[must_use]
pub fn get_max_blocked_streams(&self) -> u16 {
self.qpack_settings.max_blocked_streams
}
#[must_use]
pub fn get_qpack_settings(&self) -> &QpackSettings {
&self.qpack_settings
}
#[must_use]
pub fn max_concurrent_push_streams(mut self, max_push_streams: u64) -> Self {
self.max_concurrent_push_streams = max_push_streams;
self
}
#[must_use]
pub fn get_max_concurrent_push_streams(&self) -> u64 {
self.max_concurrent_push_streams
}
#[must_use]
pub fn webtransport(mut self, webtransport: bool) -> Self {
self.webtransport = webtransport;
self
}
#[must_use]
pub fn get_webtransport(&self) -> bool {
self.webtransport
}
}

864
third_party/rust/neqo-http3/src/connection.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -6,12 +6,14 @@
use crate::connection::{Http3Connection, Http3State};
use crate::hframe::HFrame;
use crate::recv_message::{MessageType, RecvMessage};
use crate::recv_message::{RecvMessage, RecvMessageInfo};
use crate::send_message::SendMessage;
use crate::server_connection_events::{Http3ServerConnEvent, Http3ServerConnEvents};
use crate::{Error, Header, Priority, PriorityHandler, ReceiveOutput, Res};
use neqo_common::{event::Provider, qdebug, qinfo, qtrace, Role};
use neqo_qpack::QpackSettings;
use crate::{
Error, Http3Parameters, Http3StreamType, NewStreamType, Priority, PriorityHandler,
ReceiveOutput, Res,
};
use neqo_common::{event::Provider, qdebug, qinfo, qtrace, Header, MessageType, Role};
use neqo_transport::{AppError, Connection, ConnectionEvent, StreamId, StreamType};
use std::rc::Rc;
use std::time::Instant;
@ -30,44 +32,136 @@ impl ::std::fmt::Display for Http3ServerHandler {
}
impl Http3ServerHandler {
pub(crate) fn new(qpack_settings: QpackSettings) -> Self {
pub(crate) fn new(http3_parameters: Http3Parameters) -> Self {
Self {
base_handler: Http3Connection::new(qpack_settings),
base_handler: Http3Connection::new(http3_parameters, Role::Server),
events: Http3ServerConnEvents::default(),
needs_processing: false,
}
}
/// Supply a response for a request.
pub(crate) fn set_response(
/// # Errors
/// `InvalidStreamId` if the stream does not exist,
/// `AlreadyClosed` if the stream has already been closed.
/// `TransportStreamDoesNotExist` if the transport stream does not exist (this may happen if `process_output`
/// has not been called when needed, and HTTP3 layer has not picked up the info that the stream has been closed.)
/// `InvalidInput` if an empty buffer has been supplied.
pub(crate) fn send_data(
&mut self,
stream_id: u64,
headers: &[Header],
stream_id: StreamId,
data: &[u8],
conn: &mut Connection,
) -> Res<usize> {
self.base_handler.stream_has_pending_data(stream_id);
self.needs_processing = true;
self.base_handler
.send_streams
.get_mut(&stream_id)
.ok_or(Error::InvalidStreamId)?
.send_data(conn, data)
}
/// Supply response heeaders for a request.
pub(crate) fn send_headers(
&mut self,
stream_id: StreamId,
headers: &[Header],
conn: &mut Connection,
) -> Res<()> {
self.base_handler
.send_streams
.get_mut(&stream_id)
.ok_or(Error::InvalidStreamId)?
.set_message(headers, Some(data))?;
self.base_handler
.insert_streams_have_data_to_send(stream_id);
.http_stream()
.ok_or(Error::InvalidStreamId)?
.send_headers(headers, conn)?;
self.base_handler.stream_has_pending_data(stream_id);
self.needs_processing = true;
Ok(())
}
/// Reset a request.
pub fn stream_reset(
&mut self,
conn: &mut Connection,
stream_id: u64,
app_error: AppError,
) -> Res<()> {
self.base_handler.stream_reset(conn, stream_id, app_error)?;
self.events.remove_events_for_stream_id(stream_id);
/// This is called when application is done sending a request.
/// # Errors
/// An error will be returned if stream does not exist.
pub fn stream_close_send(&mut self, stream_id: StreamId, conn: &mut Connection) -> Res<()> {
qinfo!([self], "Close sending side stream={}.", stream_id);
self.base_handler.stream_close_send(conn, stream_id)?;
self.base_handler.stream_has_pending_data(stream_id);
self.needs_processing = true;
Ok(())
}
/// An application may reset a stream(request).
/// Both sides, 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,
conn: &mut Connection,
) -> Res<()> {
qinfo!([self], "cancel_fetch {} error={}.", stream_id, error);
self.needs_processing = true;
self.base_handler.cancel_fetch(stream_id, error, conn)
}
pub fn stream_stop_sending(
&mut self,
stream_id: StreamId,
error: AppError,
conn: &mut Connection,
) -> Res<()> {
qinfo!([self], "stream_stop_sending {} error={}.", stream_id, error);
self.needs_processing = true;
self.base_handler
.stream_stop_sending(conn, stream_id, error)
}
pub fn stream_reset_send(
&mut self,
stream_id: StreamId,
error: AppError,
conn: &mut Connection,
) -> Res<()> {
qinfo!([self], "stream_reset_send {} error={}.", stream_id, error);
self.needs_processing = true;
self.base_handler.stream_reset_send(conn, stream_id, error)
}
/// Accept a `WebTransport` Session request
pub(crate) fn webtransport_session_accept(
&mut self,
conn: &mut Connection,
stream_id: StreamId,
accept: bool,
) -> Res<()> {
self.needs_processing = true;
self.base_handler.webtransport_session_accept(
conn,
stream_id,
Box::new(self.events.clone()),
accept,
)
}
pub fn webtransport_create_stream(
&mut self,
conn: &mut Connection,
session_id: StreamId,
stream_type: StreamType,
) -> Res<StreamId> {
self.needs_processing = true;
self.base_handler.webtransport_create_stream_local(
conn,
session_id,
stream_type,
Box::new(self.events.clone()),
Box::new(self.events.clone()),
)
}
/// Process HTTTP3 layer.
pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) {
qtrace!([self], "Process http3 internal.");
@ -122,23 +216,9 @@ impl Http3ServerHandler {
while let Some(e) = conn.next_event() {
qdebug!([self], "check_connection_events - event {:?}.", e);
match e {
ConnectionEvent::NewStream { stream_id } => match stream_id.stream_type() {
StreamType::BiDi => self.base_handler.add_streams(
stream_id.as_u64(),
SendMessage::new(stream_id.as_u64(), Box::new(self.events.clone())),
Box::new(RecvMessage::new(
MessageType::Request,
stream_id.as_u64(),
Rc::clone(&self.base_handler.qpack_decoder),
Box::new(self.events.clone()),
None,
PriorityHandler::new(false, Priority::default()),
)),
),
StreamType::UniDi => self
.base_handler
.handle_new_unidi_stream(stream_id.as_u64(), Role::Server),
},
ConnectionEvent::NewStream { stream_id } => {
self.base_handler.add_new_stream(stream_id);
}
ConnectionEvent::RecvStreamReadable { stream_id } => {
self.handle_stream_readable(conn, stream_id)?;
}
@ -147,14 +227,14 @@ impl Http3ServerHandler {
app_error,
} => {
self.base_handler
.handle_stream_reset(stream_id, app_error)?;
.handle_stream_reset(stream_id, app_error, conn)?;
}
ConnectionEvent::SendStreamStopSending {
stream_id,
app_error,
} => self
.base_handler
.handle_stream_stop_sending(stream_id, app_error)?,
.handle_stream_stop_sending(stream_id, app_error, conn)?,
ConnectionEvent::StateChange(state) => {
if self.base_handler.handle_state_change(conn, &state)? {
if self.base_handler.state() == Http3State::Connected {
@ -165,12 +245,16 @@ impl Http3ServerHandler {
.connection_state_change(self.base_handler.state());
}
}
ConnectionEvent::SendStreamWritable { stream_id } => {
if let Some(s) = self.base_handler.send_streams.get_mut(&stream_id) {
s.stream_writable();
}
}
ConnectionEvent::AuthenticationNeeded
| ConnectionEvent::EchFallbackAuthenticationNeeded { .. }
| ConnectionEvent::ZeroRttRejected
| ConnectionEvent::ResumptionToken(..) => return Err(Error::HttpInternal(4)),
ConnectionEvent::SendStreamWritable { .. }
| ConnectionEvent::SendStreamComplete { .. }
ConnectionEvent::SendStreamComplete { .. }
| ConnectionEvent::SendStreamCreatable { .. }
| ConnectionEvent::Datagram { .. }
| ConnectionEvent::OutgoingDatagramOutcome { .. }
@ -180,9 +264,47 @@ impl Http3ServerHandler {
Ok(())
}
fn handle_stream_readable(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
fn handle_stream_readable(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<()> {
match self.base_handler.handle_stream_readable(conn, stream_id)? {
ReceiveOutput::PushStream => Err(Error::HttpStreamCreation),
ReceiveOutput::NewStream(NewStreamType::Push(_)) => Err(Error::HttpStreamCreation),
ReceiveOutput::NewStream(NewStreamType::Http) => {
self.base_handler.add_streams(
stream_id,
Box::new(SendMessage::new(
MessageType::Response,
Http3StreamType::Http,
stream_id,
self.base_handler.qpack_encoder.clone(),
Box::new(self.events.clone()),
)),
Box::new(RecvMessage::new(
&RecvMessageInfo {
message_type: MessageType::Request,
stream_type: Http3StreamType::Http,
stream_id,
header_frame_type_read: true,
},
Rc::clone(&self.base_handler.qpack_decoder),
Box::new(self.events.clone()),
None,
PriorityHandler::new(false, Priority::default()),
)),
);
let res = self.base_handler.handle_stream_readable(conn, stream_id)?;
assert_eq!(ReceiveOutput::NoOutput, res);
Ok(())
}
ReceiveOutput::NewStream(NewStreamType::WebTransportStream(session_id)) => {
self.base_handler.webtransport_create_stream_remote(
StreamId::from(session_id),
stream_id,
Box::new(self.events.clone()),
Box::new(self.events.clone()),
)?;
let res = self.base_handler.handle_stream_readable(conn, stream_id)?;
assert_eq!(ReceiveOutput::NoOutput, res);
Ok(())
}
ReceiveOutput::ControlFrames(control_frames) => {
for f in control_frames {
match f {
@ -196,7 +318,7 @@ impl Http3ServerHandler {
HFrame::PriorityUpdatePush { element_id, priority } => {
// TODO: check if the element_id references a promised push stream or
// is greater than the maximum Push ID.
self.events.priority_update(element_id, priority);
self.events.priority_update(StreamId::from(element_id), priority);
Ok(())
}
HFrame::PriorityUpdateRequest { element_id, priority } => {
@ -210,7 +332,7 @@ impl Http3ServerHandler {
return Err(Error::HttpId)
}
self.events.priority_update(element_id, priority);
self.events.priority_update(element_stream_id, priority);
Ok(())
}
_ => unreachable!(
@ -229,27 +351,19 @@ impl Http3ServerHandler {
/// # Errors
/// It returns an error if a stream does not exist or an error happen while reading a stream, e.g.
/// early close, protocol error, etc.
pub fn read_request_data(
pub fn read_data(
&mut self,
conn: &mut Connection,
now: Instant,
stream_id: u64,
stream_id: StreamId,
buf: &mut [u8],
) -> Res<(usize, bool)> {
qinfo!([self], "read_data from stream {}.", stream_id);
let recv_stream = self
.base_handler
.recv_streams
.get_mut(&stream_id)
.ok_or(Error::InvalidStreamId)?
.http_stream()
.ok_or(Error::InvalidStreamId)?;
let res = recv_stream.read_data(conn, buf);
let res = self.base_handler.read_data(conn, stream_id, buf);
if let Err(e) = &res {
self.close(conn, now, e);
} else if recv_stream.done() {
self.base_handler.recv_streams.remove(&stream_id);
if e.connection_error() {
self.close(conn, now, e);
}
}
res
}

Просмотреть файл

@ -5,34 +5,32 @@
// except according to those terms.
use crate::hframe::HFrame;
use crate::{Http3StreamType, RecvStream, Res};
use crate::{BufferedStream, Http3StreamType, RecvStream, Res};
use neqo_common::{qtrace, Encoder};
use neqo_transport::{Connection, StreamType};
use neqo_transport::{Connection, StreamId, StreamType};
use std::collections::{HashMap, VecDeque};
use std::convert::TryFrom;
pub const HTTP3_UNI_STREAM_TYPE_CONTROL: u64 = 0x0;
// The local control stream, responsible for encoding frames and sending them
/// The local control stream, responsible for encoding frames and sending them
#[derive(Debug)]
pub(crate) struct ControlStreamLocal {
stream_id: Option<u64>,
buf: Vec<u8>,
// `stream_id`s of outstanding request streams
outstanding_priority_update: VecDeque<u64>,
stream: BufferedStream,
/// `stream_id`s of outstanding request streams
outstanding_priority_update: VecDeque<StreamId>,
}
impl ::std::fmt::Display for ControlStreamLocal {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Local control stream {:?}", self.stream_id)
write!(f, "Local control stream {:?}", self.stream)
}
}
impl ControlStreamLocal {
pub fn new() -> Self {
Self {
stream_id: None,
buf: vec![u8::try_from(HTTP3_UNI_STREAM_TYPE_CONTROL).unwrap()],
stream: BufferedStream::default(),
outstanding_priority_update: VecDeque::new(),
}
}
@ -41,10 +39,10 @@ impl ControlStreamLocal {
pub fn queue_frame(&mut self, f: &HFrame) {
let mut enc = Encoder::default();
f.encode(&mut enc);
self.buf.append(&mut enc.into());
self.stream.buffer(&enc);
}
pub fn queue_update_priority(&mut self, stream_id: u64) {
pub fn queue_update_priority(&mut self, stream_id: StreamId) {
self.outstanding_priority_update.push_back(stream_id);
}
@ -52,32 +50,16 @@ impl ControlStreamLocal {
pub fn send(
&mut self,
conn: &mut Connection,
recv_conn: &mut HashMap<u64, Box<dyn RecvStream>>,
recv_conn: &mut HashMap<StreamId, Box<dyn RecvStream>>,
) -> Res<()> {
if let Some(stream_id) = self.stream_id {
if !self.buf.is_empty() {
qtrace!([self], "sending data.");
let sent = conn.stream_send(stream_id, &self.buf[..])?;
if sent == self.buf.len() {
self.buf.clear();
} else {
let b = self.buf.split_off(sent);
self.buf = b;
}
}
// only send priority updates if all buffer data has been sent
if self.buf.is_empty() {
self.send_priority_update(stream_id, conn, recv_conn)?;
}
}
Ok(())
self.stream.send_buffer(conn)?;
self.send_priority_update(conn, recv_conn)
}
fn send_priority_update(
&mut self,
stream_id: u64,
conn: &mut Connection,
recv_conn: &mut HashMap<u64, Box<dyn RecvStream>>,
recv_conn: &mut HashMap<StreamId, Box<dyn RecvStream>>,
) -> Res<()> {
// send all necessary priority updates
while let Some(update_id) = self.outstanding_priority_update.pop_front() {
@ -98,7 +80,7 @@ impl ControlStreamLocal {
if let Some(hframe) = priority_handler.maybe_encode_frame(update_id) {
let mut enc = Encoder::new();
hframe.encode(&mut enc);
if conn.stream_send_atomic(stream_id, &enc)? {
if self.stream.send_atomic(conn, &enc)? {
priority_handler.priority_update_sent();
} else {
self.outstanding_priority_update.push_front(update_id);
@ -112,12 +94,14 @@ impl ControlStreamLocal {
/// Create a control stream.
pub fn create(&mut self, conn: &mut Connection) -> Res<()> {
qtrace!([self], "Create a control stream.");
self.stream_id = Some(conn.stream_create(StreamType::UniDi)?);
self.stream.init(conn.stream_create(StreamType::UniDi)?);
self.stream
.buffer(&[u8::try_from(HTTP3_UNI_STREAM_TYPE_CONTROL).unwrap()]);
Ok(())
}
#[must_use]
pub fn stream_id(&self) -> Option<u64> {
self.stream_id
pub fn stream_id(&self) -> Option<StreamId> {
(&self.stream).into()
}
}

Просмотреть файл

@ -5,16 +5,14 @@
// except according to those terms.
use crate::hframe::{HFrame, HFrameReader};
use crate::{
AppError, Error, Http3StreamType, HttpRecvStream, ReceiveOutput, RecvStream, Res, ResetType,
};
use crate::{CloseType, Error, Http3StreamType, ReceiveOutput, RecvStream, Res, Stream};
use neqo_common::qdebug;
use neqo_transport::Connection;
use neqo_transport::{Connection, StreamId};
/// The remote control stream is responsible only for reading frames. The frames are handled by `Http3Connection`.
#[derive(Debug)]
pub(crate) struct ControlStreamRemote {
stream_id: u64,
stream_id: StreamId,
frame_reader: HFrameReader,
}
@ -25,7 +23,7 @@ impl ::std::fmt::Display for ControlStreamRemote {
}
impl ControlStreamRemote {
pub fn new(stream_id: u64) -> Self {
pub fn new(stream_id: StreamId) -> Self {
Self {
stream_id,
frame_reader: HFrameReader::new(),
@ -42,33 +40,27 @@ impl ControlStreamRemote {
}
}
impl Stream for ControlStreamRemote {
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::Control
}
}
impl RecvStream for ControlStreamRemote {
fn stream_reset(&mut self, _error: AppError, _reset_type: ResetType) -> Res<()> {
fn reset(&mut self, _close_type: CloseType) -> Res<()> {
Err(Error::HttpClosedCriticalStream)
}
#[allow(clippy::vec_init_then_push)] // Clippy fail.
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput> {
fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
let mut control_frames = Vec::new();
loop {
if let Some(f) = self.receive_single(conn)? {
control_frames.push(f);
} else {
return Ok(ReceiveOutput::ControlFrames(control_frames));
return Ok((ReceiveOutput::ControlFrames(control_frames), false));
}
}
}
fn done(&self) -> bool {
false
}
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::Control
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
None
}
}

120
third_party/rust/neqo-http3/src/features/extended_connect/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,120 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::module_name_repetitions)]
pub mod session;
pub mod webtransport;
use crate::client_events::Http3ClientEvents;
use crate::features::NegotiationState;
use crate::settings::{HSettingType, HSettings};
use crate::{Http3StreamInfo, Http3StreamType};
use neqo_transport::{AppError, StreamId};
pub use session::ExtendedConnectSession;
use std::cell::RefCell;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::fmt::Debug;
use std::rc::Rc;
pub trait ExtendedConnectEvents: Debug {
fn session_start(&self, connect_type: ExtendedConnectType, stream_id: StreamId);
fn session_end(
&self,
connect_type: ExtendedConnectType,
stream_id: StreamId,
error: Option<AppError>,
);
fn extended_connect_new_stream(&self, stream_info: Http3StreamInfo);
}
#[derive(Debug, PartialEq, Copy, Clone, Eq)]
pub enum ExtendedConnectType {
WebTransport,
}
impl ExtendedConnectType {
#[must_use]
#[allow(clippy::unused_self)] // This will change when we have more features using ExtendedConnectType.
pub fn string(&self) -> &str {
"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 {
Http3StreamType::WebTransport(session_id)
}
}
impl From<ExtendedConnectType> for HSettingType {
fn from(_type: ExtendedConnectType) -> Self {
// This will change when we have more features using ExtendedConnectType.
HSettingType::EnableWebTransport
}
}
#[derive(Debug)]
pub struct ExtendedConnectFeature {
connect_type: ExtendedConnectType,
feature_negotiation: NegotiationState,
sessions: HashMap<StreamId, Rc<RefCell<ExtendedConnectSession>>>,
}
impl ExtendedConnectFeature {
#[must_use]
pub fn new(connect_type: ExtendedConnectType, enable: bool) -> Self {
Self {
feature_negotiation: NegotiationState::new(enable, HSettingType::from(connect_type)),
connect_type,
sessions: HashMap::new(),
}
}
pub fn set_listener(&mut self, new_listener: Http3ClientEvents) {
self.feature_negotiation.set_listener(new_listener);
}
pub fn insert(&mut self, stream_id: StreamId, session: Rc<RefCell<ExtendedConnectSession>>) {
self.sessions.insert(stream_id, session);
}
pub fn get_session(
&mut self,
stream_id: StreamId,
) -> Option<Rc<RefCell<ExtendedConnectSession>>> {
if !matches!(self.feature_negotiation, NegotiationState::Negotiated) {
return None;
}
self.sessions.get_mut(&stream_id).cloned()
}
pub fn handle_settings(&mut self, settings: &HSettings) {
self.feature_negotiation.handle_settings(settings);
}
#[must_use]
pub fn enabled(&self) -> bool {
self.feature_negotiation.enabled()
}
pub fn remove(
&mut self,
stream_id: StreamId,
) -> Option<(BTreeSet<StreamId>, BTreeSet<StreamId>)> {
self.sessions
.remove(&stream_id)
.and_then(|ec| ec.borrow_mut().take_sub_streams())
}
}

Просмотреть файл

@ -0,0 +1,179 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::module_name_repetitions)]
use super::{ExtendedConnectEvents, ExtendedConnectType};
use crate::{
CloseType, Error, Http3StreamInfo, HttpRecvStreamEvents, RecvStreamEvents, SendStreamEvents,
};
use neqo_common::{qtrace, Header, Role};
use neqo_transport::StreamId;
use std::cell::RefCell;
use std::collections::BTreeSet;
use std::mem;
use std::rc::Rc;
#[derive(Debug, PartialEq)]
enum SessionState {
Negotiating,
Active(StreamId),
Done,
}
#[derive(Debug)]
pub struct ExtendedConnectSession {
connect_type: ExtendedConnectType,
state: SessionState,
events: Box<dyn ExtendedConnectEvents>,
send_streams: BTreeSet<StreamId>,
recv_streams: BTreeSet<StreamId>,
role: Role,
}
impl ::std::fmt::Display for ExtendedConnectSession {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(
f,
"ExtendedConnectSesssion for {}",
self.connect_type.string(),
)
}
}
impl ExtendedConnectSession {
#[must_use]
pub fn new(
connect_type: ExtendedConnectType,
events: Box<dyn ExtendedConnectEvents>,
role: Role,
) -> Self {
Self {
connect_type,
state: SessionState::Negotiating,
events,
send_streams: BTreeSet::new(),
recv_streams: BTreeSet::new(),
role,
}
}
fn close(&mut self, stream_id: StreamId, close_type: CloseType) {
if self.state == SessionState::Done {
return;
}
qtrace!("ExtendedConnect close the session");
self.state = SessionState::Done;
if let CloseType::ResetApp(_) = close_type {
return;
}
self.events
.session_end(self.connect_type, stream_id, close_type.error());
}
pub fn negotiation_done(&mut self, stream_id: StreamId, succeeded: bool) {
if self.state == SessionState::Done {
return;
}
self.state = if succeeded {
self.events.session_start(self.connect_type, stream_id);
SessionState::Active(stream_id)
} else {
self.events.session_end(self.connect_type, stream_id, None);
SessionState::Done
};
}
pub fn add_stream(&mut self, stream_id: StreamId) {
if let SessionState::Active(session_id) = self.state {
if stream_id.is_bidi() {
self.send_streams.insert(stream_id);
self.recv_streams.insert(stream_id);
} else if stream_id.is_self_initiated(self.role) {
self.send_streams.insert(stream_id);
} else {
self.recv_streams.insert(stream_id);
}
if !stream_id.is_self_initiated(self.role) {
self.events
.extended_connect_new_stream(Http3StreamInfo::new(
stream_id,
self.connect_type.get_stream_type(session_id),
));
}
}
}
pub fn remove_recv_stream(&mut self, stream_id: StreamId) {
self.recv_streams.remove(&stream_id);
}
pub fn remove_send_stream(&mut self, stream_id: StreamId) {
self.send_streams.remove(&stream_id);
}
#[must_use]
pub fn is_active(&self) -> bool {
matches!(self.state, SessionState::Active(_))
}
pub fn take_sub_streams(&mut self) -> Option<(BTreeSet<StreamId>, BTreeSet<StreamId>)> {
Some((
mem::take(&mut self.recv_streams),
mem::take(&mut self.send_streams),
))
}
}
impl RecvStreamEvents for Rc<RefCell<ExtendedConnectSession>> {
fn data_readable(&self, stream_info: Http3StreamInfo) {
// A session request is not expected to receive any data. This may change in
// the future.
self.borrow_mut().close(
stream_info.stream_id(),
CloseType::LocalError(Error::HttpGeneralProtocolStream.code()),
);
}
fn recv_closed(&self, stream_info: Http3StreamInfo, close_type: CloseType) {
self.borrow_mut().close(stream_info.stream_id(), close_type);
}
}
impl HttpRecvStreamEvents for Rc<RefCell<ExtendedConnectSession>> {
fn header_ready(
&self,
stream_info: Http3StreamInfo,
headers: Vec<Header>,
_interim: bool,
_fin: bool,
) {
qtrace!("ExtendedConnect response headers {:?}", headers);
self.borrow_mut().negotiation_done(
stream_info.stream_id(),
headers
.iter()
.find_map(|h| {
if h.name() == ":status" && h.value() == "200" {
Some(())
} else {
None
}
})
.is_some(),
);
}
}
impl SendStreamEvents for Rc<RefCell<ExtendedConnectSession>> {
fn data_writable(&self, _stream_info: Http3StreamInfo) {}
/// Add a new `StopSending` event
fn send_closed(&self, stream_info: Http3StreamInfo, close_type: CloseType) {
self.borrow_mut().close(stream_info.stream_id(), close_type);
}
}

Просмотреть файл

@ -0,0 +1,202 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::ExtendedConnectSession;
use crate::{
CloseType, Http3StreamInfo, Http3StreamType, ReceiveOutput, RecvStream, RecvStreamEvents, Res,
SendStream, SendStreamEvents, Stream,
};
use neqo_common::Encoder;
use neqo_transport::{Connection, StreamId};
use std::cell::RefCell;
use std::rc::Rc;
pub const WEBTRANSPORT_UNI_STREAM: u64 = 0x54;
pub const WEBTRANSPORT_STREAM: u64 = 0x41;
#[derive(Debug)]
pub struct WebTransportRecvStream {
stream_id: StreamId,
events: Box<dyn RecvStreamEvents>,
session: Rc<RefCell<ExtendedConnectSession>>,
session_id: StreamId,
fin: bool,
}
impl WebTransportRecvStream {
pub fn new(
stream_id: StreamId,
session_id: StreamId,
events: Box<dyn RecvStreamEvents>,
session: Rc<RefCell<ExtendedConnectSession>>,
) -> Self {
Self {
stream_id,
events,
session_id,
session,
fin: false,
}
}
fn get_info(&self) -> Http3StreamInfo {
Http3StreamInfo::new(self.stream_id, self.stream_type())
}
}
impl Stream for WebTransportRecvStream {
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::WebTransport(self.session_id)
}
}
impl RecvStream for WebTransportRecvStream {
fn receive(&mut self, _conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
self.events.data_readable(self.get_info());
Ok((ReceiveOutput::NoOutput, false))
}
fn reset(&mut self, close_type: CloseType) -> Res<()> {
if !matches!(close_type, CloseType::ResetApp(_)) {
self.events.recv_closed(self.get_info(), close_type);
}
self.session.borrow_mut().remove_recv_stream(self.stream_id);
Ok(())
}
fn read_data(&mut self, conn: &mut Connection, buf: &mut [u8]) -> Res<(usize, bool)> {
let (amount, fin) = conn.stream_recv(self.stream_id, buf)?;
self.fin = fin;
if fin {
self.session.borrow_mut().remove_recv_stream(self.stream_id);
}
Ok((amount, fin))
}
}
#[derive(Debug, PartialEq)]
enum WebTransportSenderStreamState {
SendingInit { buf: Vec<u8>, fin: bool },
SendingData,
Done,
}
#[derive(Debug)]
pub struct WebTransportSendStream {
stream_id: StreamId,
state: WebTransportSenderStreamState,
events: Box<dyn SendStreamEvents>,
session: Rc<RefCell<ExtendedConnectSession>>,
session_id: StreamId,
}
impl WebTransportSendStream {
pub fn new(
stream_id: StreamId,
session_id: StreamId,
events: Box<dyn SendStreamEvents>,
session: Rc<RefCell<ExtendedConnectSession>>,
local: bool,
) -> Self {
Self {
stream_id,
state: if local {
let mut d = Encoder::default();
if stream_id.is_uni() {
d.encode_varint(WEBTRANSPORT_UNI_STREAM);
} else {
d.encode_varint(WEBTRANSPORT_STREAM);
}
d.encode_varint(session_id.as_u64());
WebTransportSenderStreamState::SendingInit {
buf: d.into(),
fin: false,
}
} else {
WebTransportSenderStreamState::SendingData
},
events,
session_id,
session,
}
}
fn set_done(&mut self, close_type: CloseType) {
self.state = WebTransportSenderStreamState::Done;
self.events.send_closed(self.get_info(), close_type);
self.session.borrow_mut().remove_send_stream(self.stream_id);
}
fn get_info(&self) -> Http3StreamInfo {
Http3StreamInfo::new(self.stream_id, self.stream_type())
}
}
impl Stream for WebTransportSendStream {
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::WebTransport(self.session_id)
}
}
impl SendStream for WebTransportSendStream {
fn send(&mut self, conn: &mut Connection) -> Res<()> {
if let WebTransportSenderStreamState::SendingInit { ref mut buf, fin } = self.state {
let sent = conn.stream_send(self.stream_id, &buf[..])?;
if sent == buf.len() {
if fin {
conn.stream_close_send(self.stream_id)?;
self.set_done(CloseType::Done);
} else {
self.state = WebTransportSenderStreamState::SendingData;
}
} else {
let b = buf.split_off(sent);
*buf = b;
}
}
Ok(())
}
fn has_data_to_send(&self) -> bool {
matches!(
self.state,
WebTransportSenderStreamState::SendingInit { .. }
)
}
fn stream_writable(&self) {
self.events.data_writable(self.get_info());
}
fn done(&self) -> bool {
self.state == WebTransportSenderStreamState::Done
}
fn send_data(&mut self, conn: &mut Connection, buf: &[u8]) -> Res<usize> {
self.send(conn)?;
if self.state == WebTransportSenderStreamState::SendingData {
let sent = conn.stream_send(self.stream_id, buf)?;
Ok(sent)
} else {
Ok(0)
}
}
fn handle_stop_sending(&mut self, close_type: CloseType) {
self.set_done(close_type);
}
fn close(&mut self, conn: &mut Connection) -> Res<()> {
if let WebTransportSenderStreamState::SendingInit { ref mut fin, .. } = self.state {
*fin = true;
} else {
self.state = WebTransportSenderStreamState::Done;
conn.stream_close_send(self.stream_id)?;
self.set_done(CloseType::Done);
}
Ok(())
}
}

91
third_party/rust/neqo-http3/src/features/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,91 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::{
client_events::Http3ClientEvents,
settings::{HSettingType, HSettings},
};
use neqo_common::qtrace;
use std::fmt::Debug;
use std::mem;
pub mod extended_connect;
/// States:
/// - `Disable` - it is not turned on for this connection.
/// - `Negotiating` - the feature is enabled locally, but settings from the peer
/// have not been received yet.
/// - `Negotiated` - the settings have been received and both sides support the feature.
/// - `NegotiationFailed` - the settings have been received and the peer does not
/// support the feature.
#[derive(Debug)]
pub enum NegotiationState {
Disabled,
Negotiating {
feature_type: HSettingType,
listener: Option<Http3ClientEvents>,
},
Negotiated,
NegotiationFailed,
}
impl NegotiationState {
#[must_use]
pub fn new(enable: bool, feature_type: HSettingType) -> Self {
if enable {
Self::Negotiating {
feature_type,
listener: None,
}
} else {
Self::Disabled
}
}
pub fn set_listener(&mut self, new_listener: Http3ClientEvents) {
if let Self::Negotiating { listener, .. } = self {
*listener = Some(new_listener);
}
}
pub fn handle_settings(&mut self, settings: &HSettings) {
if !self.locally_enabled() {
return;
}
if let Self::Negotiating {
feature_type,
listener,
} = self
{
qtrace!(
"set_negotiated {:?} to {}",
feature_type,
settings.get(*feature_type)
);
let cb = mem::take(listener);
let ft = *feature_type;
*self = if settings.get(ft) == 1 {
Self::Negotiated
} else {
Self::NegotiationFailed
};
if let Some(l) = cb {
l.negotiation_done(ft, self.enabled());
}
}
}
#[must_use]
pub fn enabled(&self) -> bool {
matches!(self, &Self::Negotiated)
}
#[must_use]
pub fn locally_enabled(&self) -> bool {
!matches!(self, &Self::Disabled)
}
}

120
third_party/rust/neqo-http3/src/headers_checks.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,120 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::{Error, MessageType, Res};
use neqo_common::Header;
const PSEUDO_HEADER_STATUS: u8 = 0x1;
const PSEUDO_HEADER_METHOD: u8 = 0x2;
const PSEUDO_HEADER_SCHEME: u8 = 0x4;
const PSEUDO_HEADER_AUTHORITY: u8 = 0x8;
const PSEUDO_HEADER_PATH: u8 = 0x10;
const PSEUDO_HEADER_PROTOCOL: u8 = 0x20;
const REGULAR_HEADER: u8 = 0x80;
/// Check whether the response is informational(1xx).
/// # Errors
/// Returns an error if response headers do not contain
/// a status header or if the value of the header cannot be parsed.
pub fn is_interim(headers: &[Header]) -> Res<bool> {
let status = headers.iter().take(1).find(|h| h.name() == ":status");
if let Some(h) = status {
#[allow(clippy::map_err_ignore)]
let status_code = h.value().parse::<i32>().map_err(|_| Error::InvalidHeader)?;
Ok((100..200).contains(&status_code))
} else {
Err(Error::InvalidHeader)
}
}
fn track_pseudo(name: &str, state: &mut u8, message_type: MessageType) -> Res<bool> {
let (pseudo, bit) = if name.starts_with(':') {
if *state & REGULAR_HEADER != 0 {
return Err(Error::InvalidHeader);
}
let bit = match (message_type, name) {
(MessageType::Response, ":status") => PSEUDO_HEADER_STATUS,
(MessageType::Request, ":method") => PSEUDO_HEADER_METHOD,
(MessageType::Request, ":scheme") => PSEUDO_HEADER_SCHEME,
(MessageType::Request, ":authority") => PSEUDO_HEADER_AUTHORITY,
(MessageType::Request, ":path") => PSEUDO_HEADER_PATH,
(MessageType::Request, ":protocol") => PSEUDO_HEADER_PROTOCOL,
(_, _) => return Err(Error::InvalidHeader),
};
(true, bit)
} else {
(false, REGULAR_HEADER)
};
if *state & bit == 0 || !pseudo {
*state |= bit;
Ok(pseudo)
} else {
Err(Error::InvalidHeader)
}
}
/// Checks if request/response headers are well formed, i.e. contain
/// allowed pseudo headers and in a right order, etc.
/// # Errors
/// Returns an error if headers are not well formed.
pub fn headers_valid(headers: &[Header], message_type: MessageType) -> Res<()> {
let mut method_value: Option<&str> = None;
let mut pseudo_state = 0;
for header in headers {
let is_pseudo = track_pseudo(header.name(), &mut pseudo_state, message_type)?;
let mut bytes = header.name().bytes();
if is_pseudo {
if header.name() == ":method" {
method_value = Some(header.value());
}
let _ = bytes.next();
}
if bytes.any(|b| matches!(b, 0 | 0x10 | 0x13 | 0x3a | 0x41..=0x5a)) {
return Err(Error::InvalidHeader); // illegal characters.
}
}
// Clear the regular header bit, since we only check pseudo headers below.
pseudo_state &= !REGULAR_HEADER;
let pseudo_header_mask = match message_type {
MessageType::Response => PSEUDO_HEADER_STATUS,
MessageType::Request => {
if method_value == Some(&"CONNECT".to_string()) {
PSEUDO_HEADER_METHOD | PSEUDO_HEADER_AUTHORITY
} else {
PSEUDO_HEADER_METHOD | PSEUDO_HEADER_SCHEME | PSEUDO_HEADER_PATH
}
}
};
if (MessageType::Request == message_type)
&& ((pseudo_state & PSEUDO_HEADER_PROTOCOL) > 0)
&& method_value != Some(&"CONNECT".to_string())
{
return Err(Error::InvalidHeader);
}
if pseudo_state & pseudo_header_mask != pseudo_header_mask {
return Err(Error::InvalidHeader);
}
Ok(())
}
/// Checks if trailers are well formed, i.e. pseudo headers are not
/// allowed in trailers.
/// # Errors
/// Returns an error if trailers are not well formed.
pub fn trailers_valid(headers: &[Header]) -> Res<()> {
for header in headers {
if header.name().starts_with(':') {
return Err(Error::InvalidHeader);
}
}
Ok(())
}

34
third_party/rust/neqo-http3/src/hframe.rs поставляемый
Просмотреть файл

@ -10,7 +10,7 @@ use neqo_common::{
IncrementalDecoderUint,
};
use neqo_crypto::random;
use neqo_transport::Connection;
use neqo_transport::{Connection, StreamId};
use std::convert::TryFrom;
use std::io::Write;
use std::mem;
@ -52,7 +52,7 @@ pub enum HFrame {
header_block: Vec<u8>,
},
Goaway {
stream_id: u64,
stream_id: StreamId,
},
MaxPushId {
push_id: u64,
@ -116,7 +116,7 @@ impl HFrame {
}
Self::Goaway { stream_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*stream_id);
enc_inner.encode_varint(stream_id.as_u64());
});
}
Self::MaxPushId { push_id } => {
@ -186,6 +186,18 @@ impl HFrameReader {
}
}
#[must_use]
pub fn new_with_type(hframe_type: u64) -> Self {
Self {
state: HFrameReaderState::GetLength {
decoder: IncrementalDecoderUint::default(),
},
hframe_type,
hframe_len: 0,
payload: Vec::new(),
}
}
fn reset(&mut self) {
self.state = HFrameReaderState::GetType {
decoder: IncrementalDecoderUint::default(),
@ -217,7 +229,7 @@ impl HFrameReader {
pub fn receive(
&mut self,
conn: &mut Connection,
stream_id: u64,
stream_id: StreamId,
) -> Res<(Option<HFrame>, bool)> {
loop {
let to_read = std::cmp::min(self.min_remaining(), MAX_READ_SIZE);
@ -372,7 +384,7 @@ impl HFrameReader {
header_block: dec.decode_remainder().to_vec(),
},
H3_FRAME_TYPE_GOAWAY => HFrame::Goaway {
stream_id: dec.decode_varint().ok_or(Error::HttpFrame)?,
stream_id: StreamId::new(dec.decode_varint().ok_or(Error::HttpFrame)?),
},
H3_FRAME_TYPE_MAX_PUSH_ID => HFrame::MaxPushId {
push_id: dec.decode_varint().ok_or(Error::HttpFrame)?,
@ -406,7 +418,7 @@ mod tests {
use crate::settings::{HSetting, HSettingType};
use crate::Priority;
use neqo_crypto::AuthenticationStatus;
use neqo_transport::{Connection, StreamType};
use neqo_transport::{Connection, StreamId, StreamType};
use std::mem;
use test_fixture::{connect, default_client, default_server, fixture_init, now};
@ -491,7 +503,9 @@ mod tests {
#[test]
fn test_goaway_frame4() {
let f = HFrame::Goaway { stream_id: 5 };
let f = HFrame::Goaway {
stream_id: StreamId::new(5),
};
enc_dec(&f, "070105", 0);
}
@ -569,7 +583,7 @@ mod tests {
pub fr: HFrameReader,
pub conn_c: Connection,
pub conn_s: Connection,
pub stream_id: u64,
pub stream_id: StreamId,
}
impl HFrameReaderTest {
@ -934,7 +948,9 @@ mod tests {
test_complete_and_incomplete_frame(&buf, buf.len());
// H3_FRAME_TYPE_GOAWAY
let f = HFrame::Goaway { stream_id: 5 };
let f = HFrame::Goaway {
stream_id: StreamId::new(5),
};
let mut enc = Encoder::default();
f.encode(&mut enc);
let buf: Vec<_> = enc.into();

199
third_party/rust/neqo-http3/src/lib.rs поставляемый
Просмотреть файл

@ -7,16 +7,19 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
mod buffered_send_stream;
mod client_events;
mod conn_params;
mod connection;
pub mod connection_client;
mod connection_server;
mod control_stream_local;
mod control_stream_remote;
pub mod features;
mod headers_checks;
pub mod hframe;
mod priority;
mod push_controller;
mod push_stream;
mod qlog;
mod qpack_decoder_receiver;
mod qpack_encoder_receiver;
@ -30,20 +33,23 @@ mod settings;
mod stream_type_reader;
use neqo_qpack::Error as QpackError;
pub use neqo_transport::Output;
use neqo_transport::{AppError, Connection, Error as TransportError};
pub use neqo_transport::{Output, StreamId};
use std::fmt::Debug;
use crate::priority::PriorityHandler;
pub use client_events::Http3ClientEvent;
pub use buffered_send_stream::BufferedStream;
pub use client_events::{Http3ClientEvent, WebTransportEvent};
pub use conn_params::Http3Parameters;
pub use connection::Http3State;
pub use connection_client::Http3Client;
pub use connection_client::Http3Parameters;
pub use hframe::{HFrame, HFrameReader};
pub use neqo_common::Header;
pub use neqo_common::{Header, MessageType};
pub use priority::Priority;
pub use server::Http3Server;
pub use server_events::{ClientRequestStream, Http3ServerEvent};
pub use server_events::{
Http3OrWebTransportStream, Http3ServerEvent, WebTransportRequest, WebTransportServerEvent,
};
pub use settings::HttpZeroRttChecker;
pub use stream_type_reader::NewStreamType;
@ -154,12 +160,13 @@ impl Error {
/// # Panics
/// On unexpected errors, in debug mode.
#[must_use]
pub fn map_stream_send_errors(err: &TransportError) -> Self {
pub fn map_stream_send_errors(err: &Error) -> Self {
match err {
TransportError::InvalidStreamId | TransportError::FinalSizeError => {
Self::TransportError(TransportError::InvalidStreamId)
| Self::TransportError(TransportError::FinalSizeError) => {
Error::TransportStreamDoesNotExist
}
TransportError::InvalidInput => Error::InvalidInput,
Self::TransportError(TransportError::InvalidInput) => Error::InvalidInput,
_ => {
debug_assert!(false, "Unexpected error");
Error::TransportStreamDoesNotExist
@ -278,7 +285,7 @@ impl ::std::fmt::Display for Error {
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Http3StreamType {
Control,
Decoder,
@ -286,50 +293,180 @@ pub enum Http3StreamType {
NewStream,
Http,
Push,
ExtendedConnect,
WebTransport(StreamId),
Unknown,
}
#[must_use]
#[derive(PartialEq, Debug)]
pub enum ReceiveOutput {
NoOutput,
PushStream,
ControlFrames(Vec<HFrame>),
UnblockedStreams(Vec<u64>),
UnblockedStreams(Vec<StreamId>),
NewStream(NewStreamType),
}
pub trait RecvStream: Debug {
/// # Errors
/// An error may happen while reading a stream, e.g. early close, etc.
fn stream_reset(&mut self, error: AppError, reset_type: ResetType) -> Res<()>;
impl Default for ReceiveOutput {
fn default() -> Self {
Self::NoOutput
}
}
pub trait Stream: Debug {
fn stream_type(&self) -> Http3StreamType;
}
pub 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.
/// # Errors
/// An error may happen while reading a stream, e.g. early close, protocol error, etc.
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput>;
fn done(&self) -> bool;
fn stream_type(&self) -> Http3StreamType;
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream>;
fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)>;
/// # Errors
/// An error may happen while reading a stream, e.g. early close, etc.
fn reset(&mut self, close_type: CloseType) -> Res<()>;
/// The function allows an app to read directly from the quic stream. The function
/// returns the number of bytes written into `buf` and true/false if the stream is
/// completely done and can be forgotten, i.e. removed from all records.
/// # Errors
/// An error may happen while reading a stream, e.g. early close, protocol error, etc.
fn read_data(&mut self, _conn: &mut Connection, _buf: &mut [u8]) -> Res<(usize, bool)> {
Err(Error::InvalidStreamId)
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
None
}
}
pub 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.
/// # Errors
/// An error may happen while reading a stream, e.g. early close, protocol error, etc.
fn header_unblocked(&mut self, conn: &mut Connection) -> Res<()>;
/// # Errors
/// An error may happen while reading a stream, e.g. early close, protocol error, etc.
fn read_data(&mut self, conn: &mut Connection, buf: &mut [u8]) -> Res<(usize, bool)>;
fn header_unblocked(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)>;
fn priority_handler_mut(&mut self) -> &mut PriorityHandler;
fn set_new_listener(&mut self, _conn_events: Box<dyn HttpRecvStreamEvents>) {}
fn extended_connect_wait_for_response(&self) -> bool {
false
}
}
pub(crate) trait RecvMessageEvents: Debug {
fn header_ready(&self, stream_id: u64, headers: Vec<Header>, interim: bool, fin: bool);
fn data_readable(&self, stream_id: u64);
fn reset(&self, stream_id: u64, error: AppError, local: bool);
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Http3StreamInfo {
stream_id: StreamId,
stream_type: Http3StreamType,
}
impl Http3StreamInfo {
#[must_use]
pub fn new(stream_id: StreamId, stream_type: Http3StreamType) -> Self {
Self {
stream_id,
stream_type,
}
}
#[must_use]
pub fn stream_id(&self) -> StreamId {
self.stream_id
}
#[must_use]
pub fn session_id(&self) -> Option<StreamId> {
if let Http3StreamType::WebTransport(session) = self.stream_type {
Some(session)
} else {
None
}
}
#[must_use]
pub fn is_http(&self) -> bool {
self.stream_type == Http3StreamType::Http
}
}
pub trait RecvStreamEvents: Debug {
fn data_readable(&self, stream_info: Http3StreamInfo);
fn recv_closed(&self, _stream_info: Http3StreamInfo, _close_type: CloseType) {}
}
pub trait HttpRecvStreamEvents: RecvStreamEvents {
fn header_ready(
&self,
stream_info: Http3StreamInfo,
headers: Vec<Header>,
interim: bool,
fin: bool,
);
fn extended_connect_new_session(&self, _stream_id: StreamId, _headers: Vec<Header>) {}
}
pub trait SendStream: Stream {
/// # Errors
/// Error my occure during sending data, e.g. protocol error, etc.
fn send(&mut self, conn: &mut Connection) -> Res<()>;
fn has_data_to_send(&self) -> bool;
fn stream_writable(&self);
fn done(&self) -> bool;
/// # Errors
/// Error my occure during sending data, e.g. protocol error, etc.
fn send_data(&mut self, _conn: &mut Connection, _buf: &[u8]) -> Res<usize>;
/// # Errors
/// It may happen that the transport stream is already close. This is unlikely.
fn close(&mut self, conn: &mut Connection) -> Res<()>;
/// This function is called when sending side is closed abruptly by the peer or
/// the application.
fn handle_stop_sending(&mut self, close_type: CloseType);
fn http_stream(&mut self) -> Option<&mut dyn HttpSendStream> {
None
}
}
pub 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.
/// # Errors
/// This can also return an error if the underlying stream is closed.
fn send_headers(&mut self, headers: &[Header], conn: &mut Connection) -> Res<()>;
fn set_new_listener(&mut self, _conn_events: Box<dyn SendStreamEvents>) {}
}
pub trait SendStreamEvents: Debug {
fn send_closed(&self, _stream_info: Http3StreamInfo, _close_type: CloseType) {}
fn data_writable(&self, _stream_info: Http3StreamInfo) {}
}
/// This enum is used to mark a different type of closing a stream:
/// `ResetApp` - the application has closed the stream.
/// `ResetRemote` - the stream was closed by the peer.
/// `LocalError` - There was a stream error on the stream. The stream errors are errors
/// 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 ResetType {
App,
Remote,
Local,
pub enum CloseType {
ResetApp(AppError),
ResetRemote(AppError),
LocalError(AppError),
Done,
}
impl CloseType {
#[must_use]
pub fn error(&self) -> Option<AppError> {
match self {
Self::ResetApp(error) | Self::ResetRemote(error) | Self::LocalError(error) => {
Some(*error)
}
Self::Done => None,
}
}
}

18
third_party/rust/neqo-http3/src/priority.rs поставляемый
Просмотреть файл

@ -1,4 +1,5 @@
use crate::{Error, HFrame, Header, Res};
use neqo_transport::StreamId;
use sfv::{BareItem, Item, ListEntry, Parser};
use std::convert::TryFrom;
use std::fmt;
@ -129,17 +130,17 @@ impl PriorityHandler {
}
/// Returns `HFrame` if an priority update is outstanding
pub fn maybe_encode_frame(&self, stream_id: u64) -> Option<HFrame> {
pub fn maybe_encode_frame(&self, stream_id: StreamId) -> Option<HFrame> {
if self.priority == self.last_send_priority {
None
} else if self.push_stream {
Some(HFrame::PriorityUpdatePush {
element_id: stream_id,
element_id: stream_id.as_u64(),
priority: self.priority,
})
} else {
Some(HFrame::PriorityUpdateRequest {
element_id: stream_id,
element_id: stream_id.as_u64(),
priority: self.priority,
})
}
@ -150,13 +151,14 @@ impl PriorityHandler {
mod test {
use crate::priority::PriorityHandler;
use crate::{HFrame, Priority};
use neqo_transport::StreamId;
#[test]
fn priority_updates_ignore_same() {
let mut p = PriorityHandler::new(false, Priority::new(5, false));
assert!(!p.maybe_update_priority(Priority::new(5, false)));
// updating with the same priority -> there should not be any priority frame sent
assert!(p.maybe_encode_frame(4).is_none());
assert!(p.maybe_encode_frame(StreamId::new(4)).is_none());
}
#[test]
@ -164,7 +166,7 @@ mod test {
let mut p = PriorityHandler::new(false, Priority::new(5, false));
assert!(p.maybe_update_priority(Priority::new(6, false)));
// updating with the a different priority -> there should be a priority frame sent
assert!(p.maybe_encode_frame(4).is_some());
assert!(p.maybe_encode_frame(StreamId::new(4)).is_some());
}
#[test]
@ -173,7 +175,7 @@ mod test {
assert!(p.maybe_update_priority(Priority::new(6, false)));
assert!(p.maybe_update_priority(Priority::new(5, false)));
// initial and last priority same -> there should not be any priority frame sent
assert!(p.maybe_encode_frame(4).is_none());
assert!(p.maybe_encode_frame(StreamId::new(4)).is_none());
}
#[test]
@ -186,7 +188,7 @@ mod test {
element_id: 4,
priority: Priority::new(7, false),
};
assert_eq!(p.maybe_encode_frame(4), Some(expected));
assert_eq!(p.maybe_encode_frame(StreamId::new(4)), Some(expected));
}
#[test]
@ -198,6 +200,6 @@ mod test {
element_id: 4,
priority: Priority::new(5, true),
};
assert_eq!(p.maybe_encode_frame(4), Some(expected));
assert_eq!(p.maybe_encode_frame(StreamId::new(4)), Some(expected));
}
}

Просмотреть файл

@ -6,10 +6,9 @@
use crate::client_events::{Http3ClientEvent, Http3ClientEvents};
use crate::connection::Http3Connection;
use crate::hframe::HFrame;
use crate::{Error, Header, Res};
use crate::{RecvMessageEvents, ResetType};
use neqo_common::{qerror, qinfo, qtrace};
use neqo_transport::{AppError, Connection};
use crate::{CloseType, Error, Http3StreamInfo, HttpRecvStreamEvents, RecvStreamEvents, Res};
use neqo_common::{qerror, qinfo, qtrace, Header};
use neqo_transport::{Connection, StreamId};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::convert::TryFrom;
@ -35,11 +34,11 @@ enum PushState {
headers: Vec<Header>,
},
OnlyPushStream {
stream_id: u64,
stream_id: StreamId,
events: Vec<Http3ClientEvent>,
},
Active {
stream_id: u64,
stream_id: StreamId,
headers: Vec<Header>,
},
Closed,
@ -177,7 +176,7 @@ impl PushController {
pub fn new_push_promise(
&mut self,
push_id: u64,
ref_stream_id: u64,
ref_stream_id: StreamId,
new_headers: Vec<Header>,
) -> Res<()> {
qtrace!(
@ -231,7 +230,7 @@ impl PushController {
}
}
pub fn add_new_push_stream(&mut self, push_id: u64, stream_id: u64) -> Res<bool> {
pub fn add_new_push_stream(&mut self, push_id: u64, stream_id: StreamId) -> Res<bool> {
qtrace!(
"A new push stream with push_id={} stream_id={}",
push_id,
@ -305,7 +304,7 @@ impl PushController {
}
PushState::OnlyPushStream { stream_id, .. }
| PushState::Active { stream_id, .. } => {
mem::drop(base_handler.stream_reset(
mem::drop(base_handler.stream_stop_sending(
conn,
stream_id,
Error::HttpRequestCancelled.code(),
@ -359,7 +358,7 @@ impl PushController {
Some(PushState::Active { stream_id, .. }) => {
self.conn_events.remove_events_for_push_id(push_id);
// Cancel the stream. the transport steam may already be done, so ignore an error.
mem::drop(base_handler.stream_reset(
mem::drop(base_handler.stream_stop_sending(
conn,
*stream_id,
Error::HttpRequestCancelled.code(),
@ -371,7 +370,7 @@ impl PushController {
}
}
pub fn push_stream_reset(&mut self, push_id: u64, app_error: AppError, reset_type: ResetType) {
pub fn push_stream_reset(&mut self, push_id: u64, close_type: CloseType) {
qtrace!("Push stream has been reset, push_id={}", push_id);
if let Some(push_state) = self.push_streams.get(push_id) {
@ -382,7 +381,7 @@ impl PushController {
PushState::Active { .. } => {
self.push_streams.close(push_id);
self.conn_events.remove_events_for_push_id(push_id);
if reset_type == ResetType::Local {
if let CloseType::LocalError(app_error) = close_type {
self.conn_events.push_reset(push_id, app_error);
} else {
self.conn_events.push_canceled(push_id);
@ -398,7 +397,7 @@ impl PushController {
}
}
pub fn get_active_stream_id(&mut self, push_id: u64) -> Option<u64> {
pub fn get_active_stream_id(&mut self, push_id: u64) -> Option<StreamId> {
match self.push_streams.get(push_id) {
Some(PushState::Active { stream_id, .. }) => Some(*stream_id),
_ => None,
@ -447,6 +446,11 @@ impl PushController {
}
}
/// `RecvPushEvents` relays a push stream events to `PushController`.
/// It informs `PushController` when a push stream is done or canceled.
/// Also when headers or data is ready and `PushController` decide whether to post
/// `PushHeaderReady` and `PushDataReadable` events or to postpone them if
/// a `push_promise` has not been yet received for the stream.
#[derive(Debug)]
pub(crate) struct RecvPushEvents {
push_id: u64,
@ -462,8 +466,36 @@ impl RecvPushEvents {
}
}
impl RecvMessageEvents for RecvPushEvents {
fn header_ready(&self, _stream_id: u64, headers: Vec<Header>, interim: bool, fin: bool) {
impl RecvStreamEvents for RecvPushEvents {
fn data_readable(&self, _stream_info: Http3StreamInfo) {
self.push_handler.borrow_mut().new_stream_event(
self.push_id,
Http3ClientEvent::PushDataReadable {
push_id: self.push_id,
},
);
}
fn recv_closed(&self, _stream_info: Http3StreamInfo, close_type: CloseType) {
match close_type {
CloseType::ResetApp(_) => {}
CloseType::ResetRemote(_) | CloseType::LocalError(_) => self
.push_handler
.borrow_mut()
.push_stream_reset(self.push_id, close_type),
CloseType::Done => self.push_handler.borrow_mut().close(self.push_id),
}
}
}
impl HttpRecvStreamEvents for RecvPushEvents {
fn header_ready(
&self,
_stream_info: Http3StreamInfo,
headers: Vec<Header>,
interim: bool,
fin: bool,
) {
self.push_handler.borrow_mut().new_stream_event(
self.push_id,
Http3ClientEvent::PushHeaderReady {
@ -474,15 +506,4 @@ impl RecvMessageEvents for RecvPushEvents {
},
);
}
fn data_readable(&self, _stream_id: u64) {
self.push_handler.borrow_mut().new_stream_event(
self.push_id,
Http3ClientEvent::PushDataReadable {
push_id: self.push_id,
},
);
}
fn reset(&self, _stream_id: u64, _error: AppError, _local: bool) {}
}

130
third_party/rust/neqo-http3/src/push_stream.rs поставляемый
Просмотреть файл

@ -1,130 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::priority::PriorityHandler;
use crate::push_controller::{PushController, RecvPushEvents};
use crate::recv_message::{MessageType, RecvMessage};
use crate::{Http3StreamType, HttpRecvStream, Priority, ReceiveOutput, RecvStream, Res, ResetType};
use neqo_qpack::decoder::QPackDecoder;
use neqo_transport::{AppError, Connection};
use std::cell::RefCell;
use std::fmt::Display;
use std::rc::Rc;
// The `PushController` keeps information about all push streams. Each push stream is responsible for contacting the
// `PushController` to consult it about the push state and to inform it when the push stream is done (this are signal
// from the peer: stream has been closed or reset). `PushController` handles CANCEL_PUSH frames and canceling
// push from applications and PUSH_PROMISE frames.
//
// `PushStream` is responsible for reading from a push stream.
// It is created when a new push stream is received.
//
// `PushStreams` are kept in Http3Connection::recv_streams the same as a normal request/response stream.
// Http3Connection and read_data is responsible for reading the push data.
//
// PushHeaderReady and PushDataReadable are posted through the `PushController` that may decide to postpone them if
// a push_promise has not been yet received for the stream.
//
// `PushStream` is responsible for removing itself from the `PushController`.
//
// `PushStream` may be reset from the peer in the same way as a request stream. The `PushStream` informs the
// `PushController` that will set the push state to closed and remove any push events.
#[derive(Debug)]
pub(crate) struct PushStream {
stream_id: u64,
push_id: u64,
response: RecvMessage,
push_handler: Rc<RefCell<PushController>>,
}
impl PushStream {
pub fn new(
stream_id: u64,
push_id: u64,
push_handler: Rc<RefCell<PushController>>,
qpack_decoder: Rc<RefCell<QPackDecoder>>,
priority: Priority,
) -> Self {
Self {
response: RecvMessage::new(
MessageType::Response,
stream_id,
qpack_decoder,
Box::new(RecvPushEvents::new(push_id, push_handler.clone())),
None,
PriorityHandler::new(true, priority),
),
stream_id,
push_id,
push_handler,
}
}
}
impl Display for PushStream {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(
f,
"Push stream {:?} push_id={}",
self.stream_id, self.push_id
)
}
}
impl RecvStream for PushStream {
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput> {
self.response.receive(conn)?;
if self.response.done() {
self.push_handler.borrow_mut().close(self.push_id);
}
Ok(ReceiveOutput::NoOutput)
}
fn done(&self) -> bool {
self.response.done()
}
fn stream_reset(&mut self, app_error: AppError, reset_type: ResetType) -> Res<()> {
match reset_type {
ResetType::App => {}
t => {
self.push_handler
.borrow_mut()
.push_stream_reset(self.push_id, app_error, t);
}
}
self.response.stream_reset(app_error, reset_type)?;
Ok(())
}
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::Push
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
Some(self)
}
}
impl HttpRecvStream for PushStream {
fn header_unblocked(&mut self, conn: &mut Connection) -> Res<()> {
self.receive(conn)?;
Ok(())
}
fn read_data(&mut self, conn: &mut Connection, buf: &mut [u8]) -> Res<(usize, bool)> {
let res = self.response.read_data(conn, buf);
if self.response.done() {
self.push_handler.borrow_mut().close(self.push_id);
}
res
}
fn priority_handler_mut(&mut self) -> &mut PriorityHandler {
self.response.priority_handler_mut()
}
}

5
third_party/rust/neqo-http3/src/qlog.rs поставляемый
Просмотреть файл

@ -9,8 +9,9 @@ use std::convert::TryFrom;
use qlog::{self, event::Event, H3DataRecipient};
use neqo_common::qlog::NeqoQlog;
use neqo_transport::StreamId;
pub fn h3_data_moved_up(qlog: &mut NeqoQlog, stream_id: u64, amount: usize) {
pub fn h3_data_moved_up(qlog: &mut NeqoQlog, stream_id: StreamId, amount: usize) {
qlog.add_event(|| {
Some(Event::h3_data_moved(
stream_id.to_string(),
@ -23,7 +24,7 @@ pub fn h3_data_moved_up(qlog: &mut NeqoQlog, stream_id: u64, amount: usize) {
});
}
pub fn h3_data_moved_down(qlog: &mut NeqoQlog, stream_id: u64, amount: usize) {
pub fn h3_data_moved_down(qlog: &mut NeqoQlog, stream_id: StreamId, amount: usize) {
qlog.add_event(|| {
Some(Event::h3_data_moved(
stream_id.to_string(),

Просмотреть файл

@ -4,46 +4,41 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::{
AppError, Error, Http3StreamType, HttpRecvStream, ReceiveOutput, RecvStream, Res, ResetType,
};
use crate::{CloseType, Error, Http3StreamType, ReceiveOutput, RecvStream, Res, Stream};
use neqo_qpack::QPackDecoder;
use neqo_transport::Connection;
use neqo_transport::{Connection, StreamId};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
pub struct DecoderRecvStream {
stream_id: u64,
stream_id: StreamId,
decoder: Rc<RefCell<QPackDecoder>>,
}
impl DecoderRecvStream {
pub fn new(stream_id: u64, decoder: Rc<RefCell<QPackDecoder>>) -> Self {
pub fn new(stream_id: StreamId, decoder: Rc<RefCell<QPackDecoder>>) -> Self {
Self { stream_id, decoder }
}
}
impl RecvStream for DecoderRecvStream {
fn stream_reset(&mut self, _error: AppError, _reset_type: ResetType) -> Res<()> {
Err(Error::HttpClosedCriticalStream)
}
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput> {
Ok(ReceiveOutput::UnblockedStreams(
self.decoder.borrow_mut().receive(conn, self.stream_id)?,
))
}
fn done(&self) -> bool {
false
}
impl Stream for DecoderRecvStream {
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::Decoder
}
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
None
impl RecvStream for DecoderRecvStream {
fn reset(&mut self, _close_type: CloseType) -> Res<()> {
Err(Error::HttpClosedCriticalStream)
}
fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
Ok((
ReceiveOutput::UnblockedStreams(
self.decoder.borrow_mut().receive(conn, self.stream_id)?,
),
false,
))
}
}

Просмотреть файл

@ -4,45 +4,37 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::{
AppError, Error, Http3StreamType, HttpRecvStream, ReceiveOutput, RecvStream, Res, ResetType,
};
use crate::{CloseType, Error, Http3StreamType, ReceiveOutput, RecvStream, Res, Stream};
use neqo_qpack::QPackEncoder;
use neqo_transport::Connection;
use neqo_transport::{Connection, StreamId};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
pub struct EncoderRecvStream {
stream_id: u64,
stream_id: StreamId,
encoder: Rc<RefCell<QPackEncoder>>,
}
impl EncoderRecvStream {
pub fn new(stream_id: u64, encoder: Rc<RefCell<QPackEncoder>>) -> Self {
pub fn new(stream_id: StreamId, encoder: Rc<RefCell<QPackEncoder>>) -> Self {
Self { stream_id, encoder }
}
}
impl RecvStream for EncoderRecvStream {
fn stream_reset(&mut self, _error: AppError, _reset_type: ResetType) -> Res<()> {
Err(Error::HttpClosedCriticalStream)
}
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput> {
self.encoder.borrow_mut().receive(conn, self.stream_id)?;
Ok(ReceiveOutput::NoOutput)
}
fn done(&self) -> bool {
false
}
impl Stream for EncoderRecvStream {
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::Encoder
}
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
None
impl RecvStream for EncoderRecvStream {
fn reset(&mut self, _close_type: CloseType) -> Res<()> {
Err(Error::HttpClosedCriticalStream)
}
fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
self.encoder.borrow_mut().receive(conn, self.stream_id)?;
Ok((ReceiveOutput::NoOutput, false))
}
}

Просмотреть файл

@ -4,17 +4,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::hframe::{HFrame, HFrameReader};
use crate::hframe::{HFrame, HFrameReader, H3_FRAME_TYPE_HEADERS};
use crate::push_controller::PushController;
use crate::{
qlog, Error, Header, Http3StreamType, HttpRecvStream, ReceiveOutput, RecvMessageEvents,
RecvStream, Res, ResetType,
headers_checks::{headers_valid, is_interim},
priority::PriorityHandler,
qlog, CloseType, Error, Http3StreamInfo, Http3StreamType, HttpRecvStream, HttpRecvStreamEvents,
MessageType, ReceiveOutput, RecvStream, Res, Stream,
};
use crate::priority::PriorityHandler;
use neqo_common::{qdebug, qinfo, qtrace};
use neqo_common::{qdebug, qinfo, qtrace, Header};
use neqo_qpack::decoder::QPackDecoder;
use neqo_transport::{AppError, Connection};
use neqo_transport::{Connection, StreamId};
use std::cell::RefCell;
use std::cmp::min;
use std::collections::VecDeque;
@ -22,17 +22,12 @@ use std::convert::TryFrom;
use std::fmt::Debug;
use std::rc::Rc;
const PSEUDO_HEADER_STATUS: u8 = 0x1;
const PSEUDO_HEADER_METHOD: u8 = 0x2;
const PSEUDO_HEADER_SCHEME: u8 = 0x4;
const PSEUDO_HEADER_AUTHORITY: u8 = 0x8;
const PSEUDO_HEADER_PATH: u8 = 0x10;
const REGULAR_HEADER: u8 = 0x80;
#[derive(Debug)]
pub enum MessageType {
Request,
Response,
#[allow(clippy::module_name_repetitions)]
pub struct RecvMessageInfo {
pub message_type: MessageType,
pub stream_type: Http3StreamType,
pub stream_id: StreamId,
pub header_frame_type_read: bool,
}
/*
@ -50,6 +45,10 @@ pub enum MessageType {
* ClosePending : waiting for app to pick up data, after that we can delete
* the TransactionClient.
* Closed
* ExtendedConnect: this request is for a WebTransport session. In this
* state RecvMessage will not be treated as a HTTP
* stream anymore. It is waiting to be transformed
* into WebTransport session or to be closed.
*/
#[derive(Debug)]
enum RecvMessageState {
@ -60,6 +59,7 @@ enum RecvMessageState {
WaitingForFinAfterTrailers { frame_reader: HFrameReader },
ClosePending, // Close must first be read by application
Closed,
ExtendedConnect,
}
#[derive(Debug)]
@ -72,10 +72,11 @@ struct PushInfo {
pub(crate) struct RecvMessage {
state: RecvMessageState,
message_type: MessageType,
stream_type: Http3StreamType,
qpack_decoder: Rc<RefCell<QPackDecoder>>,
conn_events: Box<dyn RecvMessageEvents>,
conn_events: Box<dyn HttpRecvStreamEvents>,
push_handler: Option<Rc<RefCell<PushController>>>,
stream_id: u64,
stream_id: StreamId,
priority_handler: PriorityHandler,
blocked_push_promise: VecDeque<PushInfo>,
}
@ -88,22 +89,26 @@ impl ::std::fmt::Display for RecvMessage {
impl RecvMessage {
pub fn new(
message_type: MessageType,
stream_id: u64,
message_info: &RecvMessageInfo,
qpack_decoder: Rc<RefCell<QPackDecoder>>,
conn_events: Box<dyn RecvMessageEvents>,
conn_events: Box<dyn HttpRecvStreamEvents>,
push_handler: Option<Rc<RefCell<PushController>>>,
priority_handler: PriorityHandler,
) -> Self {
Self {
state: RecvMessageState::WaitingForResponseHeaders {
frame_reader: HFrameReader::new(),
frame_reader: if message_info.header_frame_type_read {
HFrameReader::new_with_type(H3_FRAME_TYPE_HEADERS)
} else {
HFrameReader::new()
},
},
message_type,
message_type: message_info.message_type,
stream_type: message_info.stream_type,
qpack_decoder,
conn_events,
push_handler,
stream_id,
stream_id: message_info.stream_id,
priority_handler,
blocked_push_promise: VecDeque::new(),
}
@ -151,9 +156,12 @@ impl RecvMessage {
fn add_headers(&mut self, mut headers: Vec<Header>, fin: bool) -> Res<()> {
qtrace!([self], "Add new headers fin={}", fin);
let interim = self.is_interim(&headers)?;
self.headers_valid(&headers)?;
if matches!(self.message_type, MessageType::Response) {
let interim = match self.message_type {
MessageType::Request => false,
MessageType::Response => is_interim(&headers)?,
};
headers_valid(&headers, self.message_type)?;
if self.message_type == MessageType::Response {
headers.retain(Header::is_allowed_for_response);
}
@ -161,12 +169,27 @@ impl RecvMessage {
return Err(Error::HttpGeneralProtocolStream);
}
self.conn_events
.header_ready(self.stream_id, headers, interim, fin);
let is_web_transport = self.message_type == MessageType::Request
&& headers
.iter()
.any(|h| h.name() == ":method" && h.value() == "CONNECT")
&& headers
.iter()
.any(|h| h.name() == ":protocol" && h.value() == "webtransport");
if is_web_transport {
self.conn_events
.extended_connect_new_session(self.stream_id, headers);
} else {
self.conn_events
.header_ready(self.get_stream_info(), headers, interim, fin);
}
if fin {
self.set_closed();
} else {
self.state = if interim {
self.state = if is_web_transport {
RecvMessageState::ExtendedConnect
} else if interim {
RecvMessageState::WaitingForResponseHeaders {
frame_reader: HFrameReader::new(),
}
@ -192,7 +215,7 @@ impl RecvMessage {
RecvMessageState::WaitingForData { .. }
| RecvMessageState::WaitingForFinAfterTrailers { .. } => {
if post_readable_event {
self.conn_events.data_readable(self.stream_id);
self.conn_events.data_readable(self.get_stream_info());
}
}
_ => unreachable!("Closing an already closed transaction."),
@ -299,7 +322,10 @@ impl RecvMessage {
.decode_header_block(header_block, self.stream_id)?;
if let Some(headers) = d_headers {
self.add_headers(headers, done)?;
if matches!(self.state, RecvMessageState::Closed) {
if matches!(
self.state,
RecvMessageState::Closed | RecvMessageState::ExtendedConnect
) {
break Ok(());
}
} else {
@ -309,13 +335,17 @@ impl RecvMessage {
}
RecvMessageState::ReadingData { .. } => {
if post_readable_event {
self.conn_events.data_readable(self.stream_id);
self.conn_events.data_readable(self.get_stream_info());
}
break Ok(());
}
RecvMessageState::ClosePending | RecvMessageState::Closed => {
panic!("Stream readable after being closed!");
}
RecvMessageState::ExtendedConnect => {
// Ignore read event, this request is waiting to be picked up by a new WebTransportSession
break Ok(());
}
};
}
}
@ -327,6 +357,8 @@ impl RecvMessage {
.cancel_stream(self.stream_id);
}
self.state = RecvMessageState::Closed;
self.conn_events
.recv_closed(self.get_stream_info(), CloseType::Done);
}
fn closing(&self) -> bool {
@ -336,152 +368,38 @@ impl RecvMessage {
)
}
fn is_interim(&self, headers: &[Header]) -> Res<bool> {
match self.message_type {
MessageType::Response => {
let status = headers.iter().find(|h| h.name() == ":status");
if let Some(h) = status {
#[allow(clippy::map_err_ignore)]
let status_code = h.value().parse::<i32>().map_err(|_| Error::InvalidHeader)?;
Ok((100..200).contains(&status_code))
} else {
Err(Error::InvalidHeader)
}
}
MessageType::Request => Ok(false),
}
fn get_stream_info(&self) -> Http3StreamInfo {
Http3StreamInfo::new(self.stream_id, Http3StreamType::Http)
}
}
fn track_pseudo(name: &str, state: &mut u8, message_type: &MessageType) -> Res<bool> {
let (pseudo, bit) = if name.starts_with(':') {
if *state & REGULAR_HEADER != 0 {
return Err(Error::InvalidHeader);
}
let bit = match message_type {
MessageType::Response => match name {
":status" => PSEUDO_HEADER_STATUS,
_ => return Err(Error::InvalidHeader),
},
MessageType::Request => match name {
":method" => PSEUDO_HEADER_METHOD,
":scheme" => PSEUDO_HEADER_SCHEME,
":authority" => PSEUDO_HEADER_AUTHORITY,
":path" => PSEUDO_HEADER_PATH,
_ => return Err(Error::InvalidHeader),
},
};
(true, bit)
} else {
(false, REGULAR_HEADER)
};
if *state & bit == 0 || !pseudo {
*state |= bit;
Ok(pseudo)
} else {
Err(Error::InvalidHeader)
}
}
fn headers_valid(&self, headers: &[Header]) -> Res<()> {
let mut method_value: Option<&str> = None;
let mut pseudo_state = 0;
for header in headers {
let is_pseudo =
Self::track_pseudo(header.name(), &mut pseudo_state, &self.message_type)?;
let mut bytes = header.name().bytes();
if is_pseudo {
if header.name() == ":method" {
method_value = Some(header.value());
}
let _ = bytes.next();
}
if bytes.any(|b| matches!(b, 0 | 0x10 | 0x13 | 0x3a | 0x41..=0x5a)) {
return Err(Error::InvalidHeader); // illegal characters.
}
}
// Clear the regular header bit, since we only check pseudo headers below.
pseudo_state &= !REGULAR_HEADER;
let pseudo_header_mask = match self.message_type {
MessageType::Response => PSEUDO_HEADER_STATUS,
MessageType::Request => {
if method_value == Some(&"CONNECT".to_string()) {
PSEUDO_HEADER_METHOD | PSEUDO_HEADER_AUTHORITY
} else {
PSEUDO_HEADER_METHOD | PSEUDO_HEADER_SCHEME | PSEUDO_HEADER_PATH
}
}
};
if pseudo_state & pseudo_header_mask != pseudo_header_mask {
return Err(Error::InvalidHeader);
}
Ok(())
impl Stream for RecvMessage {
fn stream_type(&self) -> Http3StreamType {
self.stream_type
}
}
impl RecvStream for RecvMessage {
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput> {
fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
self.receive_internal(conn, true)?;
Ok(ReceiveOutput::NoOutput)
Ok((
ReceiveOutput::NoOutput,
matches!(self.state, RecvMessageState::Closed),
))
}
fn done(&self) -> bool {
matches!(self.state, RecvMessageState::Closed)
}
fn stream_reset(&mut self, app_error: AppError, reset_type: ResetType) -> Res<()> {
fn reset(&mut self, close_type: CloseType) -> Res<()> {
if !self.closing() || !self.blocked_push_promise.is_empty() {
self.qpack_decoder
.borrow_mut()
.cancel_stream(self.stream_id);
}
match reset_type {
ResetType::Local => {
self.conn_events.reset(self.stream_id, app_error, true);
}
ResetType::Remote => {
self.conn_events.reset(self.stream_id, app_error, false);
}
ResetType::App => {}
}
self.conn_events
.recv_closed(self.get_stream_info(), close_type);
self.state = RecvMessageState::Closed;
Ok(())
}
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::Http
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
Some(self)
}
}
impl HttpRecvStream for RecvMessage {
fn header_unblocked(&mut self, conn: &mut Connection) -> Res<()> {
while let Some(p) = self.blocked_push_promise.front() {
if let Some(headers) = self
.qpack_decoder
.borrow_mut()
.decode_header_block(&p.header_block, self.stream_id)?
{
self.push_handler
.as_ref()
.ok_or(Error::HttpFrameUnexpected)?
.borrow_mut()
.new_push_promise(p.push_id, self.stream_id, headers)?;
self.blocked_push_promise.pop_front();
} else {
return Ok(());
}
}
self.receive_internal(conn, true)
}
fn read_data(&mut self, conn: &mut Connection, buf: &mut [u8]) -> Res<(usize, bool)> {
let mut written = 0;
loop {
@ -523,7 +441,42 @@ impl HttpRecvStream for RecvMessage {
}
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
Some(self)
}
}
impl HttpRecvStream for RecvMessage {
fn header_unblocked(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
while let Some(p) = self.blocked_push_promise.front() {
if let Some(headers) = self
.qpack_decoder
.borrow_mut()
.decode_header_block(&p.header_block, self.stream_id)?
{
self.push_handler
.as_ref()
.ok_or(Error::HttpFrameUnexpected)?
.borrow_mut()
.new_push_promise(p.push_id, self.stream_id, headers)?;
self.blocked_push_promise.pop_front();
} else {
return Ok((ReceiveOutput::NoOutput, false));
}
}
self.receive(conn)
}
fn priority_handler_mut(&mut self) -> &mut PriorityHandler {
&mut self.priority_handler
}
fn set_new_listener(&mut self, conn_events: Box<dyn HttpRecvStreamEvents>) {
self.conn_events = conn_events;
}
fn extended_connect_wait_for_response(&self) -> bool {
matches!(self.state, RecvMessageState::ExtendedConnect)
}
}

Просмотреть файл

@ -5,15 +5,19 @@
// except according to those terms.
use crate::hframe::HFrame;
use crate::qlog;
use crate::Header;
use crate::{Error, Res};
use crate::{
headers_checks::{headers_valid, is_interim, trailers_valid},
qlog, BufferedStream, CloseType, Error, Http3StreamInfo, Http3StreamType, HttpSendStream, Res,
SendStream, SendStreamEvents, Stream,
};
use neqo_common::{qdebug, qinfo, qtrace, Encoder};
use neqo_common::{qdebug, qinfo, qtrace, Encoder, Header, MessageType};
use neqo_qpack::encoder::QPackEncoder;
use neqo_transport::{AppError, Connection};
use neqo_transport::{Connection, StreamId};
use std::cell::RefCell;
use std::cmp::min;
use std::fmt::Debug;
use std::rc::Rc;
const MAX_DATA_HEADER_SIZE_2: usize = (1 << 6) - 1; // Maximal amount of data with DATA frame header size 2
const MAX_DATA_HEADER_SIZE_2_LIMIT: usize = MAX_DATA_HEADER_SIZE_2 + 3; // 63 + 3 (size of the next buffer data frame header)
@ -22,246 +26,237 @@ const MAX_DATA_HEADER_SIZE_3_LIMIT: usize = MAX_DATA_HEADER_SIZE_3 + 5; // 16383
const MAX_DATA_HEADER_SIZE_5: usize = (1 << 30) - 1; // Maximal amount of data with DATA frame header size 3
const MAX_DATA_HEADER_SIZE_5_LIMIT: usize = MAX_DATA_HEADER_SIZE_5 + 9; // 1073741823 + 9 (size of the next buffer data frame header)
pub(crate) trait SendMessageEvents: Debug {
fn data_writable(&self, stream_id: u64);
fn remove_send_side_event(&self, stream_id: u64);
fn stop_sending(&self, stream_id: u64, app_err: AppError);
/// A HTTP message, request and response, consists of headers, optional data and an optional
/// trailer header block. This state machine does not reflect what was already sent to the
/// transport layer but only reflect what has been supplied to the `SendMessage`.It is
/// represented by the following states:
/// `WaitingForHeaders` - the headers have not been supplied yet. In this state only a
/// request/response header can be added. When headers are supplied
/// the state changes to `WaitingForData`. A response may contain
/// multiple messages only if all but the last one are informational(1xx)
/// responses. The informational responses can only contain headers,
/// therefore after an informational response is received the state
/// machine states in `WaitingForHeaders` state.
/// `WaitingForData` - in this state, data and trailers can be supplied. This state means that
/// a request or response header is already supplied.
/// `TrailersSet` - trailers have been supplied. At this stage no more data or headers can be
/// supply only a fin.
/// `Done` - in this state no more data or headers can be added. This state is entered when the
/// message is closed.
#[derive(Debug, PartialEq)]
enum MessageState {
WaitingForHeaders,
WaitingForData,
TrailersSet,
Done,
}
/*
* SendMessage states:
* Uninitialized
* Initialized : Headers are present but still not encoded. A message body may be present as well.
* The client side sends a message body using the send_body() function that directly
* writes into a transport stream. The server side sets headers and body when
* initializing a send message (TODO: make server use send_body as well)
* SendingInitialMessage : sending headers and maybe message body. From here we may switch to
* SendingData or Closed (if the app does not want to send data and
* has already closed the send stream).
* SendingData : We are sending request data until the app closes the stream.
* Closed
*/
#[derive(PartialEq, Debug)]
enum SendMessageState {
Uninitialized,
Initialized {
headers: Vec<Header>,
data: Option<Vec<u8>>,
fin: bool,
},
SendingInitialMessage {
buf: Vec<u8>,
fin: bool,
},
SendingData,
Closed,
}
impl SendMessageState {
pub fn is_sending_closed(&self) -> bool {
match self {
Self::Initialized { fin, .. } | Self::SendingInitialMessage { fin, .. } => *fin,
Self::SendingData => false,
_ => true,
impl MessageState {
fn new_headers(&mut self, headers: &[Header], message_type: MessageType) -> Res<()> {
match &self {
Self::WaitingForHeaders => {
// This is only a debug assertion because we expect that application will
// do the right thing here and performing the check costs.
debug_assert!(headers_valid(headers, message_type).is_ok());
match message_type {
MessageType::Request => {
*self = Self::WaitingForData;
}
MessageType::Response => {
if !is_interim(headers)? {
*self = Self::WaitingForData;
}
}
}
Ok(())
}
Self::WaitingForData => {
trailers_valid(headers)?;
*self = Self::TrailersSet;
Ok(())
}
Self::TrailersSet | Self::Done => Err(Error::InvalidInput),
}
}
pub fn done(&self) -> bool {
matches!(self, Self::Closed)
fn new_data(&self) -> Res<()> {
if &Self::WaitingForData == self {
Ok(())
} else {
Err(Error::InvalidInput)
}
}
pub fn is_state_sending_data(&self) -> bool {
matches!(self, Self::SendingData)
fn fin(&mut self) -> Res<()> {
match &self {
Self::WaitingForHeaders | Self::Done => Err(Error::InvalidInput),
Self::WaitingForData | Self::TrailersSet => {
*self = Self::Done;
Ok(())
}
}
}
fn done(&self) -> bool {
&Self::Done == self
}
}
#[derive(Debug)]
pub(crate) struct SendMessage {
state: SendMessageState,
stream_id: u64,
conn_events: Box<dyn SendMessageEvents>,
state: MessageState,
message_type: MessageType,
stream_type: Http3StreamType,
stream: BufferedStream,
encoder: Rc<RefCell<QPackEncoder>>,
conn_events: Box<dyn SendStreamEvents>,
}
impl SendMessage {
pub fn new(stream_id: u64, conn_events: Box<dyn SendMessageEvents>) -> Self {
qinfo!("Create a request stream_id={}", stream_id);
Self {
state: SendMessageState::Uninitialized,
stream_id,
conn_events,
}
}
pub fn new_with_headers(
stream_id: u64,
headers: Vec<Header>,
conn_events: Box<dyn SendMessageEvents>,
pub fn new(
message_type: MessageType,
stream_type: Http3StreamType,
stream_id: StreamId,
encoder: Rc<RefCell<QPackEncoder>>,
conn_events: Box<dyn SendStreamEvents>,
) -> Self {
qinfo!("Create a request stream_id={}", stream_id);
Self {
state: SendMessageState::Initialized {
headers,
data: None,
fin: false,
},
stream_id,
state: MessageState::WaitingForHeaders,
message_type,
stream_type,
stream: BufferedStream::new(stream_id),
encoder,
conn_events,
}
}
pub fn set_message(&mut self, headers: &[Header], data: Option<&[u8]>) -> Res<()> {
if !matches!(self.state, SendMessageState::Uninitialized) {
return Err(Error::AlreadyInitialized);
}
self.state = SendMessageState::Initialized {
headers: headers.to_vec(),
data: data.map(|d| d.to_vec()),
fin: true,
};
Ok(())
}
pub fn send_body(&mut self, conn: &mut Connection, buf: &[u8]) -> Res<usize> {
qtrace!(
[self],
"send_body: state={:?} len={}",
self.state,
buf.len()
);
match self.state {
SendMessageState::Uninitialized
| SendMessageState::Initialized { .. }
| SendMessageState::SendingInitialMessage { .. } => Ok(0),
SendMessageState::SendingData => {
let available = conn
.stream_avail_send_space(self.stream_id)
.map_err(|e| Error::map_stream_send_errors(&e))?;
if available <= 2 {
return Ok(0);
}
let to_send;
if available <= MAX_DATA_HEADER_SIZE_2_LIMIT {
// 63 + 3
to_send = min(min(buf.len(), available - 2), MAX_DATA_HEADER_SIZE_2);
} else if available <= MAX_DATA_HEADER_SIZE_3_LIMIT {
// 16383 + 5
to_send = min(min(buf.len(), available - 3), MAX_DATA_HEADER_SIZE_3);
} else if available <= MAX_DATA_HEADER_SIZE_5 {
// 1073741823 + 9
to_send = min(min(buf.len(), available - 5), MAX_DATA_HEADER_SIZE_5_LIMIT);
} else {
to_send = min(buf.len(), available - 9);
}
qinfo!(
[self],
"send_request_body: available={} to_send={}.",
available,
to_send
);
let data_frame = HFrame::Data {
len: to_send as u64,
};
let mut enc = Encoder::default();
data_frame.encode(&mut enc);
let sent_fh = conn
.stream_send(self.stream_id, &enc)
.map_err(|e| Error::map_stream_send_errors(&e))?;
debug_assert_eq!(sent_fh, enc.len());
let sent = conn
.stream_send(self.stream_id, &buf[..to_send])
.map_err(|e| Error::map_stream_send_errors(&e))?;
qlog::h3_data_moved_down(&mut conn.qlog_mut(), self.stream_id, to_send);
Ok(sent)
}
SendMessageState::Closed => Err(Error::AlreadyClosed),
}
}
pub fn done(&self) -> bool {
self.state.done()
}
pub fn stream_writable(&self) {
if self.state.is_state_sending_data() {
self.conn_events.data_writable(self.stream_id);
}
}
/// # Errors
/// `ClosedCriticalStream` if the encoder stream is closed.
/// `InternalError` if an unexpected error occurred.
fn ensure_encoded(&mut self, conn: &mut Connection, encoder: &mut QPackEncoder) -> Res<()> {
if let SendMessageState::Initialized { headers, data, fin } = &self.state {
qdebug!([self], "Encoding headers");
let header_block = encoder.encode_header_block(conn, headers, self.stream_id)?;
let hframe = HFrame::Headers {
header_block: header_block.to_vec(),
};
let mut d = Encoder::default();
hframe.encode(&mut d);
if let Some(buf) = data {
qdebug!([self], "Encoding data");
let d_frame = HFrame::Data {
len: buf.len() as u64,
};
d_frame.encode(&mut d);
d.encode(buf);
}
fn encode(
encoder: &mut QPackEncoder,
headers: &[Header],
conn: &mut Connection,
stream_id: StreamId,
) -> Vec<u8> {
qdebug!("Encoding headers");
let header_block = encoder.encode_header_block(conn, headers, stream_id);
let hframe = HFrame::Headers {
header_block: header_block.to_vec(),
};
let mut d = Encoder::default();
hframe.encode(&mut d);
d.into()
}
self.state = SendMessageState::SendingInitialMessage {
buf: d.into(),
fin: *fin,
};
fn stream_id(&self) -> StreamId {
Option::<StreamId>::from(&self.stream).unwrap()
}
fn get_stream_info(&self) -> Http3StreamInfo {
Http3StreamInfo::new(self.stream_id(), Http3StreamType::Http)
}
}
impl Stream for SendMessage {
fn stream_type(&self) -> Http3StreamType {
self.stream_type
}
}
impl SendStream for SendMessage {
fn send_data(&mut self, conn: &mut Connection, buf: &[u8]) -> Res<usize> {
qtrace!([self], "send_body: len={}", buf.len());
self.state.new_data()?;
self.stream.send_buffer(conn)?;
if self.stream.has_buffered_data() {
return Ok(0);
}
let available = conn
.stream_avail_send_space(self.stream_id())
.map_err(|e| Error::map_stream_send_errors(&e.into()))?;
if available <= 2 {
return Ok(0);
}
let to_send = if available <= MAX_DATA_HEADER_SIZE_2_LIMIT {
// 63 + 3
min(min(buf.len(), available - 2), MAX_DATA_HEADER_SIZE_2)
} else if available <= MAX_DATA_HEADER_SIZE_3_LIMIT {
// 16383 + 5
min(min(buf.len(), available - 3), MAX_DATA_HEADER_SIZE_3)
} else if available <= MAX_DATA_HEADER_SIZE_5 {
// 1073741823 + 9
min(min(buf.len(), available - 5), MAX_DATA_HEADER_SIZE_5_LIMIT)
} else {
min(buf.len(), available - 9)
};
qinfo!(
[self],
"send_request_body: available={} to_send={}.",
available,
to_send
);
let data_frame = HFrame::Data {
len: to_send as u64,
};
let mut enc = Encoder::default();
data_frame.encode(&mut enc);
let sent_fh = self
.stream
.send_atomic(conn, &enc)
.map_err(|e| Error::map_stream_send_errors(&e))?;
debug_assert!(sent_fh);
let sent = self
.stream
.send_atomic(conn, &buf[..to_send])
.map_err(|e| Error::map_stream_send_errors(&e))?;
debug_assert!(sent);
qlog::h3_data_moved_down(&mut conn.qlog_mut(), self.stream_id(), to_send);
Ok(to_send)
}
fn done(&self) -> bool {
!self.stream.has_buffered_data() && self.state.done()
}
fn stream_writable(&self) {
if !self.stream.has_buffered_data() && !self.state.done() {
// DataWritable is just a signal for an application to try to write more data,
// if writing fails it is fine. Therefore we do not need to properly check
// whether more credits are available on the transport layer.
self.conn_events.data_writable(self.get_stream_info());
}
Ok(())
}
/// # Errors
/// `ClosedCriticalStream` if the encoder stream is closed.
/// `InternalError` if an unexpected error occurred.
/// `InvalidStreamId` if the stream does not exist,
/// `AlreadyClosed` if the stream has already been closed.
/// `TransportStreamDoesNotExist` if the transport stream does not exist (this may happen if `process_output`
/// has not been called when needed, and HTTP3 layer has not picked up the info that the stream has been closed.)
pub fn send(&mut self, conn: &mut Connection, encoder: &mut QPackEncoder) -> Res<()> {
self.ensure_encoded(conn, encoder)?;
fn send(&mut self, conn: &mut Connection) -> Res<()> {
let sent = Error::map_error(self.stream.send_buffer(conn), Error::HttpInternal(5))?;
qlog::h3_data_moved_down(&mut conn.qlog_mut(), self.stream_id(), sent);
let label = if ::log::log_enabled!(::log::Level::Debug) {
format!("{}", self)
} else {
String::new()
};
if let SendMessageState::SendingInitialMessage { ref mut buf, fin } = self.state {
let sent = Error::map_error(
conn.stream_send(self.stream_id, buf),
Error::HttpInternal(5),
)?;
qlog::h3_data_moved_down(&mut conn.qlog_mut(), self.stream_id, sent);
qtrace!([label], "{} bytes sent", sent);
if sent == buf.len() {
if fin {
Error::map_error(
conn.stream_close_send(self.stream_id),
Error::HttpInternal(6),
)?;
self.state = SendMessageState::Closed;
qtrace!([label], "done sending request");
} else {
self.state = SendMessageState::SendingData;
self.conn_events.data_writable(self.stream_id);
qtrace!([label], "change to state SendingData");
}
qtrace!([self], "{} bytes sent", sent);
if !self.stream.has_buffered_data() {
if self.state.done() {
Error::map_error(
conn.stream_close_send(self.stream_id()),
Error::HttpInternal(6),
)?;
qtrace!([self], "done sending request");
} else {
let b = buf.split_off(sent);
*buf = b;
// DataWritable is just a signal for an application to try to write more data,
// if writing fails it is fine. Therefore we do not need to properly check
// whether more credits are available on the transport layer.
self.conn_events.data_writable(self.get_stream_info());
}
}
Ok(())
@ -270,39 +265,53 @@ impl SendMessage {
// SendMessage owns headers and sends them. It may also own data for the server side.
// This method returns if they're still being sent. Request body (if any) is sent by
// http client afterwards using `send_request_body` after receiving DataWritable event.
pub fn has_data_to_send(&self) -> bool {
matches!(
self.state,
SendMessageState::Initialized { .. } | SendMessageState::SendingInitialMessage { .. }
)
fn has_data_to_send(&self) -> bool {
self.stream.has_buffered_data()
}
pub fn close(&mut self, conn: &mut Connection) -> Res<()> {
match self.state {
SendMessageState::SendingInitialMessage { ref mut fin, .. }
| SendMessageState::Initialized { ref mut fin, .. } => {
*fin = true;
}
_ => {
self.state = SendMessageState::Closed;
conn.stream_close_send(self.stream_id)?;
}
fn close(&mut self, conn: &mut Connection) -> Res<()> {
self.state.fin()?;
if !self.stream.has_buffered_data() {
conn.stream_close_send(self.stream_id())?;
}
self.conn_events.remove_send_side_event(self.stream_id);
self.conn_events
.send_closed(self.get_stream_info(), CloseType::Done);
Ok(())
}
pub fn stop_sending(&mut self, app_err: AppError) {
if !self.state.is_sending_closed() {
self.conn_events.remove_send_side_event(self.stream_id);
self.conn_events.stop_sending(self.stream_id, app_err);
fn handle_stop_sending(&mut self, close_type: CloseType) {
if !self.state.done() {
self.conn_events
.send_closed(self.get_stream_info(), close_type);
}
}
fn http_stream(&mut self) -> Option<&mut dyn HttpSendStream> {
Some(self)
}
}
impl HttpSendStream for SendMessage {
fn send_headers(&mut self, headers: &[Header], conn: &mut Connection) -> Res<()> {
self.state.new_headers(headers, self.message_type)?;
let buf = SendMessage::encode(
&mut self.encoder.borrow_mut(),
headers,
conn,
self.stream_id(),
);
self.stream.buffer(&buf);
Ok(())
}
fn set_new_listener(&mut self, conn_events: Box<dyn SendStreamEvents>) {
self.conn_events = conn_events;
}
}
impl ::std::fmt::Display for SendMessage {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "SendMesage {}", self.stream_id)
write!(f, "SendMesage {}", self.stream_id())
}
}

337
third_party/rust/neqo-http3/src/server.rs поставляемый
Просмотреть файл

@ -9,16 +9,15 @@
use crate::connection::Http3State;
use crate::connection_server::Http3ServerHandler;
use crate::server_connection_events::Http3ServerConnEvent;
use crate::server_events::{ClientRequestStream, Http3ServerEvent, Http3ServerEvents};
use crate::server_events::{
Http3OrWebTransportStream, Http3ServerEvent, Http3ServerEvents, WebTransportRequest,
};
use crate::settings::HttpZeroRttChecker;
use crate::Res;
use crate::{Http3Parameters, Http3StreamInfo, Res};
use neqo_common::{qtrace, Datagram};
use neqo_crypto::{AntiReplay, Cipher, PrivateKey, PublicKey, ZeroRttChecker};
use neqo_qpack::QpackSettings;
use neqo_transport::server::{ActiveConnectionRef, Server, ValidateAddress};
use neqo_transport::{
tparams::PreferredAddress, ConnectionIdGenerator, ConnectionParameters, Output,
};
use neqo_transport::{tparams::PreferredAddress, ConnectionIdGenerator, Output};
use std::cell::RefCell;
use std::cell::RefMut;
use std::collections::HashMap;
@ -32,7 +31,7 @@ const MAX_EVENT_DATA_SIZE: usize = 1024;
pub struct Http3Server {
server: Server,
qpack_settings: QpackSettings,
http3_parameters: Http3Parameters,
http3_handlers: HashMap<ActiveConnectionRef, HandlerRef>,
events: Http3ServerEvents,
}
@ -53,7 +52,7 @@ impl Http3Server {
protocols: &[impl AsRef<str>],
anti_replay: AntiReplay,
cid_manager: Rc<RefCell<dyn ConnectionIdGenerator>>,
qpack_settings: QpackSettings,
http3_parameters: Http3Parameters,
zero_rtt_checker: Option<Box<dyn ZeroRttChecker>>,
) -> Res<Self> {
Ok(Self {
@ -63,11 +62,11 @@ impl Http3Server {
protocols,
anti_replay,
zero_rtt_checker
.unwrap_or_else(|| Box::new(HttpZeroRttChecker::new(qpack_settings))),
.unwrap_or_else(|| Box::new(HttpZeroRttChecker::new(http3_parameters))),
cid_manager,
ConnectionParameters::default(),
*http3_parameters.get_connection_parameters(),
)?,
qpack_settings,
http3_parameters,
http3_handlers: HashMap::new(),
events: Http3ServerEvents::default(),
})
@ -148,59 +147,95 @@ impl Http3Server {
active_conns
.iter()
.for_each(|conn| self.server.add_to_waiting(conn.clone()));
let qpack_settings = self.qpack_settings;
for mut conn in active_conns {
let handler = self
.http3_handlers
.entry(conn.clone())
.or_insert_with(|| Rc::new(RefCell::new(Http3ServerHandler::new(qpack_settings))));
self.process_events(&mut conn, now);
}
}
fn process_events(&mut self, conn: &mut ActiveConnectionRef, now: Instant) {
let mut remove = false;
let http3_parameters = self.http3_parameters;
{
let handler = self.http3_handlers.entry(conn.clone()).or_insert_with(|| {
Rc::new(RefCell::new(Http3ServerHandler::new(http3_parameters)))
});
handler
.borrow_mut()
.process_http3(&mut conn.borrow_mut(), now);
let mut remove = false;
{
let mut handler_borrowed = handler.borrow_mut();
while let Some(e) = handler_borrowed.next_event() {
match e {
Http3ServerConnEvent::Headers {
stream_id,
headers,
fin,
} => self.events.headers(
ClientRequestStream::new(conn.clone(), handler.clone(), stream_id),
headers,
fin,
),
Http3ServerConnEvent::DataReadable { stream_id } => {
prepare_data(
stream_id,
&mut handler_borrowed,
&mut conn,
handler,
now,
&mut self.events,
);
}
Http3ServerConnEvent::StateChange(state) => {
self.events
.connection_state_change(conn.clone(), state.clone());
if let Http3State::Closed { .. } = state {
remove = true;
}
}
Http3ServerConnEvent::PriorityUpdate {
stream_id,
priority,
} => {
self.events.priority_update(stream_id, priority);
let mut handler_borrowed = handler.borrow_mut();
while let Some(e) = handler_borrowed.next_event() {
match e {
Http3ServerConnEvent::Headers {
stream_info,
headers,
fin,
} => self.events.headers(
Http3OrWebTransportStream::new(conn.clone(), handler.clone(), stream_info),
headers,
fin,
),
Http3ServerConnEvent::DataReadable { stream_info } => {
prepare_data(
stream_info,
&mut handler_borrowed,
conn,
handler,
now,
&mut self.events,
);
}
Http3ServerConnEvent::DataWritable { stream_info } => self
.events
.data_writable(conn.clone(), handler.clone(), stream_info),
Http3ServerConnEvent::StreamReset { stream_info, error } => {
self.events
.stream_reset(conn.clone(), handler.clone(), stream_info, error);
}
Http3ServerConnEvent::StreamStopSending { stream_info, error } => {
self.events.stream_stop_sending(
conn.clone(),
handler.clone(),
stream_info,
error,
);
}
Http3ServerConnEvent::StateChange(state) => {
self.events
.connection_state_change(conn.clone(), state.clone());
if let Http3State::Closed { .. } = state {
remove = true;
}
}
Http3ServerConnEvent::PriorityUpdate {
stream_id,
priority,
} => {
self.events.priority_update(stream_id, priority);
}
Http3ServerConnEvent::ExtendedConnect { stream_id, headers } => {
self.events.webtransport_new_session(
WebTransportRequest::new(conn.clone(), handler.clone(), stream_id),
headers,
);
}
Http3ServerConnEvent::ExtendedConnectClosed {
stream_id, error, ..
} => self.events.webtransport_session_closed(
WebTransportRequest::new(conn.clone(), handler.clone(), stream_id),
error,
),
Http3ServerConnEvent::ExtendedConnectNewStream(stream_info) => self
.events
.webtransport_new_stream(Http3OrWebTransportStream::new(
conn.clone(),
handler.clone(),
stream_info,
)),
}
}
if remove {
self.http3_handlers.remove(&conn.clone());
}
}
if remove {
self.http3_handlers.remove(&conn.clone());
}
}
@ -224,7 +259,7 @@ impl Http3Server {
}
}
fn prepare_data(
stream_id: u64,
stream_info: Http3StreamInfo,
handler_borrowed: &mut RefMut<Http3ServerHandler>,
conn: &mut ActiveConnectionRef,
handler: &HandlerRef,
@ -233,18 +268,19 @@ fn prepare_data(
) {
loop {
let mut data = vec![0; MAX_EVENT_DATA_SIZE];
let res =
handler_borrowed.read_request_data(&mut conn.borrow_mut(), now, stream_id, &mut data);
let res = handler_borrowed.read_data(
&mut conn.borrow_mut(),
now,
stream_info.stream_id(),
&mut data,
);
if let Ok((amount, fin)) = res {
if amount > 0 {
if amount > 0 || fin {
if amount < MAX_EVENT_DATA_SIZE {
data.resize(amount, 0);
}
events.data(
ClientRequestStream::new(conn.clone(), handler.clone(), stream_id),
data,
fin,
);
events.data(conn.clone(), handler.clone(), stream_info, data, fin);
}
if amount < MAX_EVENT_DATA_SIZE || fin {
break;
@ -260,14 +296,13 @@ fn prepare_data(
#[cfg(test)]
mod tests {
use super::{Http3Server, Http3ServerEvent, Http3State, Rc, RefCell};
use crate::{Error, HFrame, Header, Priority};
use crate::{Error, HFrame, Header, Http3Parameters, Priority};
use neqo_common::event::Provider;
use neqo_common::Encoder;
use neqo_crypto::{AuthenticationStatus, ZeroRttCheckResult, ZeroRttChecker};
use neqo_qpack::encoder::QPackEncoder;
use neqo_qpack::QpackSettings;
use neqo_qpack::{encoder::QPackEncoder, QpackSettings};
use neqo_transport::{
Connection, ConnectionError, ConnectionEvent, State, StreamType, ZeroRttState,
Connection, ConnectionError, ConnectionEvent, State, StreamId, StreamType, ZeroRttState,
};
use std::collections::HashMap;
use std::mem;
@ -283,7 +318,14 @@ mod tests {
max_blocked_streams: 100,
};
pub fn create_server(settings: QpackSettings) -> Http3Server {
fn http3params(qpack_settings: QpackSettings) -> Http3Parameters {
Http3Parameters::default()
.max_table_size_encoder(qpack_settings.max_table_size_encoder)
.max_table_size_decoder(qpack_settings.max_table_size_decoder)
.max_blocked_streams(qpack_settings.max_blocked_streams)
}
pub fn create_server(conn_params: Http3Parameters) -> Http3Server {
fixture_init();
Http3Server::new(
now(),
@ -291,7 +333,7 @@ mod tests {
DEFAULT_ALPN,
anti_replay(),
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
settings,
conn_params,
None,
)
.expect("create a server")
@ -299,7 +341,7 @@ mod tests {
/// Create a http3 server with default configuration.
pub fn default_server() -> Http3Server {
create_server(DEFAULT_SETTINGS)
create_server(http3params(DEFAULT_SETTINGS))
}
fn assert_closed(hconn: &mut Http3Server, expected: &Error) {
@ -339,12 +381,12 @@ mod tests {
assert!(!hconn.events().any(closed));
}
const CLIENT_SIDE_CONTROL_STREAM_ID: u64 = 2;
const CLIENT_SIDE_ENCODER_STREAM_ID: u64 = 6;
const CLIENT_SIDE_DECODER_STREAM_ID: u64 = 10;
const SERVER_SIDE_CONTROL_STREAM_ID: u64 = 3;
const SERVER_SIDE_ENCODER_STREAM_ID: u64 = 7;
const SERVER_SIDE_DECODER_STREAM_ID: u64 = 11;
const CLIENT_SIDE_CONTROL_STREAM_ID: StreamId = StreamId::new(2);
const CLIENT_SIDE_ENCODER_STREAM_ID: StreamId = StreamId::new(6);
const CLIENT_SIDE_DECODER_STREAM_ID: StreamId = StreamId::new(10);
const SERVER_SIDE_CONTROL_STREAM_ID: StreamId = StreamId::new(3);
const SERVER_SIDE_ENCODER_STREAM_ID: StreamId = StreamId::new(7);
const SERVER_SIDE_DECODER_STREAM_ID: StreamId = StreamId::new(11);
fn connect_transport(server: &mut Http3Server, client: &mut Connection, resume: bool) {
let c1 = client.process(None, now()).dgram();
@ -384,9 +426,9 @@ mod tests {
match e {
ConnectionEvent::NewStream { stream_id } => {
assert!(
(stream_id.as_u64() == SERVER_SIDE_CONTROL_STREAM_ID)
|| (stream_id.as_u64() == SERVER_SIDE_ENCODER_STREAM_ID)
|| (stream_id.as_u64() == SERVER_SIDE_DECODER_STREAM_ID)
(stream_id == SERVER_SIDE_CONTROL_STREAM_ID)
|| (stream_id == SERVER_SIDE_ENCODER_STREAM_ID)
|| (stream_id == SERVER_SIDE_DECODER_STREAM_ID)
);
assert_eq!(stream_id.stream_type(), StreamType::UniDi);
}
@ -457,7 +499,7 @@ mod tests {
struct PeerConnection {
conn: Connection,
control_stream_id: u64,
control_stream_id: StreamId,
}
impl PeerConnection {
@ -491,7 +533,7 @@ mod tests {
);
assert_eq!(sent, Ok(9));
let mut encoder = QPackEncoder::new(
QpackSettings {
&QpackSettings {
max_table_size_encoder: 100,
max_table_size_decoder: 0,
max_blocked_streams: 0,
@ -499,7 +541,7 @@ mod tests {
true,
);
encoder.add_send_stream(neqo_trans_conn.stream_create(StreamType::UniDi).unwrap());
encoder.send(&mut neqo_trans_conn).unwrap();
encoder.send_encoder_updates(&mut neqo_trans_conn).unwrap();
let decoder_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
sent = neqo_trans_conn.stream_send(decoder_stream, &[0x3]);
assert_eq!(sent, Ok(1));
@ -567,11 +609,11 @@ mod tests {
assert_closed(&mut hconn, &Error::HttpFrameUnexpected);
}
fn priority_update_check_id(stream_id: u64, valid: bool) {
fn priority_update_check_id(stream_id: StreamId, valid: bool) {
let (mut hconn, mut peer_conn) = connect();
// send a priority update
let frame = HFrame::PriorityUpdateRequest {
element_id: stream_id,
element_id: stream_id.as_u64(),
priority: Priority::default(),
};
let mut e = Encoder::default();
@ -590,28 +632,28 @@ mod tests {
#[test]
fn test_priority_update_valid_id_0() {
// Client-Initiated, Bidirectional
priority_update_check_id(0, true);
priority_update_check_id(StreamId::new(0), true);
}
#[test]
fn test_priority_update_invalid_id_1() {
// Server-Initiated, Bidirectional
priority_update_check_id(1, false);
priority_update_check_id(StreamId::new(1), false);
}
#[test]
fn test_priority_update_invalid_id_2() {
// Client-Initiated, Unidirectional
priority_update_check_id(2, false);
priority_update_check_id(StreamId::new(2), false);
}
#[test]
fn test_priority_update_invalid_id_3() {
// Server-Initiated, Unidirectional
priority_update_check_id(3, false);
priority_update_check_id(StreamId::new(3), false);
}
#[test]
fn test_priority_update_invalid_large_id() {
// Server-Initiated, Unidirectional (dividable by 4)
priority_update_check_id(1_000_000_000, false);
// Server-Initiated, Unidirectional (divisible by 4)
priority_update_check_id(StreamId::new(1_000_000_000), false);
}
fn test_wrong_frame_on_control_stream(v: &[u8]) {
@ -853,24 +895,27 @@ mod tests {
headers_frames += 1;
}
Http3ServerEvent::Data {
mut request,
mut stream,
data,
fin,
} => {
assert_eq!(data, REQUEST_BODY);
assert!(fin);
request
.set_response(
&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
],
RESPONSE_BODY,
)
stream
.send_headers(&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
.unwrap();
stream.send_data(RESPONSE_BODY).unwrap();
data_received += 1;
}
Http3ServerEvent::StateChange { .. } | Http3ServerEvent::PriorityUpdate { .. } => {}
Http3ServerEvent::DataWritable { .. }
| Http3ServerEvent::StreamReset { .. }
| Http3ServerEvent::StreamStopSending { .. }
| Http3ServerEvent::StateChange { .. }
| Http3ServerEvent::PriorityUpdate { .. }
| Http3ServerEvent::WebTransport(_) => {}
}
}
assert_eq!(headers_frames, 1);
@ -895,30 +940,33 @@ mod tests {
while let Some(event) = hconn.next_event() {
match event {
Http3ServerEvent::Headers {
mut request,
mut stream,
headers,
fin,
} => {
check_request_header(&headers);
assert!(!fin);
headers_frames += 1;
request
stream
.stream_stop_sending(Error::HttpNoError.code())
.unwrap();
request
.set_response(
&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
],
RESPONSE_BODY,
)
stream
.send_headers(&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
.unwrap();
stream.send_data(RESPONSE_BODY).unwrap();
}
Http3ServerEvent::Data { .. } => {
panic!("We should not have a Data event");
}
Http3ServerEvent::StateChange { .. } | Http3ServerEvent::PriorityUpdate { .. } => {}
Http3ServerEvent::DataWritable { .. }
| Http3ServerEvent::StreamReset { .. }
| Http3ServerEvent::StreamStopSending { .. }
| Http3ServerEvent::StateChange { .. }
| Http3ServerEvent::PriorityUpdate { .. }
| Http3ServerEvent::WebTransport(_) => {}
}
}
let out = hconn.process(None, now());
@ -940,7 +988,12 @@ mod tests {
Http3ServerEvent::Data { .. } => {
panic!("We should not have a Data event");
}
Http3ServerEvent::StateChange { .. } | Http3ServerEvent::PriorityUpdate { .. } => {}
Http3ServerEvent::DataWritable { .. }
| Http3ServerEvent::StreamReset { .. }
| Http3ServerEvent::StreamStopSending { .. }
| Http3ServerEvent::StateChange { .. }
| Http3ServerEvent::PriorityUpdate { .. }
| Http3ServerEvent::WebTransport(_) => {}
}
}
assert_eq!(headers_frames, 1);
@ -965,21 +1018,26 @@ mod tests {
while let Some(event) = hconn.next_event() {
match event {
Http3ServerEvent::Headers {
mut request,
mut stream,
headers,
fin,
} => {
check_request_header(&headers);
assert!(!fin);
headers_frames += 1;
request
.stream_reset(Error::HttpRequestRejected.code())
stream
.cancel_fetch(Error::HttpRequestRejected.code())
.unwrap();
}
Http3ServerEvent::Data { .. } => {
panic!("We should not have a Data event");
}
Http3ServerEvent::StateChange { .. } | Http3ServerEvent::PriorityUpdate { .. } => {}
Http3ServerEvent::DataWritable { .. }
| Http3ServerEvent::StreamReset { .. }
| Http3ServerEvent::StreamStopSending { .. }
| Http3ServerEvent::StateChange { .. }
| Http3ServerEvent::PriorityUpdate { .. }
| Http3ServerEvent::WebTransport(_) => {}
}
}
let out = hconn.process(None, now());
@ -1089,7 +1147,7 @@ mod tests {
/// Perform a handshake, then another with the token from the first.
/// The second should always resume, but it might not always accept early data.
fn zero_rtt_with_settings(settings: QpackSettings, zero_rtt: &ZeroRttState) {
fn zero_rtt_with_settings(conn_params: Http3Parameters, zero_rtt: &ZeroRttState) {
let (_, mut client) = connect();
let token = client.events().find_map(|e| {
if let ConnectionEvent::ResumptionToken(token) = e {
@ -1100,7 +1158,7 @@ mod tests {
});
assert!(token.is_some());
let mut server = create_server(settings);
let mut server = create_server(conn_params);
let mut client = default_client();
client.enable_resumption(now(), token.unwrap()).unwrap();
@ -1111,17 +1169,17 @@ mod tests {
#[test]
fn zero_rtt() {
zero_rtt_with_settings(DEFAULT_SETTINGS, &ZeroRttState::AcceptedClient);
zero_rtt_with_settings(http3params(DEFAULT_SETTINGS), &ZeroRttState::AcceptedClient);
}
/// A larger QPACK decoder table size isn't an impediment to 0-RTT.
#[test]
fn zero_rtt_larger_decoder_table() {
zero_rtt_with_settings(
QpackSettings {
http3params(QpackSettings {
max_table_size_decoder: DEFAULT_SETTINGS.max_table_size_decoder + 1,
..DEFAULT_SETTINGS
},
}),
&ZeroRttState::AcceptedClient,
);
}
@ -1130,10 +1188,10 @@ mod tests {
#[test]
fn zero_rtt_smaller_decoder_table() {
zero_rtt_with_settings(
QpackSettings {
http3params(QpackSettings {
max_table_size_decoder: DEFAULT_SETTINGS.max_table_size_decoder - 1,
..DEFAULT_SETTINGS
},
}),
&ZeroRttState::Rejected,
);
}
@ -1142,10 +1200,10 @@ mod tests {
#[test]
fn zero_rtt_more_blocked_streams() {
zero_rtt_with_settings(
QpackSettings {
http3params(QpackSettings {
max_blocked_streams: DEFAULT_SETTINGS.max_blocked_streams + 1,
..DEFAULT_SETTINGS
},
}),
&ZeroRttState::AcceptedClient,
);
}
@ -1154,10 +1212,10 @@ mod tests {
#[test]
fn zero_rtt_fewer_blocked_streams() {
zero_rtt_with_settings(
QpackSettings {
http3params(QpackSettings {
max_blocked_streams: DEFAULT_SETTINGS.max_blocked_streams - 1,
..DEFAULT_SETTINGS
},
}),
&ZeroRttState::Rejected,
);
}
@ -1166,10 +1224,10 @@ mod tests {
#[test]
fn zero_rtt_smaller_encoder_table() {
zero_rtt_with_settings(
QpackSettings {
http3params(QpackSettings {
max_table_size_encoder: DEFAULT_SETTINGS.max_table_size_encoder - 1,
..DEFAULT_SETTINGS
},
}),
&ZeroRttState::AcceptedClient,
);
}
@ -1196,14 +1254,19 @@ mod tests {
let mut requests = HashMap::new();
while let Some(event) = hconn.next_event() {
match event {
Http3ServerEvent::Headers { request, .. } => {
assert!(requests.get(&request).is_none());
requests.insert(request, 0);
Http3ServerEvent::Headers { stream, .. } => {
assert!(requests.get(&stream).is_none());
requests.insert(stream, 0);
}
Http3ServerEvent::Data { request, .. } => {
assert!(requests.get(&request).is_some());
Http3ServerEvent::Data { stream, .. } => {
assert!(requests.get(&stream).is_some());
}
Http3ServerEvent::StateChange { .. } | Http3ServerEvent::PriorityUpdate { .. } => {}
Http3ServerEvent::DataWritable { .. }
| Http3ServerEvent::StreamReset { .. }
| Http3ServerEvent::StreamStopSending { .. }
| Http3ServerEvent::StateChange { .. }
| Http3ServerEvent::PriorityUpdate { .. }
| Http3ServerEvent::WebTransport(_) => {}
}
}
assert_eq!(requests.len(), 2);
@ -1226,7 +1289,7 @@ mod tests {
DEFAULT_ALPN,
anti_replay(),
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
DEFAULT_SETTINGS,
http3params(DEFAULT_SETTINGS),
Some(Box::new(RejectZeroRtt::default())),
)
.expect("create a server");

Просмотреть файл

@ -5,12 +5,13 @@
// except according to those terms.
use crate::connection::Http3State;
use crate::send_message::SendMessageEvents;
use crate::RecvMessageEvents;
use crate::{Header, Priority};
use crate::{
features::extended_connect::{ExtendedConnectEvents, ExtendedConnectType},
CloseType, Http3StreamInfo, HttpRecvStreamEvents, Priority, RecvStreamEvents, SendStreamEvents,
};
use neqo_common::Header;
use neqo_transport::AppError;
use neqo_transport::StreamId;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
@ -19,23 +20,41 @@ use std::rc::Rc;
pub(crate) enum Http3ServerConnEvent {
/// Headers are ready.
Headers {
stream_id: u64,
stream_info: Http3StreamInfo,
headers: Vec<Header>,
fin: bool,
},
PriorityUpdate {
stream_id: u64,
stream_id: StreamId,
priority: Priority,
},
/// Request data is ready.
DataReadable {
stream_id: u64,
stream_info: Http3StreamInfo,
},
DataWritable {
stream_info: Http3StreamInfo,
},
StreamReset {
stream_info: Http3StreamInfo,
error: AppError,
},
StreamStopSending {
stream_info: Http3StreamInfo,
error: AppError,
},
//TODO: This is never used. Do we need it?
// Peer reset the stream.
//Reset { stream_id: u64, error: AppError },
/// Connection state change.
StateChange(Http3State),
ExtendedConnect {
stream_id: StreamId,
headers: Vec<Header>,
},
ExtendedConnectClosed {
connect_type: ExtendedConnectType,
stream_id: StreamId,
error: Option<AppError>,
},
ExtendedConnectNewStream(Http3StreamInfo),
}
#[derive(Debug, Default, Clone)]
@ -43,32 +62,78 @@ pub(crate) struct Http3ServerConnEvents {
events: Rc<RefCell<VecDeque<Http3ServerConnEvent>>>,
}
impl RecvMessageEvents for Http3ServerConnEvents {
impl SendStreamEvents for Http3ServerConnEvents {
fn send_closed(&self, stream_info: Http3StreamInfo, close_type: CloseType) {
if close_type != CloseType::Done {
self.insert(Http3ServerConnEvent::StreamStopSending {
stream_info,
error: close_type.error().unwrap(),
});
}
}
fn data_writable(&self, stream_info: Http3StreamInfo) {
self.insert(Http3ServerConnEvent::DataWritable { stream_info });
}
}
impl RecvStreamEvents for Http3ServerConnEvents {
/// Add a new `DataReadable` event
fn data_readable(&self, stream_info: Http3StreamInfo) {
self.insert(Http3ServerConnEvent::DataReadable { stream_info });
}
fn recv_closed(&self, stream_info: Http3StreamInfo, close_type: CloseType) {
if close_type != CloseType::Done {
self.remove_events_for_stream_id(stream_info);
self.insert(Http3ServerConnEvent::StreamReset {
stream_info,
error: close_type.error().unwrap(),
});
}
}
}
impl HttpRecvStreamEvents for Http3ServerConnEvents {
/// Add a new `HeaderReady` event.
fn header_ready(&self, stream_id: u64, headers: Vec<Header>, _interim: bool, fin: bool) {
fn header_ready(
&self,
stream_info: Http3StreamInfo,
headers: Vec<Header>,
_interim: bool,
fin: bool,
) {
self.insert(Http3ServerConnEvent::Headers {
stream_id,
stream_info,
headers,
fin,
});
}
/// Add a new `DataReadable` event
fn data_readable(&self, stream_id: u64) {
self.insert(Http3ServerConnEvent::DataReadable { stream_id });
fn extended_connect_new_session(&self, stream_id: StreamId, headers: Vec<Header>) {
self.insert(Http3ServerConnEvent::ExtendedConnect { stream_id, headers });
}
fn reset(&self, _stream_id: u64, _error: AppError, _local: bool) {}
}
impl SendMessageEvents for Http3ServerConnEvents {
fn data_writable(&self, _stream_id: u64) {
// Curently not used on the server side.
impl ExtendedConnectEvents for Http3ServerConnEvents {
fn session_start(&self, _connect_type: ExtendedConnectType, _stream_id: StreamId) {}
fn session_end(
&self,
connect_type: ExtendedConnectType,
stream_id: StreamId,
error: Option<AppError>,
) {
self.insert(Http3ServerConnEvent::ExtendedConnectClosed {
connect_type,
stream_id,
error,
});
}
fn remove_send_side_event(&self, _stream_id: u64) {}
fn stop_sending(&self, _stream_id: u64, _app_err: AppError) {}
fn extended_connect_new_stream(&self, stream_info: Http3StreamInfo) {
self.insert(Http3ServerConnEvent::ExtendedConnectNewStream(stream_info));
}
}
impl Http3ServerConnEvents {
@ -95,17 +160,17 @@ impl Http3ServerConnEvents {
self.insert(Http3ServerConnEvent::StateChange(state));
}
pub fn priority_update(&self, stream_id: u64, priority: Priority) {
pub fn priority_update(&self, stream_id: StreamId, priority: Priority) {
self.insert(Http3ServerConnEvent::PriorityUpdate {
stream_id,
priority,
});
}
pub fn remove_events_for_stream_id(&self, stream_id: u64) {
fn remove_events_for_stream_id(&self, stream_info: Http3StreamInfo) {
self.remove(|evt| {
matches!(evt,
Http3ServerConnEvent::Headers { stream_id: x, .. } | Http3ServerConnEvent::DataReadable { stream_id: x, .. } if *x == stream_id)
Http3ServerConnEvent::Headers { stream_info: x, .. } | Http3ServerConnEvent::DataReadable { stream_info: x, .. } if *x == stream_info)
});
}
}

Просмотреть файл

@ -8,124 +8,352 @@
use crate::connection::Http3State;
use crate::connection_server::Http3ServerHandler;
use crate::{Header, Priority, Res};
use neqo_common::{qdebug, qinfo};
use crate::{Http3StreamInfo, Http3StreamType, Priority, Res};
use neqo_common::{qdebug, qinfo, Header};
use neqo_transport::server::ActiveConnectionRef;
use neqo_transport::{AppError, Connection};
use neqo_transport::{AppError, Connection, StreamId, StreamType};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct ClientRequestStream {
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_id: u64,
pub struct StreamHandler {
pub conn: ActiveConnectionRef,
pub handler: Rc<RefCell<Http3ServerHandler>>,
pub stream_info: Http3StreamInfo,
}
impl ::std::fmt::Display for ClientRequestStream {
impl ::std::fmt::Display for StreamHandler {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let conn: &Connection = &self.conn.borrow();
write!(
f,
"Http3 server conn={:?} stream_id={}",
conn, self.stream_id
)
write!(f, "conn={} stream_info={:?}", conn, self.stream_info)
}
}
impl ClientRequestStream {
pub(crate) fn new(
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_id: u64,
) -> Self {
Self {
conn,
handler,
stream_id,
}
impl std::hash::Hash for StreamHandler {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.conn.hash(state);
state.write_u64(self.stream_info.stream_id().as_u64());
state.finish();
}
}
impl PartialEq for StreamHandler {
fn eq(&self, other: &Self) -> bool {
self.conn == other.conn && self.stream_info.stream_id() == other.stream_info.stream_id()
}
}
impl Eq for StreamHandler {}
impl StreamHandler {
pub fn stream_id(&self) -> StreamId {
self.stream_info.stream_id()
}
/// Supply a response to a request.
/// Supply a response header to a request.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn set_response(&mut self, headers: &[Header], data: &[u8]) -> Res<()> {
qinfo!([self], "Set new response.");
self.handler
.borrow_mut()
.set_response(self.stream_id, headers, data)
pub fn send_headers(&mut self, headers: &[Header]) -> Res<()> {
self.handler.borrow_mut().send_headers(
self.stream_id(),
headers,
&mut self.conn.borrow_mut(),
)
}
/// Request a peer to stop sending a request.
/// Supply response data to a request.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn send_data(&mut self, buf: &[u8]) -> Res<usize> {
self.handler
.borrow_mut()
.send_data(self.stream_id(), buf, &mut self.conn.borrow_mut())
}
/// Close sending side.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn stream_close_send(&mut self) -> Res<()> {
self.handler
.borrow_mut()
.stream_close_send(self.stream_id(), &mut self.conn.borrow_mut())
}
/// Request a peer to stop sending a stream.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn stream_stop_sending(&mut self, app_error: AppError) -> Res<()> {
qdebug!(
[self],
"stop sending stream_id:{} error:{}.",
self.stream_id,
self.stream_info.stream_id(),
app_error
);
self.conn
.borrow_mut()
.stream_stop_sending(self.stream_id, app_error)?;
Ok(())
self.handler.borrow_mut().stream_stop_sending(
self.stream_info.stream_id(),
app_error,
&mut self.conn.borrow_mut(),
)
}
/// Reset sending side of a stream.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn stream_reset_send(&mut self, app_error: AppError) -> Res<()> {
qdebug!(
[self],
"reset send stream_id:{} error:{}.",
self.stream_info.stream_id(),
app_error
);
self.handler.borrow_mut().stream_reset_send(
self.stream_info.stream_id(),
app_error,
&mut self.conn.borrow_mut(),
)
}
/// Reset a stream/request.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore
pub fn stream_reset(&mut self, app_error: AppError) -> Res<()> {
pub fn cancel_fetch(&mut self, app_error: AppError) -> Res<()> {
qdebug!([self], "reset error:{}.", app_error);
self.handler.borrow_mut().stream_reset(
&mut self.conn.borrow_mut(),
self.stream_id,
self.handler.borrow_mut().cancel_fetch(
self.stream_info.stream_id(),
app_error,
&mut self.conn.borrow_mut(),
)
}
}
impl std::hash::Hash for ClientRequestStream {
#[derive(Debug, Clone)]
pub struct Http3OrWebTransportStream {
stream_handler: StreamHandler,
}
impl ::std::fmt::Display for Http3OrWebTransportStream {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Stream server {:?}", self.stream_handler)
}
}
impl Http3OrWebTransportStream {
pub(crate) fn new(
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_info: Http3StreamInfo,
) -> Self {
Self {
stream_handler: StreamHandler {
conn,
handler,
stream_info,
},
}
}
/// Supply a response header to a request.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn send_headers(&mut self, headers: &[Header]) -> Res<()> {
self.stream_handler.send_headers(headers)
}
/// Supply response data to a request.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn send_data(&mut self, data: &[u8]) -> Res<usize> {
qinfo!([self], "Set new response.");
self.stream_handler.send_data(data)
}
/// Close sending side.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn stream_close_send(&mut self) -> Res<()> {
qinfo!([self], "Set new response.");
self.stream_handler.stream_close_send()
}
}
impl Deref for Http3OrWebTransportStream {
type Target = StreamHandler;
#[must_use]
fn deref(&self) -> &Self::Target {
&self.stream_handler
}
}
impl DerefMut for Http3OrWebTransportStream {
fn deref_mut(&mut self) -> &mut StreamHandler {
&mut self.stream_handler
}
}
impl std::hash::Hash for Http3OrWebTransportStream {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.conn.hash(state);
state.write_u64(self.stream_id);
self.stream_handler.hash(state);
state.finish();
}
}
impl PartialEq for ClientRequestStream {
impl PartialEq for Http3OrWebTransportStream {
fn eq(&self, other: &Self) -> bool {
self.conn == other.conn && self.stream_id == other.stream_id
self.stream_handler == other.stream_handler
}
}
impl Eq for ClientRequestStream {}
impl Eq for Http3OrWebTransportStream {}
#[derive(Debug, Clone)]
pub struct WebTransportRequest {
stream_handler: StreamHandler,
}
impl ::std::fmt::Display for WebTransportRequest {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "WebTransport session {}", self.stream_handler)
}
}
impl WebTransportRequest {
pub(crate) fn new(
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_id: StreamId,
) -> Self {
Self {
stream_handler: StreamHandler {
conn,
handler,
stream_info: Http3StreamInfo::new(stream_id, Http3StreamType::Http),
},
}
}
/// 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<()> {
qinfo!([self], "Set a response for a WebTransport session.");
self.stream_handler
.handler
.borrow_mut()
.webtransport_session_accept(
&mut self.stream_handler.conn.borrow_mut(),
self.stream_handler.stream_info.stream_id(),
accept,
)
}
#[must_use]
pub fn stream_id(&self) -> StreamId {
self.stream_handler.stream_id()
}
/// Close sending side.
/// # Errors
/// It may return `InvalidStreamId` if a stream does not exist anymore.
pub fn create_stream(&mut self, stream_type: StreamType) -> Res<Http3OrWebTransportStream> {
let session_id = self.stream_handler.stream_id();
let id = self
.stream_handler
.handler
.borrow_mut()
.webtransport_create_stream(
&mut self.stream_handler.conn.borrow_mut(),
session_id,
stream_type,
)?;
Ok(Http3OrWebTransportStream::new(
self.stream_handler.conn.clone(),
self.stream_handler.handler.clone(),
Http3StreamInfo::new(id, Http3StreamType::WebTransport(session_id)),
))
}
}
impl Deref for WebTransportRequest {
type Target = StreamHandler;
#[must_use]
fn deref(&self) -> &Self::Target {
&self.stream_handler
}
}
impl DerefMut for WebTransportRequest {
fn deref_mut(&mut self) -> &mut StreamHandler {
&mut self.stream_handler
}
}
impl std::hash::Hash for WebTransportRequest {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.stream_handler.hash(state);
state.finish();
}
}
impl PartialEq for WebTransportRequest {
fn eq(&self, other: &Self) -> bool {
self.stream_handler == other.stream_handler
}
}
impl Eq for WebTransportRequest {}
#[derive(Debug, Clone)]
pub enum WebTransportServerEvent {
NewSession {
session: WebTransportRequest,
headers: Vec<Header>,
},
SessionClosed {
session: WebTransportRequest,
error: Option<AppError>,
},
NewStream(Http3OrWebTransportStream),
}
#[derive(Debug, Clone)]
pub enum Http3ServerEvent {
/// Headers are ready.
Headers {
request: ClientRequestStream,
stream: Http3OrWebTransportStream,
headers: Vec<Header>,
fin: bool,
},
/// Request data is ready.
Data {
request: ClientRequestStream,
stream: Http3OrWebTransportStream,
data: Vec<u8>,
fin: bool,
},
DataWritable {
stream: Http3OrWebTransportStream,
},
StreamReset {
stream: Http3OrWebTransportStream,
error: AppError,
},
StreamStopSending {
stream: Http3OrWebTransportStream,
error: AppError,
},
/// When individual connection change state. It is only used for tests.
StateChange {
conn: ActiveConnectionRef,
state: Http3State,
},
PriorityUpdate {
stream_id: u64,
stream_id: StreamId,
priority: Priority,
},
WebTransport(WebTransportServerEvent),
}
#[derive(Debug, Default, Clone)]
@ -154,9 +382,14 @@ impl Http3ServerEvents {
}
/// Insert a `Headers` event.
pub(crate) fn headers(&self, request: ClientRequestStream, headers: Vec<Header>, fin: bool) {
pub(crate) fn headers(
&self,
request: Http3OrWebTransportStream,
headers: Vec<Header>,
fin: bool,
) {
self.insert(Http3ServerEvent::Headers {
request,
stream: request,
headers,
fin,
});
@ -168,14 +401,88 @@ impl Http3ServerEvents {
}
/// Insert a `Data` event.
pub(crate) fn data(&self, request: ClientRequestStream, data: Vec<u8>, fin: bool) {
self.insert(Http3ServerEvent::Data { request, data, fin });
pub(crate) fn data(
&self,
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_info: Http3StreamInfo,
data: Vec<u8>,
fin: bool,
) {
self.insert(Http3ServerEvent::Data {
stream: Http3OrWebTransportStream::new(conn, handler, stream_info),
data,
fin,
});
}
pub(crate) fn priority_update(&self, stream_id: u64, priority: Priority) {
pub(crate) fn data_writable(
&self,
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_info: Http3StreamInfo,
) {
self.insert(Http3ServerEvent::DataWritable {
stream: Http3OrWebTransportStream::new(conn, handler, stream_info),
});
}
pub(crate) fn stream_reset(
&self,
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_info: Http3StreamInfo,
error: AppError,
) {
self.insert(Http3ServerEvent::StreamReset {
stream: Http3OrWebTransportStream::new(conn, handler, stream_info),
error,
});
}
pub(crate) fn stream_stop_sending(
&self,
conn: ActiveConnectionRef,
handler: Rc<RefCell<Http3ServerHandler>>,
stream_info: Http3StreamInfo,
error: AppError,
) {
self.insert(Http3ServerEvent::StreamStopSending {
stream: Http3OrWebTransportStream::new(conn, handler, stream_info),
error,
});
}
pub(crate) fn priority_update(&self, stream_id: StreamId, priority: Priority) {
self.insert(Http3ServerEvent::PriorityUpdate {
stream_id,
priority,
});
}
pub(crate) fn webtransport_new_session(
&self,
session: WebTransportRequest,
headers: Vec<Header>,
) {
self.insert(Http3ServerEvent::WebTransport(
WebTransportServerEvent::NewSession { session, headers },
));
}
pub(crate) fn webtransport_session_closed(
&self,
session: WebTransportRequest,
error: Option<AppError>,
) {
self.insert(Http3ServerEvent::WebTransport(
WebTransportServerEvent::SessionClosed { session, error },
));
}
pub(crate) fn webtransport_new_stream(&self, stream: Http3OrWebTransportStream) {
self.insert(Http3ServerEvent::WebTransport(
WebTransportServerEvent::NewStream(stream),
));
}
}

62
third_party/rust/neqo-http3/src/settings.rs поставляемый
Просмотреть файл

@ -6,10 +6,9 @@
#![allow(clippy::module_name_repetitions)]
use crate::{Error, Res};
use crate::{Error, Http3Parameters, Res};
use neqo_common::{Decoder, Encoder};
use neqo_crypto::{ZeroRttCheckResult, ZeroRttChecker};
use neqo_qpack::QpackSettings;
use std::ops::Deref;
type SettingsType = u64;
@ -21,6 +20,7 @@ const SETTINGS_ZERO_RTT_VERSION: u64 = 1;
const SETTINGS_MAX_HEADER_LIST_SIZE: SettingsType = 0x6;
const SETTINGS_QPACK_MAX_TABLE_CAPACITY: SettingsType = 0x1;
const SETTINGS_QPACK_BLOCKED_STREAMS: SettingsType = 0x7;
const SETTINGS_ENABLE_WEB_TRANSPORT: SettingsType = 0x2b60_3742;
pub const H3_RESERVED_SETTINGS: &[SettingsType] = &[0x2, 0x3, 0x4, 0x5];
@ -29,12 +29,15 @@ pub enum HSettingType {
MaxHeaderListSize,
MaxTableCapacity,
BlockedStreams,
EnableWebTransport,
}
fn hsetting_default(setting_type: HSettingType) -> u64 {
match setting_type {
HSettingType::MaxHeaderListSize => 1 << 62,
HSettingType::MaxTableCapacity | HSettingType::BlockedStreams => 0,
HSettingType::MaxTableCapacity
| HSettingType::BlockedStreams
| HSettingType::EnableWebTransport => 0,
}
}
@ -88,6 +91,10 @@ impl HSettings {
enc_inner.encode_varint(SETTINGS_QPACK_BLOCKED_STREAMS as u64);
enc_inner.encode_varint(iter.value);
}
HSettingType::EnableWebTransport => {
enc_inner.encode_varint(SETTINGS_ENABLE_WEB_TRANSPORT as u64);
enc_inner.encode_varint(iter.value);
}
}
}
});
@ -113,6 +120,9 @@ impl HSettings {
(Some(SETTINGS_QPACK_BLOCKED_STREAMS), Some(value)) => self
.settings
.push(HSetting::new(HSettingType::BlockedStreams, value)),
(Some(SETTINGS_ENABLE_WEB_TRANSPORT), Some(value)) => self
.settings
.push(HSetting::new(HSettingType::EnableWebTransport, value)),
// other supported settings here
(Some(_), Some(_)) => {} // ignore unknown setting, it is fine.
_ => return Err(Error::NotEnoughData),
@ -129,27 +139,50 @@ impl Deref for HSettings {
}
}
impl From<&Http3Parameters> for HSettings {
fn from(conn_param: &Http3Parameters) -> Self {
Self {
settings: vec![
HSetting {
setting_type: HSettingType::MaxTableCapacity,
value: conn_param.get_max_table_size_decoder(),
},
HSetting {
setting_type: HSettingType::BlockedStreams,
value: u64::from(conn_param.get_max_blocked_streams()),
},
HSetting {
setting_type: HSettingType::EnableWebTransport,
value: u64::from(conn_param.get_webtransport()),
},
],
}
}
}
#[derive(Debug)]
pub struct HttpZeroRttChecker {
settings: QpackSettings,
settings: Http3Parameters,
}
impl HttpZeroRttChecker {
/// Right now we only have QPACK settings, so that is all this takes.
#[must_use]
pub fn new(settings: QpackSettings) -> Self {
pub fn new(settings: Http3Parameters) -> Self {
Self { settings }
}
/// Save the settings that matter for 0-RTT.
#[must_use]
pub fn save(settings: QpackSettings) -> Vec<u8> {
pub fn save(settings: &Http3Parameters) -> Vec<u8> {
let mut enc = Encoder::new();
enc.encode_varint(SETTINGS_ZERO_RTT_VERSION)
.encode_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)
.encode_varint(settings.max_table_size_decoder)
.encode_varint(settings.get_max_table_size_decoder())
.encode_varint(SETTINGS_QPACK_BLOCKED_STREAMS)
.encode_varint(settings.max_blocked_streams);
.encode_varint(settings.get_max_blocked_streams())
.encode_varint(SETTINGS_ENABLE_WEB_TRANSPORT)
.encode_varint(settings.get_webtransport());
enc.into()
}
}
@ -174,9 +207,18 @@ impl ZeroRttChecker for HttpZeroRttChecker {
}
if settings.iter().all(|setting| match setting.setting_type {
HSettingType::BlockedStreams => {
u64::from(self.settings.max_blocked_streams) >= setting.value
u64::from(self.settings.get_max_blocked_streams()) >= setting.value
}
HSettingType::MaxTableCapacity => {
self.settings.get_max_table_size_decoder() >= setting.value
}
HSettingType::EnableWebTransport => {
if setting.value > 0 {
return false;
}
let value = setting.value == 1;
self.settings.get_webtransport() || !value
}
HSettingType::MaxTableCapacity => self.settings.max_table_size_decoder >= setting.value,
HSettingType::MaxHeaderListSize => true,
}) {
ZeroRttCheckResult::Accept

Просмотреть файл

@ -7,15 +7,16 @@
#![allow(clippy::module_name_repetitions)]
use crate::control_stream_local::HTTP3_UNI_STREAM_TYPE_CONTROL;
use crate::{
AppError, Error, Http3StreamType, HttpRecvStream, ReceiveOutput, RecvStream, Res, ResetType,
};
use crate::hframe::H3_FRAME_TYPE_HEADERS;
use crate::{CloseType, Error, Http3StreamType, ReceiveOutput, RecvStream, Res, Stream};
use neqo_common::{qtrace, Decoder, IncrementalDecoderUint, Role};
use neqo_qpack::decoder::QPACK_UNI_STREAM_TYPE_DECODER;
use neqo_qpack::encoder::QPACK_UNI_STREAM_TYPE_ENCODER;
use neqo_transport::Connection;
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;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum NewStreamType {
@ -23,6 +24,8 @@ pub enum NewStreamType {
Decoder,
Encoder,
Push(u64),
WebTransportStream(u64),
Http,
Unknown,
}
@ -33,13 +36,31 @@ impl NewStreamType {
/// # Error
/// Push streams received by the server are not allowed and this function will return
/// `HttpStreamCreation` error.
fn final_stream_type(stream_type: u64, role: Role) -> Res<Option<NewStreamType>> {
match (stream_type, role) {
(HTTP3_UNI_STREAM_TYPE_CONTROL, _) => Ok(Some(NewStreamType::Control)),
(QPACK_UNI_STREAM_TYPE_ENCODER, _) => Ok(Some(NewStreamType::Decoder)),
(QPACK_UNI_STREAM_TYPE_DECODER, _) => Ok(Some(NewStreamType::Encoder)),
(HTTP3_UNI_STREAM_TYPE_PUSH, Role::Client) => Ok(None),
(HTTP3_UNI_STREAM_TYPE_PUSH, Role::Server) => Err(Error::HttpStreamCreation),
fn final_stream_type(
stream_type: u64,
trans_stream_type: StreamType,
role: Role,
) -> Res<Option<NewStreamType>> {
match (stream_type, trans_stream_type, role) {
(HTTP3_UNI_STREAM_TYPE_CONTROL, StreamType::UniDi, _) => {
Ok(Some(NewStreamType::Control))
}
(QPACK_UNI_STREAM_TYPE_ENCODER, StreamType::UniDi, _) => {
Ok(Some(NewStreamType::Decoder))
}
(QPACK_UNI_STREAM_TYPE_DECODER, StreamType::UniDi, _) => {
Ok(Some(NewStreamType::Encoder))
}
(HTTP3_UNI_STREAM_TYPE_PUSH, StreamType::UniDi, Role::Client)
| (WEBTRANSPORT_UNI_STREAM, StreamType::UniDi, _)
| (WEBTRANSPORT_STREAM, StreamType::BiDi, _) => Ok(None),
(H3_FRAME_TYPE_HEADERS, StreamType::BiDi, Role::Server) => {
Ok(Some(NewStreamType::Http))
}
(_, StreamType::BiDi, Role::Server) => Err(Error::HttpFrame),
(HTTP3_UNI_STREAM_TYPE_PUSH, StreamType::UniDi, Role::Server)
| (H3_FRAME_TYPE_HEADERS, StreamType::BiDi, Role::Client)
| (_, StreamType::BiDi, Role::Client) => Err(Error::HttpStreamCreation),
_ => Ok(Some(NewStreamType::Unknown)),
}
}
@ -58,17 +79,18 @@ pub enum NewStreamHeadReader {
ReadType {
role: Role,
reader: IncrementalDecoderUint,
stream_id: u64,
stream_id: StreamId,
},
ReadId {
stream_type: u64,
reader: IncrementalDecoderUint,
stream_id: u64,
stream_id: StreamId,
},
Done,
}
impl NewStreamHeadReader {
pub fn new(stream_id: u64, role: Role) -> Self {
pub fn new(stream_id: StreamId, role: Role) -> Self {
NewStreamHeadReader::ReadType {
role,
reader: IncrementalDecoderUint::default(),
@ -80,7 +102,9 @@ impl NewStreamHeadReader {
if let NewStreamHeadReader::ReadType {
reader, stream_id, ..
}
| NewStreamHeadReader::ReadId { reader, stream_id } = self
| NewStreamHeadReader::ReadId {
reader, stream_id, ..
} = self
{
loop {
let to_read = reader.min_remaining();
@ -125,7 +149,8 @@ impl NewStreamHeadReader {
// - None - if a stream is not identified by the type only, but it needs
// additional data from the header to produce the final type, e.g.
// a push stream needs pushId as well.
let final_type = NewStreamType::final_stream_type(output, *role);
let final_type =
NewStreamType::final_stream_type(output, stream_id.stream_type(), *role);
match (&final_type, fin) {
(Err(_), _) => {
*self = NewStreamHeadReader::Done;
@ -145,17 +170,23 @@ impl NewStreamHeadReader {
*self = NewStreamHeadReader::ReadId {
reader: IncrementalDecoderUint::default(),
stream_id: *stream_id,
stream_type: output,
}
}
}
}
NewStreamHeadReader::ReadId { .. } => {
NewStreamHeadReader::ReadId { stream_type, .. } => {
let is_push = *stream_type == HTTP3_UNI_STREAM_TYPE_PUSH;
*self = NewStreamHeadReader::Done;
qtrace!("New Stream stream push_id={}", output);
if fin {
return Err(Error::HttpGeneralProtocol);
}
return Ok(Some(NewStreamType::Push(output)));
return if is_push {
Ok(Some(NewStreamType::Push(output)))
} else {
Ok(Some(NewStreamType::WebTransportStream(output)))
};
}
NewStreamHeadReader::Done => {
unreachable!("Cannot be in state NewStreamHeadReader::Done");
@ -170,48 +201,53 @@ impl NewStreamHeadReader {
| Some(NewStreamType::Encoder)
| Some(NewStreamType::Decoder) => Err(Error::HttpClosedCriticalStream),
None => Err(Error::HttpStreamCreation),
Some(NewStreamType::Http) => Err(Error::HttpFrame),
Some(NewStreamType::Unknown) => Ok(decoded),
Some(NewStreamType::Push(_)) => {
unreachable!("PushStream is mapped to None at this stage.")
Some(NewStreamType::Push(_)) | Some(NewStreamType::WebTransportStream(_)) => {
unreachable!("PushStream and WebTransport are mapped to None at this stage.")
}
}
}
}
impl RecvStream for NewStreamHeadReader {
fn stream_reset(&mut self, _error: AppError, _reset_type: ResetType) -> Res<()> {
*self = NewStreamHeadReader::Done;
Ok(())
}
fn receive(&mut self, conn: &mut Connection) -> Res<ReceiveOutput> {
Ok(self
.get_type(conn)?
.map_or(ReceiveOutput::NoOutput, ReceiveOutput::NewStream))
}
fn done(&self) -> bool {
matches!(self, NewStreamHeadReader::Done)
}
}
impl Stream for NewStreamHeadReader {
fn stream_type(&self) -> Http3StreamType {
Http3StreamType::NewStream
}
}
fn http_stream(&mut self) -> Option<&mut dyn HttpRecvStream> {
None
impl RecvStream for NewStreamHeadReader {
fn reset(&mut self, _close_type: CloseType) -> Res<()> {
*self = NewStreamHeadReader::Done;
Ok(())
}
fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> {
Ok((
self.get_type(conn)?
.map_or(ReceiveOutput::NoOutput, ReceiveOutput::NewStream),
self.done(),
))
}
}
#[cfg(test)]
mod tests {
use super::{NewStreamHeadReader, HTTP3_UNI_STREAM_TYPE_PUSH};
use neqo_transport::{Connection, StreamType};
use super::{
NewStreamHeadReader, HTTP3_UNI_STREAM_TYPE_PUSH, WEBTRANSPORT_STREAM,
WEBTRANSPORT_UNI_STREAM,
};
use neqo_transport::{Connection, StreamId, StreamType};
use std::mem;
use test_fixture::{connect, now};
use crate::control_stream_local::HTTP3_UNI_STREAM_TYPE_CONTROL;
use crate::{Error, NewStreamType, ReceiveOutput, RecvStream, Res, ResetType};
use crate::hframe::H3_FRAME_TYPE_HEADERS;
use crate::{CloseType, Error, NewStreamType, ReceiveOutput, RecvStream, Res};
use neqo_common::{Encoder, Role};
use neqo_qpack::decoder::QPACK_UNI_STREAM_TYPE_DECODER;
use neqo_qpack::encoder::QPACK_UNI_STREAM_TYPE_ENCODER;
@ -219,15 +255,15 @@ mod tests {
struct Test {
conn_c: Connection,
conn_s: Connection,
stream_id: u64,
stream_id: StreamId,
decoder: NewStreamHeadReader,
}
impl Test {
fn new(role: Role) -> Self {
fn new(stream_type: StreamType, role: Role) -> Self {
let (mut conn_c, mut conn_s) = connect();
// create a stream
let stream_id = conn_s.stream_create(StreamType::UniDi).unwrap();
let stream_id = conn_s.stream_create(stream_type).unwrap();
let out = conn_s.process(None, now());
mem::drop(conn_c.process(out.dgram(), now()));
@ -243,7 +279,7 @@ mod tests {
&mut self,
enc: &[u8],
fin: bool,
outcome: &Res<ReceiveOutput>,
outcome: &Res<(ReceiveOutput, bool)>,
done: bool,
) {
let len = enc.len() - 1;
@ -255,7 +291,7 @@ mod tests {
mem::drop(self.conn_c.process(out.dgram(), now()));
assert_eq!(
self.decoder.receive(&mut self.conn_c).unwrap(),
ReceiveOutput::NoOutput
(ReceiveOutput::NoOutput, false)
);
assert!(!self.decoder.done());
}
@ -275,7 +311,7 @@ mod tests {
&mut self,
to_encode: &[u64],
fin: bool,
outcome: &Res<ReceiveOutput>,
outcome: &Res<(ReceiveOutput, bool)>,
done: bool,
) {
let mut enc = Encoder::default();
@ -288,48 +324,51 @@ mod tests {
#[test]
fn decode_stream_decoder() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[QPACK_UNI_STREAM_TYPE_DECODER],
false,
&Ok(ReceiveOutput::NewStream(NewStreamType::Encoder)),
&Ok((ReceiveOutput::NewStream(NewStreamType::Encoder), true)),
true,
);
}
#[test]
fn decode_stream_encoder() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[QPACK_UNI_STREAM_TYPE_ENCODER],
false,
&Ok(ReceiveOutput::NewStream(NewStreamType::Decoder)),
&Ok((ReceiveOutput::NewStream(NewStreamType::Decoder), true)),
true,
);
}
#[test]
fn decode_stream_control() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[HTTP3_UNI_STREAM_TYPE_CONTROL],
false,
&Ok(ReceiveOutput::NewStream(NewStreamType::Control)),
&Ok((ReceiveOutput::NewStream(NewStreamType::Control), true)),
true,
);
}
#[test]
fn decode_stream_push() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[HTTP3_UNI_STREAM_TYPE_PUSH, 0xaaaa_aaaa],
false,
&Ok(ReceiveOutput::NewStream(NewStreamType::Push(0xaaaa_aaaa))),
&Ok((
ReceiveOutput::NewStream(NewStreamType::Push(0xaaaa_aaaa)),
true,
)),
true,
);
let mut t = Test::new(Role::Server);
let mut t = Test::new(StreamType::UniDi, Role::Server);
t.decode(
&[HTTP3_UNI_STREAM_TYPE_PUSH],
false,
@ -340,55 +379,175 @@ mod tests {
#[test]
fn decode_stream_unknown() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[0x3fff_ffff_ffff_ffff],
false,
&Ok(ReceiveOutput::NewStream(NewStreamType::Unknown)),
&Ok((ReceiveOutput::NewStream(NewStreamType::Unknown), true)),
true,
);
}
#[test]
fn decode_stream_http() {
let mut t = Test::new(StreamType::BiDi, Role::Server);
t.decode(
&[H3_FRAME_TYPE_HEADERS],
false,
&Ok((ReceiveOutput::NewStream(NewStreamType::Http), true)),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Server);
t.decode(
&[H3_FRAME_TYPE_HEADERS], // this is the same as a HTTP3_UNI_STREAM_TYPE_PUSH which is not aallowed on the server side.
false,
&Err(Error::HttpStreamCreation),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Client);
t.decode(
&[H3_FRAME_TYPE_HEADERS],
false,
&Err(Error::HttpStreamCreation),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[H3_FRAME_TYPE_HEADERS, 0xaaaa_aaaa], // this is the same as a HTTP3_UNI_STREAM_TYPE_PUSH
false,
&Ok((
ReceiveOutput::NewStream(NewStreamType::Push(0xaaaa_aaaa)),
true,
)),
true,
);
}
#[test]
fn decode_stream_wt_bidi() {
let mut t = Test::new(StreamType::BiDi, Role::Server);
t.decode(
&[WEBTRANSPORT_STREAM, 0xaaaa_aaaa],
false,
&Ok((
ReceiveOutput::NewStream(NewStreamType::WebTransportStream(0xaaaa_aaaa)),
true,
)),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Server);
t.decode(
&[WEBTRANSPORT_STREAM],
false,
&Ok((ReceiveOutput::NewStream(NewStreamType::Unknown), true)),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Client);
t.decode(
&[WEBTRANSPORT_STREAM, 0xaaaa_aaaa],
false,
&Ok((
ReceiveOutput::NewStream(NewStreamType::WebTransportStream(0xaaaa_aaaa)),
true,
)),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[WEBTRANSPORT_STREAM],
false,
&Ok((ReceiveOutput::NewStream(NewStreamType::Unknown), true)),
true,
);
}
#[test]
fn decode_stream_wt_unidi() {
let mut t = Test::new(StreamType::UniDi, Role::Server);
t.decode(
&[WEBTRANSPORT_UNI_STREAM, 0xaaaa_aaaa],
false,
&Ok((
ReceiveOutput::NewStream(NewStreamType::WebTransportStream(0xaaaa_aaaa)),
true,
)),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Server);
t.decode(
&[WEBTRANSPORT_UNI_STREAM],
false,
&Err(Error::HttpFrame),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[WEBTRANSPORT_UNI_STREAM, 0xaaaa_aaaa],
false,
&Ok((
ReceiveOutput::NewStream(NewStreamType::WebTransportStream(0xaaaa_aaaa)),
true,
)),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Client);
t.decode(
&[WEBTRANSPORT_UNI_STREAM],
false,
&Err(Error::HttpStreamCreation),
true,
);
}
#[test]
fn done_decoding() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[0x3fff],
false,
&Ok(ReceiveOutput::NewStream(NewStreamType::Unknown)),
&Ok((ReceiveOutput::NewStream(NewStreamType::Unknown), true)),
true,
);
// NewStreamHeadReader is done, it will not continue reading from the stream.
t.decode(
&[QPACK_UNI_STREAM_TYPE_DECODER],
false,
&Ok(ReceiveOutput::NoOutput),
&Ok((ReceiveOutput::NoOutput, true)),
true,
);
}
#[test]
fn decoding_truncate() {
let mut t = Test::new(Role::Client);
t.decode_buffer(&[0xff], false, &Ok(ReceiveOutput::NoOutput), false);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode_buffer(&[0xff], false, &Ok((ReceiveOutput::NoOutput, false)), false);
}
#[test]
fn reset() {
let mut t = Test::new(Role::Client);
t.decoder.stream_reset(0x100, ResetType::Remote).unwrap();
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decoder.reset(CloseType::ResetRemote(0x100)).unwrap();
// after a reset NewStreamHeadReader will not read more data.
t.decode(
&[QPACK_UNI_STREAM_TYPE_DECODER],
false,
&Ok(ReceiveOutput::NoOutput),
&Ok((ReceiveOutput::NoOutput, true)),
true,
);
}
#[test]
fn stream_fin_decoder() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[QPACK_UNI_STREAM_TYPE_DECODER],
true,
@ -399,7 +558,7 @@ mod tests {
#[test]
fn stream_fin_encoder() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[QPACK_UNI_STREAM_TYPE_ENCODER],
true,
@ -410,7 +569,7 @@ mod tests {
#[test]
fn stream_fin_control() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[HTTP3_UNI_STREAM_TYPE_CONTROL],
true,
@ -421,7 +580,7 @@ mod tests {
#[test]
fn stream_fin_push() {
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[HTTP3_UNI_STREAM_TYPE_PUSH, 0xaaaa_aaaa],
true,
@ -429,7 +588,7 @@ mod tests {
true,
);
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[HTTP3_UNI_STREAM_TYPE_PUSH],
true,
@ -439,16 +598,83 @@ mod tests {
}
#[test]
fn stream_fin_uknown() {
let mut t = Test::new(Role::Client);
fn stream_fin_wt() {
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[0x3fff_ffff_ffff_ffff],
&[WEBTRANSPORT_UNI_STREAM, 0xaaaa_aaaa],
true,
&Ok(ReceiveOutput::NewStream(NewStreamType::Unknown)),
&Err(Error::HttpGeneralProtocol),
true,
);
let mut t = Test::new(Role::Client);
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[WEBTRANSPORT_UNI_STREAM],
true,
&Err(Error::HttpStreamCreation),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Server);
t.decode(
&[WEBTRANSPORT_UNI_STREAM, 0xaaaa_aaaa],
true,
&Err(Error::HttpGeneralProtocol),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Server);
t.decode(
&[WEBTRANSPORT_UNI_STREAM],
true,
&Err(Error::HttpStreamCreation),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Client);
t.decode(
&[WEBTRANSPORT_STREAM, 0xaaaa_aaaa],
true,
&Err(Error::HttpGeneralProtocol),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Client);
t.decode(
&[WEBTRANSPORT_STREAM],
true,
&Err(Error::HttpStreamCreation),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Server);
t.decode(
&[WEBTRANSPORT_STREAM, 0xaaaa_aaaa],
true,
&Err(Error::HttpGeneralProtocol),
true,
);
let mut t = Test::new(StreamType::BiDi, Role::Server);
t.decode(
&[WEBTRANSPORT_STREAM],
true,
&Err(Error::HttpStreamCreation),
true,
);
}
#[test]
fn stream_fin_uknown() {
let mut t = Test::new(StreamType::UniDi, Role::Client);
t.decode(
&[0x3fff_ffff_ffff_ffff],
true,
&Ok((ReceiveOutput::NewStream(NewStreamType::Unknown), true)),
true,
);
let mut t = Test::new(StreamType::UniDi, Role::Client);
// A stream ID of 0x3fff_ffff_ffff_ffff is encoded into [0xff; 8].
// For this test the stream type is truncated.
// This should cause an error.

209
third_party/rust/neqo-http3/tests/httpconn.rs поставляемый
Просмотреть файл

@ -9,25 +9,26 @@
use neqo_common::{event::Provider, Datagram};
use neqo_crypto::AuthenticationStatus;
use neqo_http3::{
Header, Http3Client, Http3ClientEvent, Http3Server, Http3ServerEvent, Http3State, Priority,
Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server,
Http3ServerEvent, Http3State, Priority,
};
use neqo_transport::{ConnectionParameters, StreamType};
use std::mem;
use test_fixture::*;
const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
fn process_server_events(server: &mut Http3Server) {
let mut request_found = false;
fn receive_request(server: &mut Http3Server) -> Option<Http3OrWebTransportStream> {
while let Some(event) = server.next_event() {
if let Http3ServerEvent::Headers {
mut request,
stream,
headers,
fin,
} = event
{
assert_eq!(
headers,
vec![
&headers,
&[
Header::new(":method", "GET"),
Header::new(":scheme", "https"),
Header::new(":authority", "something.com"),
@ -35,19 +36,27 @@ fn process_server_events(server: &mut Http3Server) {
]
);
assert!(fin);
request
.set_response(
&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
],
RESPONSE_DATA,
)
.unwrap();
request_found = true;
return Some(stream);
}
}
assert!(request_found);
None
}
fn set_response(request: &mut Http3OrWebTransportStream) {
request
.send_headers(&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
.unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
}
fn process_server_events(server: &mut Http3Server) {
let mut request = receive_request(server).unwrap();
set_response(&mut request);
}
fn process_client_events(conn: &mut Http3Client) {
@ -57,8 +66,8 @@ fn process_client_events(conn: &mut Http3Client) {
match event {
Http3ClientEvent::HeaderReady { headers, fin, .. } => {
assert_eq!(
headers,
vec![
&headers,
&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
]
@ -68,7 +77,7 @@ fn process_client_events(conn: &mut Http3Client) {
}
Http3ClientEvent::DataReadable { stream_id } => {
let mut buf = [0u8; 100];
let (amount, fin) = conn.read_response_data(now(), stream_id, &mut buf).unwrap();
let (amount, fin) = conn.read_data(now(), stream_id, &mut buf).unwrap();
assert!(fin);
assert_eq!(amount, RESPONSE_DATA.len());
assert_eq!(&buf[..RESPONSE_DATA.len()], RESPONSE_DATA);
@ -81,10 +90,7 @@ fn process_client_events(conn: &mut Http3Client) {
assert!(response_data_found);
}
fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
let mut hconn_c = default_http3_client();
let mut hconn_s = default_http3_server();
fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option<Datagram> {
assert_eq!(hconn_c.state(), Http3State::Initializing);
let out = hconn_c.process(None, now()); // Initial
let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake
@ -102,7 +108,26 @@ fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
let out = hconn_c.process(out.dgram(), now());
// assert!(hconn_c.settings_received);
(hconn_c, hconn_s, out.dgram())
out.dgram()
}
fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
let mut hconn_c = default_http3_client();
let mut hconn_s = default_http3_server();
let out = connect_peers(&mut hconn_c, &mut hconn_s);
(hconn_c, hconn_s, out)
}
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;
}
}
}
#[test]
@ -139,3 +164,137 @@ fn test_fetch() {
mem::drop(hconn_c.process(out.dgram(), now()));
process_client_events(&mut hconn_c);
}
#[test]
fn test_103_response() {
let (mut hconn_c, mut hconn_s, dgram) = connect();
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());
let out = hconn_s.process(out.dgram(), now());
mem::drop(hconn_c.process(out.dgram(), now()));
let mut request = receive_request(&mut hconn_s).unwrap();
let info_headers = [
Header::new(":status", "103"),
Header::new("link", "</style.css>; rel=preload; as=style"),
];
// Send 103
request.send_headers(&info_headers).unwrap();
let out = hconn_s.process(None, now());
mem::drop(hconn_c.process(out.dgram(), now()));
let info_headers_event = |e| {
matches!(e, Http3ClientEvent::HeaderReady { headers,
interim,
fin, .. } if !fin && interim && headers.as_ref() == info_headers)
};
assert!(hconn_c.events().any(info_headers_event));
set_response(&mut request);
let out = hconn_s.process(None, now());
mem::drop(hconn_c.process(out.dgram(), now()));
process_client_events(&mut hconn_c)
}
#[test]
fn test_data_writable_events() {
const STREAM_LIMIT: u64 = 5000;
const DATA_AMOUNT: usize = 10000;
let mut hconn_c = http3_client_with_params(Http3Parameters::default().connection_parameters(
ConnectionParameters::default().max_stream_data(StreamType::BiDi, false, STREAM_LIMIT),
));
let mut hconn_s = default_http3_server();
mem::drop(connect_peers(&mut hconn_c, &mut hconn_s));
// Create a request.
let req = hconn_c
.fetch(
now(),
"GET",
&("https", "something.com", "/"),
&[],
Priority::default(),
)
.unwrap();
hconn_c.stream_close_send(req).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
let mut request = receive_request(&mut hconn_s).unwrap();
request
.send_headers(&[
Header::new(":status", "200"),
Header::new("content-length", DATA_AMOUNT.to_string()),
])
.unwrap();
// Send a lot of data
let buf = &[1; DATA_AMOUNT];
let mut sent = request.send_data(buf).unwrap();
assert!(sent < DATA_AMOUNT);
// Exchange packets and read the data on the client side.
exchange_packets(&mut hconn_c, &mut hconn_s);
let stream_id = request.stream_id();
let mut recv_buf = [0_u8; DATA_AMOUNT];
let (mut recvd, _) = hconn_c.read_data(now(), stream_id, &mut recv_buf).unwrap();
assert_eq!(sent, recvd);
exchange_packets(&mut hconn_c, &mut hconn_s);
let data_writable = |e| {
matches!(
e,
Http3ServerEvent::DataWritable {
stream
} if stream.stream_id() == stream_id
)
};
// Make sure we have a DataWritable event.
assert!(hconn_s.events().any(data_writable));
// Data can be sent again.
let s = request.send_data(&buf[sent..]).unwrap();
assert!(s > 0);
sent += s;
// Exchange packets and read the data on the client side.
exchange_packets(&mut hconn_c, &mut hconn_s);
let (r, _) = hconn_c
.read_data(now(), stream_id, &mut recv_buf[recvd..])
.unwrap();
recvd += r;
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(sent, recvd);
// One more DataWritable event.
assert!(hconn_s.events().any(data_writable));
// Send more data.
let s = request.send_data(&buf[sent..]).unwrap();
assert!(s > 0);
sent += s;
assert_eq!(sent, DATA_AMOUNT);
exchange_packets(&mut hconn_c, &mut hconn_s);
let (r, _) = hconn_c
.read_data(now(), stream_id, &mut recv_buf[recvd..])
.unwrap();
recvd += r;
// Make sure all data is received by the client.
assert_eq!(recvd, DATA_AMOUNT);
assert_eq!(&recv_buf, buf);
}

7
third_party/rust/neqo-http3/tests/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,7 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
mod webtransport;

52
third_party/rust/neqo-http3/tests/priority.rs поставляемый
Просмотреть файл

@ -8,54 +8,12 @@ use neqo_common::event::Provider;
use neqo_crypto::AuthenticationStatus;
use neqo_http3::{
Header, Http3Client, Http3ClientEvent, Http3Parameters, Http3Server, Http3ServerEvent,
Http3State, Priority,
Header, Http3Client, Http3ClientEvent, Http3Server, Http3ServerEvent, Http3State, Priority,
};
use neqo_qpack::QpackSettings;
use neqo_transport::ConnectionParameters;
use std::cell::RefCell;
use std::rc::Rc;
use std::time::Instant;
use test_fixture::*;
const DEFAULT_SETTINGS: QpackSettings = QpackSettings {
max_table_size_encoder: 65536,
max_table_size_decoder: 65536,
max_blocked_streams: 100,
};
pub fn default_http3_client() -> Http3Client {
fixture_init();
Http3Client::new(
DEFAULT_SERVER_NAME,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
ConnectionParameters::default(),
&Http3Parameters {
qpack_settings: DEFAULT_SETTINGS,
max_concurrent_push_streams: 5,
},
now(),
)
.expect("create a default client")
}
pub fn default_http3_server() -> Http3Server {
Http3Server::new(
now(),
DEFAULT_KEYS,
DEFAULT_ALPN_H3,
anti_replay(),
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
DEFAULT_SETTINGS,
None,
)
.expect("create a server")
}
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
let mut out = None;
let mut client_data;
@ -128,18 +86,18 @@ fn priority_update() {
match header_event {
Http3ServerEvent::Headers {
request: _,
stream: _,
headers,
fin,
} => {
let expected_headers = vec![
let expected_headers = &[
Header::new(":method", "GET"),
Header::new(":scheme", "https"),
Header::new(":authority", "something.com"),
Header::new(":path", "/"),
Header::new("priority", "u=4,i"),
];
assert_eq!(headers, expected_headers);
assert_eq!(&headers, expected_headers);
assert!(!fin);
}
other => panic!("unexpected server event: {:?}", other),
@ -184,7 +142,7 @@ fn priority_update_dont_send_for_cancelled_stream() {
let update_priority = Priority::new(6, false);
client.priority_update(stream_id, update_priority).unwrap();
client.stream_reset(stream_id, 11).unwrap();
client.cancel_fetch(stream_id, 11).unwrap();
exchange_packets(&mut client, &mut server);
while let Some(event) = server.next_event() {

329
third_party/rust/neqo-http3/tests/send_message.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,329 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lazy_static::lazy_static;
use neqo_common::event::Provider;
use neqo_crypto::AuthenticationStatus;
use neqo_http3::{
Error, Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Server,
Http3ServerEvent, Priority,
};
use test_fixture::*;
const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
lazy_static! {
static ref RESPONSE_HEADER_NO_DATA: Vec<Header> =
vec![Header::new(":status", "200"), Header::new("something", "3")];
}
lazy_static! {
static ref RESPONSE_HEADER_103: Vec<Header> =
vec![Header::new(":status", "103"), Header::new("link", "...")];
}
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 receive_request(server: &mut Http3Server) -> Option<Http3OrWebTransportStream> {
while let Some(event) = server.next_event() {
if let Http3ServerEvent::Headers {
stream,
headers,
fin,
} = event
{
assert_eq!(
&headers,
&[
Header::new(":method", "GET"),
Header::new(":scheme", "https"),
Header::new(":authority", "something.com"),
Header::new(":path", "/")
]
);
assert!(fin);
return Some(stream);
}
}
None
}
fn send_trailers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(&[
Header::new("something1", "something"),
Header::new("something2", "3"),
])
}
fn send_informational_headers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(&RESPONSE_HEADER_103)
}
fn send_headers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(&[
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
}
fn process_client_events(conn: &mut Http3Client) {
let mut response_header_found = false;
let mut response_data_found = false;
while let Some(event) = conn.next_event() {
match event {
Http3ClientEvent::HeaderReady { headers, fin, .. } => {
assert!(
(headers.as_ref()
== [
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
|| (headers.as_ref() == *RESPONSE_HEADER_103)
);
assert!(!fin);
response_header_found = true;
}
Http3ClientEvent::DataReadable { stream_id } => {
let mut buf = [0u8; 100];
let (amount, fin) = conn.read_data(now(), stream_id, &mut buf).unwrap();
assert!(fin);
assert_eq!(amount, RESPONSE_DATA.len());
assert_eq!(&buf[..RESPONSE_DATA.len()], RESPONSE_DATA);
response_data_found = true;
}
_ => {}
}
}
assert!(response_header_found);
assert!(response_data_found);
}
fn process_client_events_no_data(conn: &mut Http3Client) {
let mut response_header_found = false;
let mut fin_received = false;
while let Some(event) = conn.next_event() {
match event {
Http3ClientEvent::HeaderReady { headers, fin, .. } => {
assert_eq!(headers.as_ref(), *RESPONSE_HEADER_NO_DATA);
fin_received = fin;
response_header_found = true;
}
Http3ClientEvent::DataReadable { stream_id } => {
let mut buf = [0u8; 100];
let (amount, fin) = conn.read_data(now(), stream_id, &mut buf).unwrap();
assert!(fin);
fin_received = true;
assert_eq!(amount, 0);
}
_ => {}
}
}
assert!(response_header_found);
assert!(fin_received);
}
fn connect_send_and_receive_request() -> (Http3Client, Http3Server, Http3OrWebTransportStream) {
let mut hconn_c = default_http3_client();
let mut hconn_s = default_http3_server();
exchange_packets(&mut hconn_c, &mut hconn_s);
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(hconn_c.events().any(authentication_needed));
hconn_c.authenticated(AuthenticationStatus::Ok, now());
exchange_packets(&mut hconn_c, &mut hconn_s);
let req = hconn_c
.fetch(
now(),
"GET",
&("https", "something.com", "/"),
&[],
Priority::default(),
)
.unwrap();
assert_eq!(req, 0);
hconn_c.stream_close_send(req).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
let request = receive_request(&mut hconn_s).unwrap();
(hconn_c, hconn_s, request)
}
#[test]
fn response_trailers1() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
send_trailers(&mut request).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn response_trailers2() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn response_trailers3() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn response_trailers_no_data() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(&RESPONSE_HEADER_NO_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events_no_data(&mut hconn_c);
}
#[test]
fn multiple_response_trailers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(send_trailers(&mut request), Err(Error::InvalidInput));
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn data_after_trailer() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(request.send_data(RESPONSE_DATA), Err(Error::InvalidInput));
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn trailers_after_close() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
assert_eq!(send_trailers(&mut request), Err(Error::InvalidStreamId));
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn multiple_response_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(&RESPONSE_HEADER_NO_DATA).unwrap();
assert_eq!(
request.send_headers(&RESPONSE_HEADER_NO_DATA),
Err(Error::InvalidHeader)
);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events_no_data(&mut hconn_c);
}
#[test]
fn informational_after_response_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(&RESPONSE_HEADER_NO_DATA).unwrap();
assert_eq!(
send_informational_headers(&mut request),
Err(Error::InvalidHeader)
);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events_no_data(&mut hconn_c);
}
#[test]
fn data_after_informational() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_informational_headers(&mut request).unwrap();
assert_eq!(request.send_data(RESPONSE_DATA), Err(Error::InvalidInput));
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn non_trailers_headers_after_data() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(
request.send_headers(&RESPONSE_HEADER_NO_DATA),
Err(Error::InvalidHeader)
);
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}
#[test]
fn data_before_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
assert_eq!(request.send_data(RESPONSE_DATA), Err(Error::InvalidInput));
send_headers(&mut request).unwrap();
request.send_data(RESPONSE_DATA).unwrap();
request.stream_close_send().unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
process_client_events(&mut hconn_c);
}

521
third_party/rust/neqo-http3/tests/webtransport/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,521 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
mod negotiation;
mod sessions;
mod streams;
use neqo_common::event::Provider;
use neqo_crypto::AuthenticationStatus;
use neqo_http3::{
Error, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server,
Http3ServerEvent, Http3State, WebTransportEvent, WebTransportRequest, WebTransportServerEvent,
};
use neqo_transport::{AppError, 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 {
fixture_init();
Http3Client::new(
DEFAULT_SERVER_NAME,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
Http3Parameters::default().webtransport(webtransport),
now(),
)
.expect("create a default client")
}
pub fn default_http3_server(webtransport: bool) -> Http3Server {
Http3Server::new(
now(),
DEFAULT_KEYS,
DEFAULT_ALPN_H3,
anti_replay(),
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
Http3Parameters::default().webtransport(webtransport),
None,
)
.expect("create a 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;
}
}
}
// Perform only Quic transport handshake.
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
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 out = client.process(out.dgram(), now());
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
assert!(client.events().any(connected));
assert_eq!(client.state(), Http3State::Connected);
// Exchange H3 setttings
let out = server.process(out.dgram(), now());
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());
}
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);
connect_with(&mut client, &mut server);
(client, server)
}
struct WtTest {
client: Http3Client,
server: Http3Server,
}
impl WtTest {
pub fn new() -> Self {
let (client, server) = connect(true, true);
Self { client, server }
}
fn negotiate_wt_session(&mut self, accept: bool) -> (StreamId, Option<WebTransportRequest>) {
let wt_session_id = self
.client
.webtransport_create_session(now(), &("https", "something.com", "/"), &[])
.unwrap();
self.exchange_packets();
let mut wt_server_session = None;
while let Some(event) = self.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(accept).unwrap();
wt_server_session = Some(session);
}
Http3ServerEvent::Data { .. } => {
panic!("There should not be any data events!");
}
_ => {}
}
}
self.exchange_packets();
(wt_session_id, wt_server_session)
}
fn create_wt_session(&mut self) -> WebTransportRequest {
let (wt_session_id, wt_server_session) = self.negotiate_wt_session(true);
let wt_session_negotiated_event = |e| {
matches!(
e,
Http3ClientEvent::WebTransport(WebTransportEvent::Session(stream_id)) if stream_id == wt_session_id
)
};
assert!(self.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 exchange_packets(&mut self) {
let mut out = None;
loop {
out = self.client.process(out, now()).dgram();
out = self.server.process(out, now()).dgram();
if out.is_none() {
break;
}
}
}
pub fn cancel_session_client(&mut self, wt_stream_id: StreamId) {
self.client
.cancel_fetch(wt_stream_id, Error::HttpNoError.code())
.unwrap();
self.exchange_packets();
}
fn session_closed_client(
e: &Http3ClientEvent,
id: StreamId,
expected_error: &Option<AppError>,
) -> bool {
if let Http3ClientEvent::WebTransport(WebTransportEvent::SessionClosed {
stream_id,
error,
}) = e
{
*stream_id == id && error == expected_error
} else {
false
}
}
pub fn check_session_closed_event_client(
&mut self,
wt_session_id: StreamId,
expected_error: Option<AppError>,
) {
let mut event_found = false;
while let Some(event) = self.client.next_event() {
event_found = WtTest::session_closed_client(&event, wt_session_id, &expected_error);
if event_found {
break;
}
}
assert!(event_found);
}
pub fn cancel_session_server(&mut self, wt_session: &mut WebTransportRequest) {
wt_session.cancel_fetch(Error::HttpNoError.code()).unwrap();
self.exchange_packets();
}
fn session_closed_server(
e: &Http3ServerEvent,
id: StreamId,
expected_error: &Option<AppError>,
) -> bool {
if let Http3ServerEvent::WebTransport(WebTransportServerEvent::SessionClosed {
session,
error,
}) = e
{
session.stream_id() == id && error == expected_error
} else {
false
}
}
pub fn check_session_closed_event_server(
&mut self,
wt_session: &mut WebTransportRequest,
expected_error: Option<AppError>,
) {
let event = self.server.next_event().unwrap();
assert!(WtTest::session_closed_server(
&event,
wt_session.stream_id(),
&expected_error
));
}
fn create_wt_stream_client(
&mut self,
wt_session_id: StreamId,
stream_type: StreamType,
) -> StreamId {
self.client
.webtransport_create_stream(wt_session_id, stream_type)
.unwrap()
}
fn send_data_client(&mut self, wt_stream_id: StreamId, data: &[u8]) {
assert_eq!(
self.client.send_data(wt_stream_id, data).unwrap(),
data.len()
);
self.exchange_packets();
}
fn receive_data_client(
&mut self,
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) = self.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) = self.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 close_stream_sending_client(&mut self, wt_stream_id: StreamId) {
self.client.stream_close_send(wt_stream_id).unwrap();
self.exchange_packets();
}
fn reset_stream_client(&mut self, wt_stream_id: StreamId) {
self.client
.stream_reset_send(wt_stream_id, Error::HttpNoError.code())
.unwrap();
self.exchange_packets();
}
fn receive_reset_client(&mut self, expected_stream_id: StreamId) {
let wt_reset_event = |e| {
matches!(
e,
Http3ClientEvent::Reset {
stream_id,
error,
local
} if stream_id == expected_stream_id && error == Error::HttpNoError.code() && !local
)
};
assert!(self.client.events().any(wt_reset_event));
}
fn stream_stop_sending_client(&mut self, stream_id: StreamId) {
self.client
.stream_stop_sending(stream_id, Error::HttpNoError.code())
.unwrap();
self.exchange_packets();
}
fn receive_stop_sending_client(&mut self, expected_stream_id: StreamId) {
let wt_stop_sending_event = |e| {
matches!(
e,
Http3ClientEvent::StopSending {
stream_id,
error
} if stream_id == expected_stream_id && error == Error::HttpNoError.code()
)
};
assert!(self.client.events().any(wt_stop_sending_event));
}
fn check_events_after_closing_session_client(
&mut self,
expected_reset_ids: &[StreamId],
expected_error_stream_reset: Option<u64>,
expected_stop_sending_ids: &[StreamId],
expected_error_stream_stop_sending: Option<u64>,
expected_local: bool,
expected_session_close: Option<(StreamId, Option<u64>)>,
) {
let mut reset_ids_count = 0;
let mut stop_sending_ids_count = 0;
let mut close_event = false;
while let Some(event) = self.client.next_event() {
match event {
Http3ClientEvent::Reset {
stream_id,
error,
local,
} => {
assert!(expected_reset_ids.contains(&stream_id));
assert_eq!(expected_error_stream_reset.unwrap(), error);
assert_eq!(expected_local, local);
reset_ids_count += 1;
}
Http3ClientEvent::StopSending { stream_id, error } => {
assert!(expected_stop_sending_ids.contains(&stream_id));
assert_eq!(expected_error_stream_stop_sending.unwrap(), error);
stop_sending_ids_count += 1;
}
Http3ClientEvent::WebTransport(WebTransportEvent::SessionClosed {
stream_id,
error,
}) => {
close_event = true;
assert_eq!(stream_id, expected_session_close.unwrap().0);
assert_eq!(expected_session_close.unwrap().1, error);
}
_ => {}
}
}
assert_eq!(reset_ids_count, expected_reset_ids.len());
assert_eq!(stop_sending_ids_count, expected_stop_sending_ids.len());
assert_eq!(close_event, expected_session_close.is_some());
}
fn create_wt_stream_server(
&mut self,
wt_server_session: &mut WebTransportRequest,
stream_type: StreamType,
) -> Http3OrWebTransportStream {
wt_server_session.create_stream(stream_type).unwrap()
}
fn send_data_server(&mut self, wt_stream: &mut Http3OrWebTransportStream, data: &[u8]) {
assert_eq!(wt_stream.send_data(data).unwrap(), data.len());
self.exchange_packets();
}
fn receive_data_server(
&mut self,
stream_id: StreamId,
new_stream: bool,
expected_data: &[u8],
expected_fin: bool,
) -> Http3OrWebTransportStream {
self.exchange_packets();
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) = self.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()
}
fn close_stream_sending_server(&mut self, wt_stream: &mut Http3OrWebTransportStream) {
wt_stream.stream_close_send().unwrap();
self.exchange_packets();
}
fn reset_stream_server(&mut self, wt_stream: &mut Http3OrWebTransportStream) {
wt_stream
.stream_reset_send(Error::HttpNoError.code())
.unwrap();
self.exchange_packets();
}
fn stream_stop_sending_server(&mut self, wt_stream: &mut Http3OrWebTransportStream) {
wt_stream
.stream_stop_sending(Error::HttpNoError.code())
.unwrap();
self.exchange_packets();
}
fn receive_reset_server(&mut self, expected_stream_id: StreamId, expected_error: u64) {
let stream_reset = |e| {
matches!(
e,
Http3ServerEvent::StreamReset {
stream,
error
} if stream.stream_id() == expected_stream_id && error == expected_error
)
};
assert!(self.server.events().any(stream_reset));
}
fn receive_stop_sending_server(&mut self, expected_stream_id: StreamId, expected_error: u64) {
let stop_sending = |e| {
matches!(
e,
Http3ServerEvent::StreamStopSending {
stream,
error
} if stream.stream_id() == expected_stream_id && error == expected_error
)
};
assert!(self.server.events().any(stop_sending));
}
fn check_events_after_closing_session_server(
&mut self,
expected_reset_ids: &[StreamId],
expected_error_stream_reset: Option<u64>,
expected_stop_sending_ids: &[StreamId],
expected_error_stream_stop_sending: Option<u64>,
expected_session_close: Option<(StreamId, Option<u64>)>,
) {
let mut reset_ids_count = 0;
let mut stop_sending_ids_count = 0;
let mut close_event = false;
while let Some(event) = self.server.next_event() {
match event {
Http3ServerEvent::StreamReset { stream, error } => {
assert!(expected_reset_ids.contains(&stream.stream_id()));
assert_eq!(expected_error_stream_reset.unwrap(), error);
reset_ids_count += 1;
}
Http3ServerEvent::StreamStopSending { stream, error } => {
assert!(expected_stop_sending_ids.contains(&stream.stream_id()));
assert_eq!(expected_error_stream_stop_sending.unwrap(), error);
stop_sending_ids_count += 1;
}
Http3ServerEvent::WebTransport(WebTransportServerEvent::SessionClosed {
session,
error,
}) => {
close_event = true;
assert_eq!(session.stream_id(), expected_session_close.unwrap().0);
assert_eq!(expected_session_close.unwrap().1, error);
}
_ => {}
}
}
assert_eq!(reset_ids_count, expected_reset_ids.len());
assert_eq!(stop_sending_ids_count, expected_stop_sending_ids.len());
assert_eq!(close_event, expected_session_close.is_some());
}
}

105
third_party/rust/neqo-http3/tests/webtransport/negotiation.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,105 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
use neqo_http3::{Http3Client, Http3ClientEvent, Http3State, WebTransportEvent};
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);
}

78
third_party/rust/neqo-http3/tests/webtransport/sessions.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,78 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::webtransport::WtTest;
use neqo_http3::Error;
use std::mem;
#[test]
fn wt_session() {
let mut wt = WtTest::new();
mem::drop(wt.create_wt_session());
}
#[test]
fn wt_session_reject() {
let mut wt = WtTest::new();
let (wt_session_id, _wt_session) = wt.negotiate_wt_session(false);
wt.check_session_closed_event_client(wt_session_id, Some(Error::HttpRequestRejected.code()));
}
#[test]
fn wt_session_close_client() {
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
wt.cancel_session_client(wt_session.stream_id());
wt.check_session_closed_event_server(&mut wt_session, Some(Error::HttpNoError.code()));
}
#[test]
fn wt_session_close_server() {
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
wt.cancel_session_server(&mut wt_session);
wt.check_session_closed_event_client(wt_session.stream_id(), Some(Error::HttpNoError.code()));
}
#[test]
fn wt_session_close_server_close_send() {
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
wt_session.stream_close_send().unwrap();
wt.exchange_packets();
wt.check_session_closed_event_client(
wt_session.stream_id(),
Some(Error::HttpGeneralProtocolStream.code()),
);
}
#[test]
fn wt_session_close_server_stop_sending() {
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
wt_session
.stream_stop_sending(Error::HttpNoError.code())
.unwrap();
wt.exchange_packets();
wt.check_session_closed_event_client(wt_session.stream_id(), Some(Error::HttpNoError.code()));
}
#[test]
fn wt_session_close_server_reset() {
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
wt_session
.stream_reset_send(Error::HttpNoError.code())
.unwrap();
wt.exchange_packets();
wt.check_session_closed_event_client(wt_session.stream_id(), Some(Error::HttpNoError.code()));
}

971
third_party/rust/neqo-http3/tests/webtransport/streams.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,971 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::webtransport::WtTest;
use neqo_http3::Error;
use neqo_transport::StreamType;
use std::mem;
#[test]
fn wt_client_stream_uni() {
const BUF_CLIENT: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(wt_stream, BUF_CLIENT);
wt.receive_data_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 wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_client_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(wt_client_stream, BUF_CLIENT);
let mut wt_server_stream = wt.receive_data_server(wt_client_stream, true, BUF_CLIENT, false);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_client(wt_client_stream, false, BUF_SERVER, false);
}
#[test]
fn wt_server_stream_uni() {
const BUF_SERVER: &[u8] = &[2; 30];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_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 wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, false);
wt.send_data_client(wt_server_stream.stream_id(), BUF_CLIENT);
mem::drop(wt.receive_data_server(wt_server_stream.stream_id(), false, BUF_CLIENT, false));
}
#[test]
fn wt_client_stream_uni_close() {
const BUF_CLIENT: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(wt_stream, BUF_CLIENT);
wt.close_stream_sending_client(wt_stream);
wt.receive_data_server(wt_stream, true, BUF_CLIENT, true);
}
#[test]
fn wt_client_stream_bidi_close() {
const BUF_CLIENT: &[u8] = &[0; 10];
const BUF_SERVER: &[u8] = &[1; 20];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_client_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(wt_client_stream, BUF_CLIENT);
wt.close_stream_sending_client(wt_client_stream);
let mut wt_server_stream = wt.receive_data_server(wt_client_stream, true, BUF_CLIENT, true);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.close_stream_sending_server(&mut wt_server_stream);
wt.receive_data_client(wt_client_stream, false, BUF_SERVER, true);
}
#[test]
fn wt_server_stream_uni_closed() {
const BUF_SERVER: &[u8] = &[2; 30];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.close_stream_sending_server(&mut wt_server_stream);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, true);
}
#[test]
fn wt_server_stream_bidi_close() {
const BUF_CLIENT: &[u8] = &[0; 10];
const BUF_SERVER: &[u8] = &[1; 20];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.close_stream_sending_server(&mut wt_server_stream);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, true);
wt.send_data_client(wt_server_stream.stream_id(), BUF_CLIENT);
wt.close_stream_sending_client(wt_server_stream.stream_id());
mem::drop(wt.receive_data_server(wt_server_stream.stream_id(), false, BUF_CLIENT, true));
}
#[test]
fn wt_client_stream_uni_reset() {
const BUF_CLIENT: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(wt_stream, BUF_CLIENT);
mem::drop(wt.receive_data_server(wt_stream, true, BUF_CLIENT, false));
wt.reset_stream_client(wt_stream);
wt.receive_reset_server(wt_stream, Error::HttpNoError.code());
}
#[test]
fn wt_server_stream_uni_reset() {
const BUF_SERVER: &[u8] = &[2; 30];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, false);
wt.reset_stream_server(&mut wt_server_stream);
wt.receive_reset_client(wt_server_stream.stream_id());
}
#[test]
fn wt_client_stream_bidi_reset() {
const BUF_CLIENT: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_client_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(wt_client_stream, BUF_CLIENT);
let mut wt_server_stream = wt.receive_data_server(wt_client_stream, true, BUF_CLIENT, false);
wt.reset_stream_client(wt_client_stream);
wt.receive_reset_server(wt_server_stream.stream_id(), Error::HttpNoError.code());
wt.reset_stream_server(&mut wt_server_stream);
wt.receive_reset_client(wt_client_stream);
}
#[test]
fn wt_server_stream_bidi_reset() {
const BUF_SERVER: &[u8] = &[1; 20];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, false);
wt.reset_stream_client(wt_server_stream.stream_id());
wt.receive_reset_server(wt_server_stream.stream_id(), Error::HttpNoError.code());
wt.reset_stream_server(&mut wt_server_stream);
wt.receive_reset_client(wt_server_stream.stream_id());
}
#[test]
fn wt_client_stream_uni_stop_sending() {
const BUF_CLIENT: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(wt_stream, BUF_CLIENT);
let mut wt_server_stream = wt.receive_data_server(wt_stream, true, BUF_CLIENT, false);
wt.stream_stop_sending_server(&mut wt_server_stream);
wt.receive_stop_sending_client(wt_stream);
}
#[test]
fn wt_server_stream_uni_stop_sending() {
const BUF_SERVER: &[u8] = &[2; 30];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, false);
wt.stream_stop_sending_client(wt_server_stream.stream_id());
wt.receive_stop_sending_server(wt_server_stream.stream_id(), Error::HttpNoError.code());
}
#[test]
fn wt_client_stream_bidi_stop_sending() {
const BUF_CLIENT: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let wt_client_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(wt_client_stream, BUF_CLIENT);
let mut wt_server_stream = wt.receive_data_server(wt_client_stream, true, BUF_CLIENT, false);
wt.stream_stop_sending_client(wt_client_stream);
wt.receive_stop_sending_server(wt_server_stream.stream_id(), Error::HttpNoError.code());
wt.stream_stop_sending_server(&mut wt_server_stream);
wt.receive_stop_sending_client(wt_server_stream.stream_id());
}
#[test]
fn wt_server_stream_bidi_stop_sending() {
const BUF_SERVER: &[u8] = &[1; 20];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut wt_server_stream = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut wt_server_stream, BUF_SERVER);
wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, false);
wt.stream_stop_sending_client(wt_server_stream.stream_id());
wt.receive_stop_sending_server(wt_server_stream.stream_id(), Error::HttpNoError.code());
wt.stream_stop_sending_server(&mut wt_server_stream);
wt.receive_stop_sending_client(wt_server_stream.stream_id());
}
// For the following tests the client cancels a session. The streams are in different states:
// 1) Both sides of a bidirectional client stream are opened.
// 2) A client unidirectional stream is opened.
// 3) A client unidirectional stream has been closed and both sides consumed the closing info.
// 4) A client unidirectional stream has been closed, but only the server has consumed the closing info.
// 5) A client unidirectional stream has been closed, but only the client has consum the closing info.
// 6) Both sides of a bidirectional server stream are opened.
// 7) A server unidirectional stream is opened.
// 8) A server unidirectional stream has been closed and both sides consumed the closing info.
// 9) A server unidirectional stream has been closed, but only the server has consumed the closing info.
// 10) A server unidirectional stream has been closed, but only the client has consumed the closing info.
// 11) Both sides of a bidirectional stream have been closed and consumed by both sides.
// 12) Both sides of a bidirectional stream have been closed, but not consumed by both sides.
// 13) Multiples open streams
#[test]
fn wt_client_session_close_1() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let bidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(bidi_from_client, BUF);
let _ = wt.receive_data_server(bidi_from_client, true, BUF, false);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[bidi_from_client],
Some(Error::HttpRequestCancelled.code()),
&[bidi_from_client],
Some(Error::HttpRequestCancelled.code()),
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[bidi_from_client],
Some(Error::HttpRequestCancelled.code()),
&[bidi_from_client],
Some(Error::HttpRequestCancelled.code()),
false,
None,
);
}
#[test]
fn wt_client_session_close_2() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_from_client, BUF);
let _ = wt.receive_data_server(unidi_from_client, true, BUF, false);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[unidi_from_client],
Some(Error::HttpRequestCancelled.code()),
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[],
None,
&[unidi_from_client],
Some(Error::HttpRequestCancelled.code()),
false,
None,
);
}
#[test]
fn wt_client_session_close_3() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_from_client, BUF);
let _ = wt.receive_data_server(unidi_from_client, true, BUF, false);
wt.close_stream_sending_client(unidi_from_client);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(&[], None, &[], None, false, None);
}
#[test]
fn wt_client_session_close_4() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_from_client, BUF);
let mut unidi_from_client_s = wt.receive_data_server(unidi_from_client, true, BUF, false);
wt.stream_stop_sending_server(&mut unidi_from_client_s);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[],
None,
&[unidi_from_client],
Some(Error::HttpNoError.code()),
false,
None,
);
}
#[test]
fn wt_client_session_close_5() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_from_client, BUF);
mem::drop(wt.receive_data_server(unidi_from_client, true, BUF, false));
wt.reset_stream_client(unidi_from_client);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[unidi_from_client],
Some(Error::HttpNoError.code()),
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(&[], None, &[], None, false, None);
}
#[test]
fn wt_client_session_close_6() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut bidi_from_server = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut bidi_from_server, BUF);
wt.receive_data_client(bidi_from_server.stream_id(), true, BUF, false);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[bidi_from_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[bidi_from_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[bidi_from_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[bidi_from_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
false,
None,
);
}
#[test]
fn wt_client_session_close_7() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_from_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut unidi_from_server, BUF);
wt.receive_data_client(unidi_from_server.stream_id(), true, BUF, false);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[unidi_from_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[unidi_from_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[],
None,
false,
None,
);
}
#[test]
fn wt_client_session_close_8() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut unidi_server, BUF);
wt.close_stream_sending_server(&mut unidi_server);
wt.receive_data_client(unidi_server.stream_id(), true, BUF, true);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(&[], None, &[], None, false, None);
}
#[test]
fn wt_client_session_close_9() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut unidi_server, BUF);
wt.stream_stop_sending_client(unidi_server.stream_id());
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[unidi_server.stream_id()],
Some(Error::HttpNoError.code()),
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(&[], None, &[], None, false, None);
}
#[test]
fn wt_client_session_close_10() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut unidi_server, BUF);
wt.close_stream_sending_server(&mut unidi_server);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[unidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[],
None,
false,
None,
);
}
#[test]
fn wt_client_session_close_11() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut bidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut bidi_server, BUF);
wt.close_stream_sending_server(&mut bidi_server);
wt.receive_data_client(bidi_server.stream_id(), true, BUF, true);
wt.stream_stop_sending_server(&mut bidi_server);
wt.receive_stop_sending_client(bidi_server.stream_id());
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(&[], None, &[], None, false, None);
}
#[test]
fn wt_client_session_close_12() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut bidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut bidi_server, BUF);
wt.close_stream_sending_server(&mut bidi_server);
wt.stream_stop_sending_server(&mut bidi_server);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[],
None,
&[],
None,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[bidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[bidi_server.stream_id()],
Some(Error::HttpNoError.code()),
false,
None,
);
}
#[test]
fn wt_client_session_close_13() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let wt_session = wt.create_wt_session();
let bidi_client_1 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(bidi_client_1, BUF);
let _ = wt.receive_data_server(bidi_client_1, true, BUF, false);
let bidi_client_2 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(bidi_client_2, BUF);
let _ = wt.receive_data_server(bidi_client_2, true, BUF, false);
wt.cancel_session_client(wt_session.stream_id());
wt.check_events_after_closing_session_server(
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_client(
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
false,
None,
);
}
// For the following tests the server cancels a session. The streams are in different states:
// 1) Both sides of a bidirectional client stream are opened.
// 2) A client unidirectional stream is opened.
// 3) A client unidirectional stream has been closed and consumed by both sides.
// 4) A client unidirectional stream has been closed, but not consumed by the client.
// 5) Both sides of a bidirectional server stream are opened.
// 6) A server unidirectional stream is opened.
// 7) A server unidirectional stream has been closed and consumed by both sides.
// 8) A server unidirectional stream has been closed, but not consumed by the client.
// 9) Both sides of a bidirectional stream have been closed and consumed by both sides.
// 10) Both sides of a bidirectional stream have been closed, but not consumed by the client.
// 12) Multiples open streams
#[test]
fn wt_client_session_server_close_1() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let bidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(bidi_client, BUF);
let _ = wt.receive_data_server(bidi_client, true, BUF, false);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[bidi_client],
Some(Error::HttpRequestCancelled.code()),
&[bidi_client],
Some(Error::HttpRequestCancelled.code()),
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(
&[bidi_client],
Some(Error::HttpRequestCancelled.code()),
&[bidi_client],
Some(Error::HttpRequestCancelled.code()),
None,
);
}
#[test]
fn wt_client_session_server_close_2() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let unidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_client, BUF);
let _ = wt.receive_data_server(unidi_client, true, BUF, false);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[],
None,
&[unidi_client],
Some(Error::HttpRequestCancelled.code()),
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(
&[unidi_client],
Some(Error::HttpRequestCancelled.code()),
&[],
None,
None,
);
}
#[test]
fn wt_client_session_server_close_3() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let unidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_client, BUF);
let mut unidi_client_s = wt.receive_data_server(unidi_client, true, BUF, false);
wt.stream_stop_sending_server(&mut unidi_client_s);
wt.receive_stop_sending_client(unidi_client);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[],
None,
&[],
None,
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(&[], None, &[], None, None);
}
#[test]
fn wt_client_session_server_close_4() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let unidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
wt.send_data_client(unidi_client, BUF);
let mut unidi_client_s = wt.receive_data_server(unidi_client, true, BUF, false);
wt.stream_stop_sending_server(&mut unidi_client_s);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[],
None,
&[unidi_client],
Some(Error::HttpNoError.code()),
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(&[], None, &[], None, None);
}
#[test]
fn wt_client_session_server_close_5() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut bidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut bidi_server, BUF);
wt.receive_data_client(bidi_server.stream_id(), true, BUF, false);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[bidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[bidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(
&[bidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[bidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
None,
);
}
#[test]
fn wt_client_session_server_close_6() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_server = wt.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);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[unidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[],
None,
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(
&[],
None,
&[unidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
None,
);
}
#[test]
fn wt_client_session_server_close_7() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut unidi_server, BUF);
wt.close_stream_sending_server(&mut unidi_server);
wt.receive_data_client(unidi_server.stream_id(), true, BUF, true);
wt.cancel_session_server(&mut wt_session);
// Already close stream will not have a reset event.
wt.check_events_after_closing_session_client(
&[],
None,
&[],
None,
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(&[], None, &[], None, None);
}
#[test]
fn wt_client_session_server_close_8() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut unidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::UniDi);
wt.send_data_server(&mut unidi_server, BUF);
wt.close_stream_sending_server(&mut unidi_server);
wt.cancel_session_server(&mut wt_session);
// The stream was only closed on the server side therefore it is cancelled on the client side.
wt.check_events_after_closing_session_client(
&[unidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[],
None,
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(&[], None, &[], None, None);
}
#[test]
fn wt_client_session_server_close_9() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut bidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut bidi_server, BUF);
wt.close_stream_sending_server(&mut bidi_server);
wt.receive_data_client(bidi_server.stream_id(), true, BUF, true);
wt.stream_stop_sending_server(&mut bidi_server);
wt.receive_stop_sending_client(bidi_server.stream_id());
wt.cancel_session_server(&mut wt_session);
// Already close stream will not have a reset event.
wt.check_events_after_closing_session_client(
&[],
None,
&[],
None,
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(&[], None, &[], None, None);
}
#[test]
fn wt_client_session_server_close_10() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let mut bidi_server = wt.create_wt_stream_server(&mut wt_session, StreamType::BiDi);
wt.send_data_server(&mut bidi_server, BUF);
wt.close_stream_sending_server(&mut bidi_server);
wt.stream_stop_sending_server(&mut bidi_server);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[bidi_server.stream_id()],
Some(Error::HttpRequestCancelled.code()),
&[bidi_server.stream_id()],
Some(Error::HttpNoError.code()),
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(&[], None, &[], None, None);
}
#[test]
fn wt_client_session_server_close_11() {
const BUF: &[u8] = &[0; 10];
let mut wt = WtTest::new();
let mut wt_session = wt.create_wt_session();
let bidi_client_1 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(bidi_client_1, BUF);
let _ = wt.receive_data_server(bidi_client_1, true, BUF, false);
let bidi_client_2 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi);
wt.send_data_client(bidi_client_2, BUF);
let _ = wt.receive_data_server(bidi_client_2, true, BUF, false);
wt.cancel_session_server(&mut wt_session);
wt.check_events_after_closing_session_client(
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
false,
Some((wt_session.stream_id(), Some(Error::HttpNoError.code()))),
);
wt.check_events_after_closing_session_server(
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
&[bidi_client_1, bidi_client_2],
Some(Error::HttpRequestCancelled.code()),
None,
);
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"26d508a0c9b82cbdaccaae625d06b30fdaa0ff679fa5124e97cb56793423cc37","src/decoder.rs":"542f03f35044efa880780f851dbe8b1794a0ee8fe537e7b24928562298ac0a7f","src/decoder_instructions.rs":"6f40dd661f28c034239b0fa34b4bbf6beaa36cbab249fd3410292e2343d69658","src/encoder.rs":"cd2c0268a5c1d63e374e971c4d6000f9c3a4c1ef9d163148a8a79ac90b8ecfe3","src/encoder_instructions.rs":"a7f1d3a4f8ae941286d0aba81037a8df3ef85e275392ef31d9938e9314c706db","src/header_block.rs":"7910ddc28b44d2065070cb2d87ab3cfbb905cce912b23d8b12b0f0add5691ceb","src/huffman.rs":"3a9edaf827343ec6e43cfd50fcc0d0077287947160ae630da5c3ddaaefedd010","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"29c5e47f8a4cf9c0a5dfdc614594868db22bc25b9688e5efdbc041cd222a17e5","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"ca620f64e2d9c1514bbac3e968ff692d0f8f60d99e805e05c173c74c56da39ee","src/reader.rs":"a97c5d94cba1756735e389b127b9397b5ee673855cedbe7a34894e306ee64434","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}
{"files":{"Cargo.toml":"0dc3e499db364f97db58d873c8a652db66eeb608cf1b3ddd8d71560be9c0c8ce","src/decoder.rs":"6404dc3f93799aa0d3589817de9e2e2a5162d1235ff9dc66011df326e7f1f0d9","src/decoder_instructions.rs":"19d47158bc09551b449be205f5cd5ea83e6984c4e4d3e7d4b95938b09617015e","src/encoder.rs":"a902a3161fac8a0daea25ca15afb2333df9da01a8b5e5db92a82fe28cec417b8","src/encoder_instructions.rs":"a7f1d3a4f8ae941286d0aba81037a8df3ef85e275392ef31d9938e9314c706db","src/header_block.rs":"7910ddc28b44d2065070cb2d87ab3cfbb905cce912b23d8b12b0f0add5691ceb","src/huffman.rs":"3a9edaf827343ec6e43cfd50fcc0d0077287947160ae630da5c3ddaaefedd010","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"29c5e47f8a4cf9c0a5dfdc614594868db22bc25b9688e5efdbc041cd222a17e5","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"ca620f64e2d9c1514bbac3e968ff692d0f8f60d99e805e05c173c74c56da39ee","src/reader.rs":"448729cb2fc7857914d093f9d1ca00b27f013666f834463ef6569c23f2ddf597","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}

2
third_party/rust/neqo-qpack/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-qpack"
version = "0.5.3"
version = "0.5.5"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

61
third_party/rust/neqo-qpack/src/decoder.rs поставляемый
Просмотреть файл

@ -13,7 +13,7 @@ use crate::stats::Stats;
use crate::table::HeaderTable;
use crate::{Error, QpackSettings, Res};
use neqo_common::{qdebug, Header};
use neqo_transport::Connection;
use neqo_transport::{Connection, StreamId};
use std::convert::TryFrom;
pub const QPACK_UNI_STREAM_TYPE_DECODER: u64 = 0x3;
@ -25,10 +25,10 @@ pub struct QPackDecoder {
acked_inserts: u64,
max_entries: u64,
send_buf: QpackData,
local_stream_id: Option<u64>,
local_stream_id: Option<StreamId>,
max_table_size: u64,
max_blocked_streams: usize,
blocked_streams: Vec<(u64, u64)>, //stream_id and requested inserts count.
blocked_streams: Vec<(StreamId, u64)>, //stream_id and requested inserts count.
stats: Stats,
}
@ -36,7 +36,7 @@ impl QPackDecoder {
/// # Panics
/// If settings include invalid values.
#[must_use]
pub fn new(qpack_settings: QpackSettings) -> Self {
pub fn new(qpack_settings: &QpackSettings) -> Self {
qdebug!("Decoder: creating a new qpack decoder.");
let mut send_buf = QpackData::default();
send_buf.encode_varint(QPACK_UNI_STREAM_TYPE_DECODER);
@ -75,7 +75,7 @@ impl QPackDecoder {
/// # Errors
/// May return: `ClosedCriticalStream` if stream has been closed or `EncoderStream`
/// in case of any other transport error.
pub fn receive(&mut self, conn: &mut Connection, stream_id: u64) -> Res<Vec<u64>> {
pub fn receive(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<Vec<StreamId>> {
let base_old = self.table.base();
self.read_instructions(conn, stream_id)
.map_err(|e| map_error(&e))?;
@ -93,7 +93,7 @@ impl QPackDecoder {
Ok(r)
}
fn read_instructions(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
fn read_instructions(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<()> {
let mut recv = ReceiverConnWrapper::new(conn, stream_id);
loop {
match self.instruction_reader.read_instructions(&mut recv) {
@ -147,14 +147,14 @@ impl QPackDecoder {
self.table.set_capacity(cap)
}
fn header_ack(&mut self, stream_id: u64, required_inserts: u64) {
fn header_ack(&mut self, stream_id: StreamId, required_inserts: u64) {
DecoderInstruction::HeaderAck { stream_id }.marshal(&mut self.send_buf);
if required_inserts > self.acked_inserts {
self.acked_inserts = required_inserts;
}
}
pub fn cancel_stream(&mut self, stream_id: u64) {
pub fn cancel_stream(&mut self, stream_id: StreamId) {
if self.table.capacity() > 0 {
self.blocked_streams.retain(|(id, _)| *id != stream_id);
DecoderInstruction::StreamCancellation { stream_id }.marshal(&mut self.send_buf);
@ -195,7 +195,11 @@ impl QPackDecoder {
/// May return `DecompressionFailed` if header block is incorrect or incomplete.
/// # Panics
/// When there is a programming error.
pub fn decode_header_block(&mut self, buf: &[u8], stream_id: u64) -> Res<Option<Vec<Header>>> {
pub fn decode_header_block(
&mut self,
buf: &[u8],
stream_id: StreamId,
) -> Res<Option<Vec<Header>>> {
qdebug!([self], "decode header block.");
let mut decoder = HeaderDecoder::new(buf);
@ -231,7 +235,7 @@ impl QPackDecoder {
/// # Panics
/// When a stream has already been added.
pub fn add_send_stream(&mut self, stream_id: u64) {
pub fn add_send_stream(&mut self, stream_id: StreamId) {
if self.local_stream_id.is_some() {
panic!("Adding multiple local streams");
}
@ -239,7 +243,7 @@ impl QPackDecoder {
}
#[must_use]
pub fn local_stream_id(&self) -> Option<u64> {
pub fn local_stream_id(&self) -> Option<StreamId> {
self.local_stream_id
}
@ -265,17 +269,20 @@ fn map_error(err: &Error) -> Error {
#[cfg(test)]
mod tests {
use super::{Connection, Error, Header, QPackDecoder, Res};
use super::{Connection, Error, QPackDecoder, Res};
use crate::QpackSettings;
use neqo_transport::StreamType;
use std::convert::TryInto;
use neqo_common::Header;
use neqo_transport::{StreamId, StreamType};
use std::convert::TryFrom;
use std::mem;
use test_fixture::now;
const STREAM_0: StreamId = StreamId::new(0);
struct TestDecoder {
decoder: QPackDecoder,
send_stream_id: u64,
recv_stream_id: u64,
send_stream_id: StreamId,
recv_stream_id: StreamId,
conn: Connection,
peer_conn: Connection,
}
@ -288,7 +295,7 @@ mod tests {
let send_stream_id = conn.stream_create(StreamType::UniDi).unwrap();
// create a decoder
let mut decoder = QPackDecoder::new(QpackSettings {
let mut decoder = QPackDecoder::new(&QpackSettings {
max_table_size_encoder: 0,
max_table_size_decoder: 300,
max_blocked_streams: 100,
@ -336,7 +343,7 @@ mod tests {
decoder: &mut TestDecoder,
header_block: &[u8],
headers: &[Header],
stream_id: u64,
stream_id: StreamId,
) {
let decoded_headers = decoder
.decoder
@ -486,7 +493,7 @@ mod tests {
recv_instruction(&mut decoder, second_encoder_inst, &Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
decode_headers(&mut decoder, header_block, &headers, STREAM_0);
send_instructions_and_check(&mut decoder, &[0x80, 0x1]);
}
@ -522,7 +529,7 @@ mod tests {
recv_instruction(&mut decoder, second_encoder_inst, &Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
decode_headers(&mut decoder, header_block, &headers, STREAM_0);
send_instructions_and_check(&mut decoder, &[0x80]);
}
@ -548,7 +555,7 @@ mod tests {
recv_instruction(&mut decoder, encoder_inst, &Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
decode_headers(&mut decoder, header_block, &headers, STREAM_0);
send_instructions_and_check(&mut decoder, &[0x03, 0x80]);
}
@ -572,7 +579,7 @@ mod tests {
recv_instruction(&mut decoder, encoder_inst, &Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
decode_headers(&mut decoder, header_block, &headers, STREAM_0);
send_instructions_and_check(&mut decoder, &[0x03, 0x80, 0x01]);
}
@ -649,7 +656,7 @@ mod tests {
&mut decoder,
t.header_block,
&t.headers,
i.try_into().unwrap(),
StreamId::from(u64::try_from(i).unwrap()),
);
}
@ -727,7 +734,7 @@ mod tests {
&mut decoder,
t.header_block,
&t.headers,
i.try_into().unwrap(),
StreamId::from(u64::try_from(i).unwrap()),
);
}
@ -760,11 +767,11 @@ mod tests {
recv_instruction(&mut decoder, ENCODER_INST, &Ok(()));
decode_headers(&mut decoder, HEADER_BLOCK_1, &headers, 0);
decode_headers(&mut decoder, HEADER_BLOCK_1, &headers, STREAM_0);
let headers = vec![Header::new("my-headera", "my-valuea")];
decode_headers(&mut decoder, HEADER_BLOCK_2, &headers, 0);
decode_headers(&mut decoder, HEADER_BLOCK_2, &headers, STREAM_0);
}
#[test]
@ -791,6 +798,6 @@ mod tests {
recv_instruction(&mut decoder, ENCODER_INST, &Ok(()));
decode_headers(&mut decoder, HEADER_BLOCK, &headers, 0);
decode_headers(&mut decoder, HEADER_BLOCK, &headers, STREAM_0);
}
}

Просмотреть файл

@ -11,22 +11,27 @@ use crate::qpack_send_buf::QpackData;
use crate::reader::{IntReader, ReadByte};
use crate::Res;
use neqo_common::{qdebug, qtrace};
use neqo_transport::StreamId;
use std::mem;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum DecoderInstruction {
InsertCountIncrement { increment: u64 },
HeaderAck { stream_id: u64 },
StreamCancellation { stream_id: u64 },
HeaderAck { stream_id: StreamId },
StreamCancellation { stream_id: StreamId },
NoInstruction,
}
impl DecoderInstruction {
fn get_instruction(b: u8) -> Self {
if DECODER_HEADER_ACK.cmp_prefix(b) {
Self::HeaderAck { stream_id: 0 }
Self::HeaderAck {
stream_id: StreamId::from(0),
}
} else if DECODER_STREAM_CANCELLATION.cmp_prefix(b) {
Self::StreamCancellation { stream_id: 0 }
Self::StreamCancellation {
stream_id: StreamId::from(0),
}
} else if DECODER_INSERT_COUNT_INCREMENT.cmp_prefix(b) {
Self::InsertCountIncrement { increment: 0 }
} else {
@ -40,10 +45,10 @@ impl DecoderInstruction {
enc.encode_prefixed_encoded_int(DECODER_INSERT_COUNT_INCREMENT, *increment);
}
Self::HeaderAck { stream_id } => {
enc.encode_prefixed_encoded_int(DECODER_HEADER_ACK, *stream_id);
enc.encode_prefixed_encoded_int(DECODER_HEADER_ACK, stream_id.as_u64());
}
Self::StreamCancellation { stream_id } => {
enc.encode_prefixed_encoded_int(DECODER_STREAM_CANCELLATION, *stream_id);
enc.encode_prefixed_encoded_int(DECODER_STREAM_CANCELLATION, stream_id.as_u64());
}
Self::NoInstruction => {}
}
@ -102,9 +107,7 @@ impl DecoderInstructionReader {
let val = reader.read(recv)?;
qtrace!([self], "varint read {}", val);
match &mut self.instruction {
DecoderInstruction::InsertCountIncrement { increment: v }
| DecoderInstruction::HeaderAck { stream_id: v }
| DecoderInstruction::StreamCancellation { stream_id: v } => {
DecoderInstruction::InsertCountIncrement { increment: v } => {
*v = val;
self.state = DecoderInstructionReaderState::ReadInstruction;
break Ok(mem::replace(
@ -112,6 +115,15 @@ impl DecoderInstructionReader {
DecoderInstruction::NoInstruction,
));
}
DecoderInstruction::HeaderAck { stream_id: v }
| DecoderInstruction::StreamCancellation { stream_id: v } => {
*v = StreamId::from(val);
self.state = DecoderInstructionReaderState::ReadInstruction;
break Ok(mem::replace(
&mut self.instruction,
DecoderInstruction::NoInstruction,
));
}
DecoderInstruction::NoInstruction => {
unreachable!("This instruction cannot be in this state.");
}
@ -128,6 +140,7 @@ mod test {
use super::{DecoderInstruction, DecoderInstructionReader, QpackData};
use crate::reader::test_receiver::TestReceiver;
use crate::Error;
use neqo_transport::StreamId;
fn test_encoding_decoding(instruction: DecoderInstruction) {
let mut buf = QpackData::default();
@ -146,11 +159,19 @@ mod test {
test_encoding_decoding(DecoderInstruction::InsertCountIncrement { increment: 1 });
test_encoding_decoding(DecoderInstruction::InsertCountIncrement { increment: 10_000 });
test_encoding_decoding(DecoderInstruction::HeaderAck { stream_id: 1 });
test_encoding_decoding(DecoderInstruction::HeaderAck { stream_id: 10_000 });
test_encoding_decoding(DecoderInstruction::HeaderAck {
stream_id: StreamId::new(1),
});
test_encoding_decoding(DecoderInstruction::HeaderAck {
stream_id: StreamId::new(10_000),
});
test_encoding_decoding(DecoderInstruction::StreamCancellation { stream_id: 1 });
test_encoding_decoding(DecoderInstruction::StreamCancellation { stream_id: 10_000 });
test_encoding_decoding(DecoderInstruction::StreamCancellation {
stream_id: StreamId::new(1),
});
test_encoding_decoding(DecoderInstruction::StreamCancellation {
stream_id: StreamId::new(10_000),
});
}
fn test_encoding_decoding_slow_reader(instruction: DecoderInstruction) {
@ -177,9 +198,11 @@ mod test {
test_encoding_decoding_slow_reader(DecoderInstruction::InsertCountIncrement {
increment: 10_000,
});
test_encoding_decoding_slow_reader(DecoderInstruction::HeaderAck { stream_id: 10_000 });
test_encoding_decoding_slow_reader(DecoderInstruction::HeaderAck {
stream_id: StreamId::new(10_000),
});
test_encoding_decoding_slow_reader(DecoderInstruction::StreamCancellation {
stream_id: 10_000,
stream_id: StreamId::new(10_000),
});
}

461
third_party/rust/neqo-qpack/src/encoder.rs поставляемый
Просмотреть файл

@ -48,7 +48,7 @@ pub struct QPackEncoder {
// There can be multiple header blocks in one stream, headers, trailer, push stream request, etc.
// This HashMap maps a stream ID to a list of header blocks. Each header block is a list of
// referenced dynamic table entries.
unacked_header_blocks: HashMap<u64, VecDeque<HashSet<u64>>>,
unacked_header_blocks: HashMap<StreamId, VecDeque<HashSet<u64>>>,
blocked_stream_cnt: u16,
use_huffman: bool,
next_capacity: Option<u64>,
@ -57,7 +57,7 @@ pub struct QPackEncoder {
impl QPackEncoder {
#[must_use]
pub fn new(qpack_settings: QpackSettings, use_huffman: bool) -> Self {
pub fn new(qpack_settings: &QpackSettings, use_huffman: bool) -> Self {
Self {
table: HeaderTable::new(true),
max_table_size: qpack_settings.max_table_size_encoder,
@ -114,12 +114,12 @@ impl QPackEncoder {
/// # Errors
/// May return: `ClosedCriticalStream` if stream has been closed or `DecoderStream`
/// in case of any other transport error.
pub fn receive(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
pub fn receive(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<()> {
self.read_instructions(conn, stream_id)
.map_err(|e| map_error(&e))
}
fn read_instructions(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
fn read_instructions(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<()> {
qdebug!([self], "read a new instraction");
loop {
let mut recv = ReceiverConnWrapper::new(conn, stream_id);
@ -151,7 +151,7 @@ impl QPackEncoder {
Ok(())
}
fn header_ack(&mut self, stream_id: u64) {
fn header_ack(&mut self, stream_id: StreamId) {
self.stats.header_acks_recv += 1;
let mut new_acked = self.table.get_acked_inserts_cnt();
if let Some(hb_list) = self.unacked_header_blocks.get_mut(&stream_id) {
@ -175,7 +175,7 @@ impl QPackEncoder {
}
}
fn stream_cancellation(&mut self, stream_id: u64) {
fn stream_cancellation(&mut self, stream_id: StreamId) {
self.stats.stream_cancelled_recv += 1;
let mut was_blocker = false;
if let Some(mut hb_list) = self.unacked_header_blocks.remove(&stream_id) {
@ -251,7 +251,7 @@ impl QPackEncoder {
let stream_id = self.local_stream.stream_id().ok_or(Error::Internal)?;
let sent = conn
.stream_send_atomic(stream_id.as_u64(), &buf)
.stream_send_atomic(stream_id, &buf)
.map_err(|e| map_stream_send_atomic_error(&e))?;
if !sent {
return Err(Error::EncoderStreamBlocked);
@ -285,7 +285,7 @@ impl QPackEncoder {
}
let mut buf = QpackData::default();
EncoderInstruction::Capacity { value: cap }.marshal(&mut buf, self.use_huffman);
if !conn.stream_send_atomic(stream_id.as_u64(), &buf)? {
if !conn.stream_send_atomic(stream_id, &buf)? {
return Err(Error::EncoderStreamBlocked);
}
if self.table.set_capacity(cap).is_err() {
@ -304,7 +304,7 @@ impl QPackEncoder {
/// Sends any qpack encoder instructions.
/// # Errors
/// returns `EncoderStream` in case of an error.
pub fn send(&mut self, conn: &mut Connection) -> Res<()> {
pub fn send_encoder_updates(&mut self, conn: &mut Connection) -> Res<()> {
match self.local_stream {
LocalStreamState::NoStream => {
qerror!("Send call but there is no stream yet.");
@ -313,7 +313,7 @@ impl QPackEncoder {
LocalStreamState::Uninitialized(stream_id) => {
let mut buf = QpackData::default();
buf.encode_varint(QPACK_UNI_STREAM_TYPE_ENCODER);
if !conn.stream_send_atomic(stream_id.as_u64(), &buf[..])? {
if !conn.stream_send_atomic(stream_id, &buf[..])? {
return Err(Error::EncoderStreamBlocked);
}
self.local_stream = LocalStreamState::Initialized(stream_id);
@ -325,7 +325,7 @@ impl QPackEncoder {
}
}
fn is_stream_blocker(&self, stream_id: u64) -> bool {
fn is_stream_blocker(&self, stream_id: StreamId) -> bool {
if let Some(hb_list) = self.unacked_header_blocks.get(&stream_id) {
debug_assert!(!hb_list.is_empty());
match hb_list.iter().flatten().max() {
@ -347,21 +347,25 @@ impl QPackEncoder {
&mut self,
conn: &mut Connection,
h: &[Header],
stream_id: u64,
) -> Res<HeaderEncoder> {
stream_id: StreamId,
) -> HeaderEncoder {
qdebug!([self], "encoding headers.");
let mut encoder_blocked = false;
// Try to send capacity instructions if present.
match self.send(conn) {
Ok(()) => {}
Err(Error::EncoderStreamBlocked) => {
encoder_blocked = true;
}
Err(e) => {
// `InternalError`, `ClosedCriticalStream`
return Err(e);
}
if self.send_encoder_updates(conn).is_err() {
// This code doesn't try to deal with errors, it just tries
// to write to the encoder stream AND if it can't uses
// literal instructions.
// The errors can be:
// 1) `EncoderStreamBlocked` - this is an error that
// can occur.
// 2) `InternalError` - this is unexpected error.
// 3) `ClosedCriticalStream` - this is error that should
// close the HTTP/3 session.
// The last 2 errors are ignored here and will be picked up
// by the main loop.
encoder_blocked = true;
}
let mut encoded_h =
@ -404,21 +408,27 @@ impl QPackEncoder {
} else if can_block && !encoder_blocked {
// Insert using an InsertWithNameLiteral instruction. This entry name does not match any name in the
// tables therefore we cannot use any other instruction.
match self.send_and_insert(conn, &name, &value) {
Ok(index) => {
encoded_h.encode_indexed_dynamic(index);
ref_entries.insert(index);
self.table.add_ref(index);
}
Err(Error::EncoderStreamBlocked) | Err(Error::DynamicTableFull) => {
// As soon as one of the instructions cannot be written or the table is full, do not try again.
encoder_blocked = true;
encoded_h.encode_literal_with_name_literal(&name, &value);
}
Err(e) => {
// `InternalError`, `ClosedCriticalStream`
return Err(e);
}
if let Ok(index) = self.send_and_insert(conn, &name, &value) {
encoded_h.encode_indexed_dynamic(index);
ref_entries.insert(index);
self.table.add_ref(index);
} else {
// This code doesn't try to deal with errors, it just tries
// to write to the encoder stream AND if it can't uses
// literal instructions.
// The errors can be:
// 1) `EncoderStreamBlocked` - this is an error that
// can occur.
// 2) `DynamicTableFull` - this is an error that
// can occur.
// 3) `InternalError` - this is unexpected error.
// 4) `ClosedCriticalStream` - this is error that should
// close the HTTP/3 session.
// The last 2 errors are ignored here and will be picked up
// by the main loop.
// As soon as one of the instructions cannot be written or the table is full, do not try again.
encoder_blocked = true;
encoded_h.encode_literal_with_name_literal(&name, &value);
}
} else {
encoded_h.encode_literal_with_name_literal(&name, &value);
@ -444,15 +454,15 @@ impl QPackEncoder {
.push_front(ref_entries);
self.stats.dynamic_table_references += 1;
}
Ok(encoded_h)
encoded_h
}
/// Encoder stream has been created. Add the stream id.
/// # Panics
/// If a stream has already been added.
pub fn add_send_stream(&mut self, stream_id: u64) {
pub fn add_send_stream(&mut self, stream_id: StreamId) {
if self.local_stream == LocalStreamState::NoStream {
self.local_stream = LocalStreamState::Uninitialized(StreamId::new(stream_id));
self.local_stream = LocalStreamState::Uninitialized(stream_id);
} else {
panic!("Adding multiple local streams");
}
@ -464,8 +474,8 @@ impl QPackEncoder {
}
#[must_use]
pub fn local_stream_id(&self) -> Option<u64> {
self.local_stream.stream_id().map(StreamId::as_u64)
pub fn local_stream_id(&self) -> Option<StreamId> {
self.local_stream.stream_id()
}
#[cfg(test)]
@ -504,14 +514,14 @@ fn map_stream_send_atomic_error(err: &TransportError) -> Error {
mod tests {
use super::{Connection, Error, Header, QPackEncoder, Res};
use crate::QpackSettings;
use neqo_transport::{ConnectionParameters, StreamType};
use neqo_transport::{ConnectionParameters, StreamId, StreamType};
use std::mem;
use test_fixture::{configure_server, default_client, default_server, handshake, now};
struct TestEncoder {
encoder: QPackEncoder,
send_stream_id: u64,
recv_stream_id: u64,
send_stream_id: StreamId,
recv_stream_id: StreamId,
conn: Connection,
peer_conn: Connection,
}
@ -520,7 +530,7 @@ mod tests {
pub fn change_capacity(&mut self, capacity: u64) -> Res<()> {
self.encoder.set_max_capacity(capacity).unwrap();
// We will try to really change the table only when we send the change capacity instruction.
self.encoder.send(&mut self.conn)
self.encoder.send_encoder_updates(&mut self.conn)
}
pub fn insert(&mut self, header: &[u8], value: &[u8], inst: &[u8]) {
@ -531,21 +541,20 @@ mod tests {
pub fn encode_header_block(
&mut self,
stream_id: u64,
stream_id: StreamId,
headers: &[Header],
expected_encoding: &[u8],
inst: &[u8],
) {
let buf = self
.encoder
.encode_header_block(&mut self.conn, headers, stream_id)
.unwrap();
.encode_header_block(&mut self.conn, headers, stream_id);
assert_eq!(&buf[..], expected_encoding);
self.send_instructions(inst);
}
pub fn send_instructions(&mut self, encoder_instruction: &[u8]) {
self.encoder.send(&mut self.conn).unwrap();
self.encoder.send_encoder_updates(&mut self.conn).unwrap();
let out = self.conn.process(None, now());
let out2 = self.peer_conn.process(out.dgram(), now());
mem::drop(self.conn.process(out2.dgram(), now()));
@ -577,7 +586,7 @@ mod tests {
// create an encoder
let mut encoder = QPackEncoder::new(
QpackSettings {
&QpackSettings {
max_table_size_encoder: 1500,
max_table_size_decoder: 0,
max_blocked_streams: 0,
@ -642,6 +651,8 @@ mod tests {
// Indexed Header Field that refers to the first entry in the dynamic table.
const ENCODE_INDEXED_REF_DYNAMIC: &[u8] = &[0x02, 0x00, 0x80];
const STREAM_1: StreamId = StreamId::new(1);
const STREAM_2: StreamId = StreamId::new(2);
const HEADER_ACK_STREAM_ID_1: &[u8] = &[0x81];
const HEADER_ACK_STREAM_ID_2: &[u8] = &[0x82];
const STREAM_CANCELED_ID_1: &[u8] = &[0x41];
@ -761,8 +772,7 @@ mod tests {
for t in &test_cases {
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &t.headers, 1)
.unwrap();
.encode_header_block(&mut encoder.conn, &t.headers, STREAM_1);
assert_eq!(&buf[..], t.header_block);
encoder.send_instructions(t.encoder_inst);
}
@ -835,8 +845,7 @@ mod tests {
for t in &test_cases {
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &t.headers, 1)
.unwrap();
.encode_header_block(&mut encoder.conn, &t.headers, STREAM_1);
assert_eq!(&buf[..], t.header_block);
encoder.send_instructions(t.encoder_inst);
}
@ -903,14 +912,11 @@ mod tests {
recv_instruction(&mut encoder, &[0x01]);
// send a header block
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
1,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_eq!(&buf[..], ENCODE_INDEXED_REF_DYNAMIC);
encoder.send_instructions(&[]);
@ -986,14 +992,11 @@ mod tests {
encoder.encoder.set_max_blocked_streams(1).unwrap();
// send a header block, it refers to unacked entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
1,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
@ -1002,28 +1005,22 @@ mod tests {
// The next one will not use the dynamic entry because it is exceeding the max_blocked_streams
// limit.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
2,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
StreamId::new(2),
);
assert_is_index_to_static_name_only(&buf);
encoder.send_instructions(&[]);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// another header block to already blocked stream can still use the entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
1,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
@ -1058,30 +1055,23 @@ mod tests {
encoder.encoder.set_max_blocked_streams(1).unwrap();
let stream_id = 1;
// send a header block, it refers to unacked entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
stream_id,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
// encode another header block for the same stream that will refer to the second entry
// in the dynamic table.
// This should work because the stream is already a blocked stream
// send a header block, it refers to unacked entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "12345")],
stream_id,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "12345")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
}
@ -1099,28 +1089,31 @@ mod tests {
assert_eq!(encoder.encoder.blocked_stream_cnt(), 0);
// send a header block, that creates an new entry and refers to it.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// The next one will not create a new entry because the encoder is on max_blocked_streams limit.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name2", "value2")], 2)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name2", "value2")],
STREAM_2,
);
assert_is_literal_value_literal_name(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// another header block to already blocked stream can still create a new entry.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name2", "value2")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name2", "value2")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
@ -1140,19 +1133,21 @@ mod tests {
assert_eq!(encoder.encoder.blocked_stream_cnt(), 0);
// send a header block, that creates an new entry and refers to it.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// another header block to already blocked stream can still create a new entry.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name2", "value2")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name2", "value2")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
@ -1178,19 +1173,21 @@ mod tests {
assert_eq!(encoder.encoder.blocked_stream_cnt(), 0);
// send a header block, that creates an new entry and refers to it.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// another header block to already blocked stream can still create a new entry.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
@ -1216,19 +1213,21 @@ mod tests {
assert_eq!(encoder.encoder.blocked_stream_cnt(), 0);
// send a header block, that creates an new entry and refers to it.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// header block for the next stream will create an new entry as well.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name2", "value2")], 2)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name2", "value2")],
STREAM_2,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 2);
@ -1254,19 +1253,21 @@ mod tests {
assert_eq!(encoder.encoder.blocked_stream_cnt(), 0);
// send a header block, that creates an new entry and refers to it.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// header block for the next stream will create an new entry as well.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 2)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_2,
);
assert_is_index_to_dynamic(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 2);
@ -1294,28 +1295,31 @@ mod tests {
assert_eq!(encoder.encoder.blocked_stream_cnt(), 0);
// send a header block, that creates an new entry and refers to it.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 1);
// header block for the next stream will refer to the same entry.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name1", "value1")], 2)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name1", "value1")],
STREAM_2,
);
assert_is_index_to_dynamic(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 2);
// send another header block on stream 1.
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &[Header::new("name2", "value2")], 1)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("name2", "value2")],
STREAM_1,
);
assert_is_index_to_dynamic_post(&buf);
assert_eq!(encoder.encoder.blocked_stream_cnt(), 2);
@ -1349,14 +1353,11 @@ mod tests {
encoder.send_instructions(HEADER_CONTENT_LENGTH_VALUE_1_NAME_LITERAL);
// send a header block, it refers to unacked entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
1,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
// trying to evict the entry will failed.
@ -1396,14 +1397,11 @@ mod tests {
encoder.send_instructions(HEADER_CONTENT_LENGTH_VALUE_1_NAME_LITERAL);
// send a header block, it refers to unacked entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
1,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
// trying to evict the entry will failed.
@ -1473,14 +1471,11 @@ mod tests {
encoder.send_instructions(HEADER_CONTENT_LENGTH_VALUE_1_NAME_LITERAL);
// send a header block, it refers to unacked entry.
let buf = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
1,
)
.unwrap();
let buf = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_is_index_to_dynamic(&buf);
// trying to evict the entry will failed. The stream is still referring to it and
@ -1514,17 +1509,14 @@ mod tests {
// Encode a header block with 2 headers. The first header will be added to the dynamic table.
// The second will not be added to the dynamic table, because the corresponding instruction
// cannot be written immediately due to the flow control limit.
let buf1 = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[
Header::new("something", "1234"),
Header::new("something2", "12345678910"),
],
1,
)
.unwrap();
let buf1 = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[
Header::new("something", "1234"),
Header::new("something2", "12345678910"),
],
STREAM_1,
);
// Assert that the first header is encoded as an index to the dynamic table (a post form).
assert_eq!(buf1[2], 0x10);
@ -1532,17 +1524,14 @@ mod tests {
assert_eq!(buf1[3] & 0xf0, 0x20);
// Try to encode another header block. Here both headers will be encoded as a literal with a name literal
let buf2 = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[
Header::new("something3", "1234"),
Header::new("something4", "12345678910"),
],
2,
)
.unwrap();
let buf2 = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[
Header::new("something3", "1234"),
Header::new("something4", "12345678910"),
],
STREAM_2,
);
assert_eq!(buf2[2] & 0xf0, 0x20);
// Ensure that we have sent only one instruction for (String::from("something", "1234"))
@ -1554,17 +1543,14 @@ mod tests {
// Try writing a new header block. Now, headers will be added to the dynamic table again, because
// instructions can be sent.
let buf3 = encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[
Header::new("something5", "1234"),
Header::new("something6", "12345678910"),
],
3,
)
.unwrap();
let buf3 = encoder.encoder.encode_header_block(
&mut encoder.conn,
&[
Header::new("something5", "1234"),
Header::new("something6", "12345678910"),
],
StreamId::new(3),
);
// Assert that the first header is encoded as an index to the dynamic table (a post form).
assert_eq!(buf3[2], 0x10);
// Assert that the second header is encoded as a literal with a name literal
@ -1584,7 +1570,7 @@ mod tests {
}
#[test]
fn test_do_not_evict_entry_that_are_referd_only_by_the_same_header_blocked_encoding() {
fn test_do_not_evict_entry_that_are_referred_only_by_the_same_header_blocked_encoding() {
let mut encoder = connect(false);
encoder.encoder.set_max_blocked_streams(20).unwrap();
@ -1595,23 +1581,36 @@ mod tests {
.send_and_insert(&mut encoder.conn, b"something5", b"1234")
.unwrap();
encoder.encoder.send(&mut encoder.conn).unwrap();
encoder
.encoder
.send_encoder_updates(&mut encoder.conn)
.unwrap();
let out = encoder.conn.process(None, now());
mem::drop(encoder.peer_conn.process(out.dgram(), now()));
// receive an insert count increment.
recv_instruction(&mut encoder, &[0x01]);
assert!(encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[
Header::new("something5", "1234"),
Header::new("something6", "1234"),
],
3,
)
.is_ok());
// The first header will use the table entry and the second will use the literal
// encoding because the first entry is referred to and cannot be evicted.
assert_eq!(
encoder
.encoder
.encode_header_block(
&mut encoder.conn,
&[
Header::new("something5", "1234"),
Header::new("something6", "1234"),
],
StreamId::new(3),
)
.to_vec(),
&[
0x02, 0x00, 0x80, 0x27, 0x03, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67,
0x36, 0x04, 0x31, 0x32, 0x33, 0x34
]
);
// Also check that ther is no new instruction send by the encoder.
assert!(encoder.conn.process_output(now()).dgram().is_none());
}
#[test]
@ -1631,7 +1630,7 @@ mod tests {
// send a header block
encoder.encode_header_block(
1,
StreamId::new(1),
&[Header::new("content-length", "1234")],
ENCODE_INDEXED_REF_DYNAMIC,
&[],

6
third_party/rust/neqo-qpack/src/reader.rs поставляемый
Просмотреть файл

@ -8,7 +8,7 @@ use crate::huffman::decode_huffman;
use crate::prefix::Prefix;
use crate::{Error, Res};
use neqo_common::{qdebug, qerror};
use neqo_transport::Connection;
use neqo_transport::{Connection, StreamId};
use std::convert::TryInto;
use std::mem;
use std::str;
@ -29,7 +29,7 @@ pub trait Reader {
pub(crate) struct ReceiverConnWrapper<'a> {
conn: &'a mut Connection,
stream_id: u64,
stream_id: StreamId,
}
impl<'a> ReadByte for ReceiverConnWrapper<'a> {
@ -53,7 +53,7 @@ impl<'a> Reader for ReceiverConnWrapper<'a> {
}
impl<'a> ReceiverConnWrapper<'a> {
pub fn new(conn: &'a mut Connection, stream_id: u64) -> Self {
pub fn new(conn: &'a mut Connection, stream_id: StreamId) -> Self {
Self { conn, stream_id }
}
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

2
third_party/rust/neqo-transport/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-transport"
version = "0.5.3"
version = "0.5.5"
authors = ["EKR <ekr@rtfm.com>", "Andy Grover <agrover@mozilla.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

Просмотреть файл

@ -2698,7 +2698,7 @@ impl Connection {
/// # Errors
/// `ConnectionState` if the connecton stat does not allow to create streams.
/// `StreamLimitError` if we are limiied by server's stream concurence.
pub fn stream_create(&mut self, st: StreamType) -> Res<u64> {
pub fn stream_create(&mut self, st: StreamType) -> Res<StreamId> {
// Can't make streams while closing, otherwise rely on the stream limits.
match self.state {
State::Closing { .. } | State::Draining { .. } | State::Closed { .. } => {
@ -2721,12 +2721,12 @@ impl Connection {
/// `InvalidStreamId` the stream does not exist.
pub fn stream_priority(
&mut self,
stream_id: u64,
stream_id: StreamId,
transmission: TransmissionPriority,
retransmission: RetransmissionPriority,
) -> Res<()> {
self.streams
.get_send_stream_mut(stream_id.into())?
.get_send_stream_mut(stream_id)?
.set_priority(transmission, retransmission);
Ok(())
}
@ -2738,10 +2738,8 @@ impl Connection {
/// `InvalidStreamId` the stream does not exist,
/// `InvalidInput` if length of `data` is zero,
/// `FinalSizeError` if the stream has already been closed.
pub fn stream_send(&mut self, stream_id: u64, data: &[u8]) -> Res<usize> {
self.streams
.get_send_stream_mut(stream_id.into())?
.send(data)
pub fn stream_send(&mut self, stream_id: StreamId, data: &[u8]) -> Res<usize> {
self.streams.get_send_stream_mut(stream_id)?.send(data)
}
/// Send all data or nothing on a stream. May cause DATA_BLOCKED or
@ -2751,10 +2749,10 @@ impl Connection {
/// `InvalidStreamId` the stream does not exist,
/// `InvalidInput` if length of `data` is zero,
/// `FinalSizeError` if the stream has already been closed.
pub fn stream_send_atomic(&mut self, stream_id: u64, data: &[u8]) -> Res<bool> {
pub fn stream_send_atomic(&mut self, stream_id: StreamId, data: &[u8]) -> Res<bool> {
let val = self
.streams
.get_send_stream_mut(stream_id.into())?
.get_send_stream_mut(stream_id)?
.send_atomic(data);
if let Ok(val) = val {
debug_assert!(
@ -2770,21 +2768,19 @@ impl Connection {
/// Bytes that stream_send() is guaranteed to accept for sending.
/// i.e. that will not be blocked by flow credits or send buffer max
/// capacity.
pub fn stream_avail_send_space(&self, stream_id: u64) -> Res<usize> {
Ok(self.streams.get_send_stream(stream_id.into())?.avail())
pub fn stream_avail_send_space(&self, stream_id: StreamId) -> Res<usize> {
Ok(self.streams.get_send_stream(stream_id)?.avail())
}
/// Close the stream. Enqueued data will be sent.
pub fn stream_close_send(&mut self, stream_id: u64) -> Res<()> {
self.streams.get_send_stream_mut(stream_id.into())?.close();
pub fn stream_close_send(&mut self, stream_id: StreamId) -> Res<()> {
self.streams.get_send_stream_mut(stream_id)?.close();
Ok(())
}
/// Abandon transmission of in-flight and future stream data.
pub fn stream_reset_send(&mut self, stream_id: u64, err: AppError) -> Res<()> {
self.streams
.get_send_stream_mut(stream_id.into())?
.reset(err);
pub fn stream_reset_send(&mut self, stream_id: StreamId, err: AppError) -> Res<()> {
self.streams.get_send_stream_mut(stream_id)?.reset(err);
Ok(())
}
@ -2793,16 +2789,16 @@ impl Connection {
/// # Errors
/// `InvalidStreamId` if the stream does not exist.
/// `NoMoreData` if data and fin bit were previously read by the application.
pub fn stream_recv(&mut self, stream_id: u64, data: &mut [u8]) -> Res<(usize, bool)> {
let stream = self.streams.get_recv_stream_mut(stream_id.into())?;
pub fn stream_recv(&mut self, stream_id: StreamId, data: &mut [u8]) -> Res<(usize, bool)> {
let stream = self.streams.get_recv_stream_mut(stream_id)?;
let rb = stream.read(data)?;
Ok((rb.0 as usize, rb.1))
}
/// Application is no longer interested in this stream.
pub fn stream_stop_sending(&mut self, stream_id: u64, err: AppError) -> Res<()> {
let stream = self.streams.get_recv_stream_mut(stream_id.into())?;
pub fn stream_stop_sending(&mut self, stream_id: StreamId, err: AppError) -> Res<()> {
let stream = self.streams.get_recv_stream_mut(stream_id)?;
stream.stop_sending(err);
Ok(())
@ -2812,8 +2808,8 @@ impl Connection {
/// # Errors
/// Returns `InvalidStreamId` if a stream does not exist or the receiving
/// side is closed.
pub fn set_stream_max_data(&mut self, stream_id: u64, max_data: u64) -> Res<()> {
let stream = self.streams.get_recv_stream_mut(stream_id.into())?;
pub fn set_stream_max_data(&mut self, stream_id: StreamId, max_data: u64) -> Res<()> {
let stream = self.streams.get_recv_stream_mut(stream_id)?;
stream.set_stream_max_data(max_data);
Ok(())
@ -2826,8 +2822,8 @@ impl Connection {
/// # Errors
/// Returns `InvalidStreamId` if a stream does not exist or the receiving
/// side is closed.
pub fn stream_keep_alive(&mut self, stream_id: u64, keep: bool) -> Res<()> {
self.streams.keep_alive(stream_id.into(), keep)
pub fn stream_keep_alive(&mut self, stream_id: StreamId, keep: bool) -> Res<()> {
self.streams.keep_alive(stream_id, keep)
}
pub fn remote_datagram_size(&self) -> u64 {

Просмотреть файл

@ -28,7 +28,7 @@ const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
const MAX_QUEUED_DATAGRAMS_DEFAULT: usize = 10;
/// What to do with preferred addresses.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub enum PreferredAddressConfig {
/// Disabled, whether for client or server.
Disabled,
@ -41,7 +41,7 @@ pub enum PreferredAddressConfig {
/// ConnectionParameters use for setting intitial value for QUIC parameters.
/// This collects configuration like initial limits, protocol version, and
/// congestion control algorithm.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub struct ConnectionParameters {
quic_version: QuicVersion,
cc_algorithm: CongestionControlAlgorithm,

Просмотреть файл

@ -44,10 +44,11 @@ fn cc_slow_start_to_cong_avoidance_recovery_period() {
let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
// Create stream 0
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
assert_eq!(stream_id, 0);
// Buffer up lot of data and generate packets
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, stream_id, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
// Predict the packet number of the last packet sent.
// We have already sent packets in `connect_rtt_idle`,
@ -57,7 +58,7 @@ fn cc_slow_start_to_cong_avoidance_recovery_period() {
// Server: Receive and generate ack
now += DEFAULT_RTT / 2;
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
assert_eq!(
server.stats().frame_tx.largest_acknowledged,
flight1_largest
@ -72,14 +73,14 @@ fn cc_slow_start_to_cong_avoidance_recovery_period() {
);
// Client: send more
let (mut c_tx_dgrams, mut now) = fill_cwnd(&mut client, 0, now);
let (mut c_tx_dgrams, mut now) = fill_cwnd(&mut client, stream_id, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND * 2);
let flight2_largest = flight1_largest + u64::try_from(c_tx_dgrams.len()).unwrap();
// Server: Receive and generate ack again, but drop first packet
now += DEFAULT_RTT / 2;
c_tx_dgrams.remove(0);
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
assert_eq!(
server.stats().frame_tx.largest_acknowledged,
flight2_largest
@ -103,10 +104,11 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
// Create stream 0
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
assert_eq!(stream_id, 0);
// Buffer up lot of data and generate packets
let (mut c_tx_dgrams, now) = fill_cwnd(&mut client, 0, now);
let (mut c_tx_dgrams, now) = fill_cwnd(&mut client, stream_id, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
// Drop 0th packet. When acked, this should put client into CARP.
@ -115,13 +117,13 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
let c_tx_dgrams2 = c_tx_dgrams.split_off(5);
// Server: Receive and generate ack
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
client.process_input(s_ack, now);
let cwnd1 = cwnd(&client);
// Generate ACK for more received packets
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams2, now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams2, now);
// ACK more packets but they were sent before end of recovery period
client.process_input(s_ack, now);
@ -147,8 +149,9 @@ fn single_packet_on_recovery() {
let delivered = send_something(&mut client, now);
// Now fill the congestion window.
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
let (_, now) = fill_cwnd(&mut client, 0, now);
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
assert_eq!(stream_id, 0);
let (_, now) = fill_cwnd(&mut client, stream_id, now);
assert!(cwnd_avail(&client) < ACK_ONLY_SIZE_LIMIT);
// Acknowledge just one packet and cause one packet to be declared lost.
@ -175,17 +178,18 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
// Create stream 0
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
assert_eq!(stream_id, 0);
// Buffer up lot of data and generate packets
let (mut c_tx_dgrams, mut now) = fill_cwnd(&mut client, 0, now);
let (mut c_tx_dgrams, mut now) = fill_cwnd(&mut client, stream_id, now);
// Drop 0th packet. When acked, this should put client into CARP.
c_tx_dgrams.remove(0);
// Server: Receive and generate ack
now += DEFAULT_RTT / 2;
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
// Client: Process ack
now += DEFAULT_RTT / 2;
@ -200,7 +204,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
// Check over several increases to be sure.
let mut expected_cwnd = cwnd(&client);
// Fill cwnd.
let (mut c_tx_dgrams, next_now) = fill_cwnd(&mut client, 0, now);
let (mut c_tx_dgrams, next_now) = fill_cwnd(&mut client, stream_id, now);
now = next_now;
for i in 0..5 {
qinfo!("iteration {}", i);
@ -221,19 +225,19 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
// Note that we need the client to process ACK frames in stages, so split the
// datagrams into two, ensuring that we allow for an ACK for each batch.
let most = c_tx_dgrams.len() - usize::try_from(DEFAULT_ACK_PACKET_TOLERANCE).unwrap() - 1;
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams.drain(..most), now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams.drain(..most), now);
assert_eq!(cwnd(&client), expected_cwnd);
client.process_input(s_ack, now);
// make sure to fill cwnd again.
let (mut new_pkts, next_now) = fill_cwnd(&mut client, 0, now);
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
now = next_now;
next_c_tx_dgrams.append(&mut new_pkts);
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
assert_eq!(cwnd(&client), expected_cwnd);
client.process_input(s_ack, now);
// make sure to fill cwnd again.
let (mut new_pkts, next_now) = fill_cwnd(&mut client, 0, now);
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
now = next_now;
next_c_tx_dgrams.append(&mut new_pkts);
@ -250,16 +254,15 @@ fn cc_slow_start_to_persistent_congestion_no_acks() {
let mut server = default_server();
let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
// Create stream 0
let stream = client.stream_create(StreamType::BiDi).unwrap();
// Buffer up lot of data and generate packets
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, stream, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
// Server: Receive and generate ack
now += DEFAULT_RTT / 2;
mem::drop(ack_bytes(&mut server, 0, c_tx_dgrams, now));
mem::drop(ack_bytes(&mut server, stream, c_tx_dgrams, now));
// ACK lost.
induce_persistent_congestion(&mut client, &mut server, stream, now);
@ -276,18 +279,18 @@ fn cc_slow_start_to_persistent_congestion_some_acks() {
let stream = client.stream_create(StreamType::BiDi).unwrap();
// Buffer up lot of data and generate packets
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, stream, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
// Server: Receive and generate ack
now += Duration::from_millis(100);
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream, c_tx_dgrams, now);
now += Duration::from_millis(100);
client.process_input(s_ack, now);
// send bytes that will be lost
let (_, next_now) = fill_cwnd(&mut client, 0, now);
let (_, next_now) = fill_cwnd(&mut client, stream, now);
now = next_now + Duration::from_millis(100);
induce_persistent_congestion(&mut client, &mut server, stream, now);
@ -305,12 +308,12 @@ fn cc_persistent_congestion_to_slow_start() {
let stream = client.stream_create(StreamType::BiDi).unwrap();
// Buffer up lot of data and generate packets
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, mut now) = fill_cwnd(&mut client, stream, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
// Server: Receive and generate ack
now += Duration::from_millis(10);
mem::drop(ack_bytes(&mut server, 0, c_tx_dgrams, now));
mem::drop(ack_bytes(&mut server, stream, c_tx_dgrams, now));
// ACK lost.
@ -321,19 +324,19 @@ fn cc_persistent_congestion_to_slow_start() {
now += Duration::from_millis(10);
// Send packets from after start of CARP
let (c_tx_dgrams, next_now) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, next_now) = fill_cwnd(&mut client, stream, now);
assert_eq!(c_tx_dgrams.len(), 2);
// Server: Receive and generate ack
now = next_now + Duration::from_millis(100);
let s_ack = ack_bytes(&mut server, 0, c_tx_dgrams, now);
let s_ack = ack_bytes(&mut server, stream, c_tx_dgrams, now);
// No longer in CARP. (pkts acked from after start of CARP)
// Should be in slow start now.
client.process_input(s_ack, now);
// ACKing 2 packets should let client send 4.
let (c_tx_dgrams, _) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, _) = fill_cwnd(&mut client, stream, now);
assert_eq!(c_tx_dgrams.len(), 4);
}
@ -344,23 +347,25 @@ fn ack_are_not_cc() {
let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
// Create a stream
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
let stream = client.stream_create(StreamType::BiDi).unwrap();
assert_eq!(stream, 0);
// Buffer up lot of data and generate packets, so that cc window is filled.
let (c_tx_dgrams, now) = fill_cwnd(&mut client, 0, now);
let (c_tx_dgrams, now) = fill_cwnd(&mut client, stream, now);
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
// The server hasn't received any of these packets yet, the server
// won't ACK, but if it sends an ack-eliciting packet instead.
qdebug!([server], "Sending ack-eliciting");
assert_eq!(server.stream_create(StreamType::BiDi).unwrap(), 1);
server.stream_send(1, b"dropped").unwrap();
let other_stream = server.stream_create(StreamType::BiDi).unwrap();
assert_eq!(other_stream, 1);
server.stream_send(other_stream, b"dropped").unwrap();
let dropped_packet = server.process(None, now).dgram();
assert!(dropped_packet.is_some()); // Now drop this one.
// Now the server sends a packet that will force an ACK,
// because the client will detect a gap.
server.stream_send(1, b"sent").unwrap();
server.stream_send(other_stream, b"sent").unwrap();
let ack_eliciting_packet = server.process(None, now).dgram();
assert!(ack_eliciting_packet.is_some());

Просмотреть файл

@ -12,9 +12,9 @@ use super::{
};
use crate::packet::PacketBuilder;
use crate::stats::FrameStats;
use crate::stream_id::{StreamId, StreamType};
use crate::tparams::{self, TransportParameter};
use crate::tracking::PacketNumberSpace;
use crate::StreamType;
use neqo_common::{qtrace, Encoder};
use std::mem;
@ -239,13 +239,14 @@ fn idle_recv_packet() {
let res = client.process(None, now);
assert_eq!(res, Output::Callback(default_timeout()));
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
assert_eq!(client.stream_send(0, b"hello").unwrap(), 5);
let stream = client.stream_create(StreamType::BiDi).unwrap();
assert_eq!(stream, 0);
assert_eq!(client.stream_send(stream, b"hello").unwrap(), 5);
// Respond with another packet
let out = client.process(None, now + Duration::from_secs(10));
server.process_input(out.dgram().unwrap(), now + Duration::from_secs(10));
assert_eq!(server.stream_send(0, b"world").unwrap(), 5);
assert_eq!(server.stream_send(stream, b"world").unwrap(), 5);
let out = server.process_output(now + Duration::from_secs(10));
assert_ne!(out.as_dgram_ref(), None);
@ -350,7 +351,7 @@ fn create_stream_idle_rtt(
responder: &mut Connection,
mut now: Instant,
rtt: Duration,
) -> (Instant, u64) {
) -> (Instant, StreamId) {
let check_idle = |endpoint: &mut Connection, now: Instant| {
let delay = endpoint.process_output(now).callback();
qtrace!([endpoint], "idle timeout {:?}", delay);
@ -389,7 +390,7 @@ fn create_stream_idle_rtt(
(now, stream)
}
fn create_stream_idle(initiator: &mut Connection, responder: &mut Connection) -> u64 {
fn create_stream_idle(initiator: &mut Connection, responder: &mut Connection) -> StreamId {
let (_, stream) = create_stream_idle_rtt(initiator, responder, now(), Duration::new(0, 0));
stream
}

Просмотреть файл

@ -14,7 +14,9 @@ use crate::events::ConnectionEvent;
use crate::path::PATH_MTU_V6;
use crate::recovery::ACK_ONLY_SIZE_LIMIT;
use crate::stats::{FrameStats, Stats, MAX_PTO_COUNTS};
use crate::{ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamType};
use crate::{
ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamId, StreamType,
};
use std::cell::RefCell;
use std::cmp::min;
@ -287,7 +289,7 @@ fn connect_force_idle(client: &mut Connection, server: &mut Connection) {
connect_rtt_idle(client, server, Duration::new(0, 0));
}
fn fill_stream(c: &mut Connection, stream: u64) {
fn fill_stream(c: &mut Connection, stream: StreamId) {
const BLOCK_SIZE: usize = 4_096;
loop {
let bytes_sent = c.stream_send(stream, &[0x42; BLOCK_SIZE]).unwrap();
@ -304,7 +306,7 @@ fn fill_stream(c: &mut Connection, stream: u64) {
/// from the return value whether a timeout is an ACK delay, PTO, or
/// pacing, this looks at the congestion window to tell when to stop.
/// Returns a list of datagrams and the new time.
fn fill_cwnd(c: &mut Connection, stream: u64, mut now: Instant) -> (Vec<Datagram>, Instant) {
fn fill_cwnd(c: &mut Connection, stream: StreamId, mut now: Instant) -> (Vec<Datagram>, Instant) {
// Train wreck function to get the remaining congestion window on the primary path.
fn cwnd(c: &Connection) -> usize {
c.paths.primary().borrow().sender().cwnd_avail()
@ -343,7 +345,7 @@ fn fill_cwnd(c: &mut Connection, stream: u64, mut now: Instant) -> (Vec<Datagram
fn increase_cwnd(
sender: &mut Connection,
receiver: &mut Connection,
stream: u64,
stream: StreamId,
mut now: Instant,
) -> Instant {
fill_stream(sender, stream);
@ -377,7 +379,7 @@ fn increase_cwnd(
/// The caller is responsible for ensuring that `dest` has received
/// enough data that it wants to generate an ACK. This panics if
/// no ACK frame is generated.
fn ack_bytes<D>(dest: &mut Connection, stream: u64, in_dgrams: D, now: Instant) -> Datagram
fn ack_bytes<D>(dest: &mut Connection, stream: StreamId, in_dgrams: D, now: Instant) -> Datagram
where
D: IntoIterator<Item = Datagram>,
D::IntoIter: ExactSizeIterator,
@ -412,7 +414,7 @@ fn cwnd_avail(c: &Connection) -> usize {
fn induce_persistent_congestion(
client: &mut Connection,
server: &mut Connection,
stream: u64,
stream: StreamId,
mut now: Instant,
) -> Instant {
// Note: wait some arbitrary time that should be longer than pto

Просмотреть файл

@ -8,7 +8,7 @@ use super::super::{Connection, Error, Output};
use super::{connect, default_client, default_server, fill_cwnd, maybe_authenticate};
use crate::addr_valid::{AddressValidation, ValidateAddress};
use crate::send_stream::{RetransmissionPriority, TransmissionPriority};
use crate::{ConnectionEvent, StreamType};
use crate::{ConnectionEvent, StreamId, StreamType};
use neqo_common::event::Provider;
use std::cell::RefCell;
@ -18,7 +18,7 @@ use test_fixture::{self, now};
const BLOCK_SIZE: usize = 4_096;
fn fill_stream(c: &mut Connection, id: u64) {
fn fill_stream(c: &mut Connection, id: StreamId) {
loop {
if c.stream_send(id, &[0x42; BLOCK_SIZE]).unwrap() < BLOCK_SIZE {
return;

Просмотреть файл

@ -344,8 +344,9 @@ fn pto_handshake_frames() {
now += Duration::from_millis(10);
client.authenticated(AuthenticationStatus::Ok, now);
assert_eq!(client.stream_create(StreamType::UniDi).unwrap(), 2);
assert_eq!(client.stream_send(2, b"zero").unwrap(), 4);
let stream = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(stream, 2);
assert_eq!(client.stream_send(stream, b"zero").unwrap(), 4);
qdebug!("---- client: SH..FIN -> FIN and 1RTT packet");
let pkt1 = client.process(None, now).dgram();
assert!(pkt1.is_some());

Просмотреть файл

@ -15,7 +15,7 @@ use crate::send_stream::{SendStreamState, SEND_BUFFER_SIZE};
use crate::tparams::{self, TransportParameter};
use crate::tracking::DEFAULT_ACK_PACKET_TOLERANCE;
use crate::{Connection, ConnectionError, ConnectionParameters};
use crate::{Error, StreamId, StreamType};
use crate::{Error, StreamType};
use neqo_common::{event::Provider, qdebug};
use std::cmp::max;
@ -101,16 +101,14 @@ fn transfer() {
.next()
.expect("should have a second new stream event");
assert!(stream_ids.next().is_none());
let (received1, fin1) = server.stream_recv(first_stream.as_u64(), &mut buf).unwrap();
let (received1, fin1) = server.stream_recv(first_stream, &mut buf).unwrap();
assert_eq!(received1, 4000);
assert!(!fin1);
let (received2, fin2) = server.stream_recv(first_stream.as_u64(), &mut buf).unwrap();
let (received2, fin2) = server.stream_recv(first_stream, &mut buf).unwrap();
assert_eq!(received2, 140);
assert!(!fin2);
let (received3, fin3) = server
.stream_recv(second_stream.as_u64(), &mut buf)
.unwrap();
let (received3, fin3) = server.stream_recv(second_stream, &mut buf).unwrap();
assert_eq!(received3, 60);
assert!(fin3);
}
@ -228,13 +226,13 @@ fn max_data() {
assert_eq!(client.stream_send(stream_id, b"hello").unwrap(), 0);
client
.streams
.get_send_stream_mut(stream_id.into())
.get_send_stream_mut(stream_id)
.unwrap()
.mark_as_sent(0, 4096, false);
assert_eq!(client.events().count(), 0);
client
.streams
.get_send_stream_mut(stream_id.into())
.get_send_stream_mut(stream_id)
.unwrap()
.mark_as_acked(0, 4096, false);
assert_eq!(client.events().count(), 0);
@ -253,7 +251,7 @@ fn max_data() {
// Increase max stream data. Avail space now limited by tx buffer
client
.streams
.get_send_stream_mut(stream_id.into())
.get_send_stream_mut(stream_id)
.unwrap()
.set_max_stream_data(100_000_000);
assert_eq!(
@ -506,10 +504,7 @@ fn stream_data_blocked_generates_max_stream_data() {
assert!(!end);
// Now send `STREAM_DATA_BLOCKED`.
let internal_stream = server
.streams
.get_send_stream_mut(StreamId::from(stream_id))
.unwrap();
let internal_stream = server.streams.get_send_stream_mut(stream_id).unwrap();
if let SendStreamState::Send { fc, .. } = internal_stream.state() {
fc.blocked();
} else {

4
third_party/rust/neqo-transport/src/dump.rs поставляемый
Просмотреть файл

@ -22,6 +22,10 @@ pub fn dump_packet(
pn: PacketNumber,
payload: &[u8],
) {
if ::log::Level::Debug > ::log::max_level() {
return;
}
let mut s = String::from("");
let mut d = Decoder::from(payload);
while d.remaining() > 0 {

24
third_party/rust/neqo-transport/src/events.rs поставляемый
Просмотреть файл

@ -44,21 +44,21 @@ pub enum ConnectionEvent {
},
/// New bytes available for reading.
RecvStreamReadable {
stream_id: u64,
stream_id: StreamId,
},
/// Peer reset the stream.
RecvStreamReset {
stream_id: u64,
stream_id: StreamId,
app_error: AppError,
},
/// Peer has sent STOP_SENDING
SendStreamStopSending {
stream_id: u64,
stream_id: StreamId,
app_error: AppError,
},
/// Peer has acked everything sent on the stream.
SendStreamComplete {
stream_id: u64,
stream_id: StreamId,
},
/// Peer increased MAX_STREAMS
SendStreamCreatable {
@ -99,9 +99,7 @@ impl ConnectionEvents {
}
pub fn recv_stream_readable(&self, stream_id: StreamId) {
self.insert(ConnectionEvent::RecvStreamReadable {
stream_id: stream_id.as_u64(),
});
self.insert(ConnectionEvent::RecvStreamReadable { stream_id });
}
pub fn recv_stream_reset(&self, stream_id: StreamId, app_error: AppError) {
@ -109,7 +107,7 @@ impl ConnectionEvents {
self.remove(|evt| matches!(evt, ConnectionEvent::RecvStreamReadable { stream_id: x } if *x == stream_id.as_u64()));
self.insert(ConnectionEvent::RecvStreamReset {
stream_id: stream_id.as_u64(),
stream_id,
app_error,
});
}
@ -120,10 +118,10 @@ impl ConnectionEvents {
pub fn send_stream_stop_sending(&self, stream_id: StreamId, app_error: AppError) {
// If stopped, no longer writable.
self.remove(|evt| matches!(evt, ConnectionEvent::SendStreamWritable { stream_id: x } if *x == stream_id.as_u64()));
self.remove(|evt| matches!(evt, ConnectionEvent::SendStreamWritable { stream_id: x } if *x == stream_id));
self.insert(ConnectionEvent::SendStreamStopSending {
stream_id: stream_id.as_u64(),
stream_id,
app_error,
});
}
@ -133,9 +131,7 @@ impl ConnectionEvents {
self.remove(|evt| matches!(evt, ConnectionEvent::SendStreamStopSending { stream_id: x, .. } if *x == stream_id.as_u64()));
self.insert(ConnectionEvent::SendStreamComplete {
stream_id: stream_id.as_u64(),
});
self.insert(ConnectionEvent::SendStreamComplete { stream_id });
}
pub fn send_stream_creatable(&self, stream_type: StreamType) {
@ -287,7 +283,7 @@ mod tests {
assert_eq!(
events[0],
ConnectionEvent::SendStreamStopSending {
stream_id: 8,
stream_id: StreamId::new(8),
app_error: 55
}
);

Просмотреть файл

@ -491,7 +491,7 @@ impl Server {
&self.certs,
&self.protocols,
Rc::clone(&cid_mgr) as _,
self.conn_params.clone().quic_version(initial.quic_version),
self.conn_params.quic_version(initial.quic_version),
);
if let Ok(mut c) = sconn {

Просмотреть файл

@ -113,6 +113,12 @@ impl PartialEq<u64> for StreamId {
}
}
impl AsRef<u64> for StreamId {
fn as_ref(&self) -> &u64 {
&self.0
}
}
impl ::std::fmt::Display for StreamId {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", self.as_u64())

Просмотреть файл

@ -377,7 +377,7 @@ impl Streams {
))
}
pub fn stream_create(&mut self, st: StreamType) -> Res<u64> {
pub fn stream_create(&mut self, st: StreamType) -> Res<StreamId> {
match self.local_stream_limits.take_stream_id(st) {
None => Err(Error::StreamLimitError),
Some(new_id) => {
@ -416,7 +416,7 @@ impl Streams {
),
);
}
Ok(new_id.as_u64())
Ok(new_id)
}
}
}

Просмотреть файл

@ -51,7 +51,7 @@ tpids! {
MAX_DATAGRAM_FRAME_SIZE = 0x0020,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Copy)]
pub struct PreferredAddress {
v4: Option<SocketAddr>,
v6: Option<SocketAddr>,
@ -761,6 +761,7 @@ mod tests {
#[test]
#[should_panic]
fn preferred_address_neither() {
#[allow(clippy::drop_copy)]
mem::drop(PreferredAddress::new(None, None));
}

Просмотреть файл

@ -184,14 +184,13 @@ impl SendData {
if self.stream_id.is_none() {
if let Ok(stream_id) = c.stream_create(StreamType::UniDi) {
qdebug!([c], "made stream {} for sending", stream_id);
self.stream_id = Some(StreamId::new(stream_id));
self.stream_id = Some(stream_id);
}
}
}
fn send(&mut self, c: &mut Connection, stream_id: StreamId) -> GoalStatus {
const DATA: &[u8] = &[0; 4096];
let stream_id = stream_id.as_u64();
let mut status = GoalStatus::Waiting;
loop {
let end = min(self.remaining, DATA.len());
@ -266,7 +265,7 @@ impl ReceiveData {
let mut status = GoalStatus::Waiting;
loop {
let end = min(self.remaining, buf.len());
let (recvd, _) = c.stream_recv(stream_id.as_u64(), &mut buf[..end]).unwrap();
let (recvd, _) = c.stream_recv(stream_id, &mut buf[..end]).unwrap();
qtrace!("received {} remaining {}", recvd, self.remaining);
if recvd == 0 {
return status;
@ -288,7 +287,7 @@ impl ConnectionGoal for ReceiveData {
_now: Instant,
) -> GoalStatus {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
self.recv(c, StreamId::new(*stream_id))
self.recv(c, *stream_id)
} else {
GoalStatus::Waiting
}