mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 04:38:02 +00:00
Bug 1619375 - Update Neqo to 0.2.0 r=dragana
Differential Revision: https://phabricator.services.mozilla.com/D65023 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
cdad6a0be8
commit
948bb52d09
@ -15,7 +15,7 @@ rev = "6a866fdad2ca880df9b87fcbc9921abac1e91914"
|
||||
[source."https://github.com/mozilla/neqo"]
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
replace-with = "vendored-sources"
|
||||
tag = "v0.1.14"
|
||||
tag = "v0.2.0"
|
||||
|
||||
[source."https://github.com/mozilla-spidermonkey/jsparagus"]
|
||||
git = "https://github.com/mozilla-spidermonkey/jsparagus"
|
||||
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -2641,8 +2641,8 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
||||
|
||||
[[package]]
|
||||
name = "neqo-common"
|
||||
version = "0.1.14"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.14#562b6f9ac332c6017fd068bb8f6cbe6ca8176403"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.2.0#b2ae769121dc406561d6bf1d4425f5038162160a"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
@ -2652,8 +2652,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-crypto"
|
||||
version = "0.1.14"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.14#562b6f9ac332c6017fd068bb8f6cbe6ca8176403"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.2.0#b2ae769121dc406561d6bf1d4425f5038162160a"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"log",
|
||||
@ -2665,8 +2665,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-http3"
|
||||
version = "0.1.14"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.14#562b6f9ac332c6017fd068bb8f6cbe6ca8176403"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.2.0#b2ae769121dc406561d6bf1d4425f5038162160a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"neqo-common",
|
||||
@ -2679,8 +2679,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-qpack"
|
||||
version = "0.1.14"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.14#562b6f9ac332c6017fd068bb8f6cbe6ca8176403"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.2.0#b2ae769121dc406561d6bf1d4425f5038162160a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"neqo-common",
|
||||
@ -2690,8 +2690,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-transport"
|
||||
version = "0.1.14"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.14#562b6f9ac332c6017fd068bb8f6cbe6ca8176403"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.2.0#b2ae769121dc406561d6bf1d4425f5038162160a"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
|
@ -27,7 +27,7 @@
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
const nsCString kHttp3Version = NS_LITERAL_CSTRING("h3-25");
|
||||
const nsCString kHttp3Version = NS_LITERAL_CSTRING("h3-27");
|
||||
|
||||
// define storage for all atoms
|
||||
namespace nsHttp {
|
||||
|
@ -35,13 +35,10 @@ enum class HttpVersion {
|
||||
v3_0 = 30
|
||||
};
|
||||
|
||||
enum class SpdyVersion {
|
||||
NONE = 0,
|
||||
HTTP_2 = 5
|
||||
};
|
||||
enum class SpdyVersion { NONE = 0, HTTP_2 = 5 };
|
||||
|
||||
extern const nsCString kHttp3Version;
|
||||
const char kHttp3VersionHEX[] = "ff00000019"; // this is draft 25.
|
||||
const char kHttp3VersionHEX[] = "ff0000001b"; // this is draft 27.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// http connection capabilities
|
||||
|
@ -8,16 +8,16 @@ edition = "2018"
|
||||
name = "neqo_glue"
|
||||
|
||||
[dependencies]
|
||||
neqo-http3 = { tag = "v0.1.14", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { tag = "v0.1.14", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.1.14", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-http3 = { tag = "v0.2.0", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { tag = "v0.2.0", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.2.0", git = "https://github.com/mozilla/neqo" }
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||
thin-vec = { version = "0.1.0", features = ["gecko-ffi"] }
|
||||
|
||||
[dependencies.neqo-crypto]
|
||||
tag = "v0.1.14"
|
||||
tag = "v0.2.0"
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
default-features = false
|
||||
features = ["gecko"]
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"34739642048f7cc148d2ba25092aa98857fc80aac1794e7f8e5b91a969338809","src/codec.rs":"00846df0051f32ec8b75b2f8e0344422e0693acbd4151aaec31e3ae02d6e696c","src/datagram.rs":"4beb13d5ea7927df6801fbe684dc231626c1856010eaef975d866ee66e894a45","src/incrdecoder.rs":"7b7b7fba57714a3baf0fe881010a9f5a9814bf26b9283a6d56d1c44010cbd822","src/lib.rs":"f6ee17bc45cafdccb562340a4d253a517c5366a74d07c38960aedc2554fe783c","src/log.rs":"943e4e332400d94805d60f965d1d0ae7aad180f6d5b50936d0bd9e085bbc1502","src/once.rs":"d8b2bf7a9e3ce83bdd7f29d8f73ce7ad0268c9618ae7255028fea9f90c9c9fd6","src/timer.rs":"56082a6ecb45bd31c7c677c4c1f0830e55821c860e70b5637b2015fa3be63743","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
|
||||
{"files":{"Cargo.toml":"61878763ccac1259d4d42ed0787a0dda1a003ccb37d51785f6e5ada5f5eb8942","src/codec.rs":"00846df0051f32ec8b75b2f8e0344422e0693acbd4151aaec31e3ae02d6e696c","src/datagram.rs":"4beb13d5ea7927df6801fbe684dc231626c1856010eaef975d866ee66e894a45","src/incrdecoder.rs":"7b7b7fba57714a3baf0fe881010a9f5a9814bf26b9283a6d56d1c44010cbd822","src/lib.rs":"f6ee17bc45cafdccb562340a4d253a517c5366a74d07c38960aedc2554fe783c","src/log.rs":"943e4e332400d94805d60f965d1d0ae7aad180f6d5b50936d0bd9e085bbc1502","src/once.rs":"d8b2bf7a9e3ce83bdd7f29d8f73ce7ad0268c9618ae7255028fea9f90c9c9fd6","src/timer.rs":"56082a6ecb45bd31c7c677c4c1f0830e55821c860e70b5637b2015fa3be63743","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
|
2
third_party/rust/neqo-common/Cargo.toml
vendored
2
third_party/rust/neqo-common/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-common"
|
||||
version = "0.1.14"
|
||||
version = "0.2.0"
|
||||
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"7c3b530c7717ad3e5c3da4ab280ae04d2c897c9a5ac411717392d057605404ed","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"00ff7348732c956b4f8829f00df2b18b3a7211f5fa2a4cea4ae40c0f859e5f50","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":"eb324a3f076f0079acc0332379bc68ba6fb1232c3f9e44ef63334fe625d569c1","src/aead.rs":"2013408fbcf9e93331ae14d9d6bdd096966f125b3cf48f83e671f537e89d4e77","src/agent.rs":"5f460010eff4a604b23c456b5cff132f995b30767f0188285fdf39d7724ecf6f","src/agentio.rs":"aeb91f3e4c4cc5b8a816307747090c5df02924801511f9523f9d767fe9dd67e9","src/auth.rs":"71ac7e297a5f872d26cf67b6bbd96e4548ea38374bdd84c1094f76a5de4ed1cb","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"e756c07525bd7c2ff271e504708f903b3ede0a3ae821446bd37701055eb11f5f","src/err.rs":"04f38831ca62d29d8aadfe9daf95fd29e68ece184e6d3e00bfb9ee1d12744033","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"bf7b5f23caf26ab14fba3baf0823dd093e4194f759779e4cfd608478312ed58c","src/hkdf.rs":"1bb57806bbf67af74966bb2bb724de9d6b0094c6f5cddbe12d46292d58ba1f16","src/hp.rs":"0384bc676d8cc66a2cfec7be9df176f04557e4f1424c6d19d03ba5687920ac86","src/lib.rs":"49e0ad22fb5aec2e0864b907cb6d419389d53014e33c147f53198b440ec8929f","src/p11.rs":"6e94cbb594b709c3081449bf50d9961d36648b5db95fb824779bff4f45125ad2","src/prio.rs":"bc4e97049563b136cb7b39f5171e7909d56a77ed46690aaacb781eeb4a4743e0","src/replay.rs":"9bc5826cc8be6afe787f0d403b3958245efce9bfbc7b3100734e5aec3f8b9753","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"531ec0de048f55108f2612d8f330bee18ffd58b3b26124ca290cc14cec8671dc","src/selfencrypt.rs":"02e963e8b9ea0802f7ee64384e5ccef3e31420e75bc1aacd02270dd504ffbdb1","src/ssl.rs":"ee0e638bd0a6ce2f01ecb6a1c1a203ac7a7ae8145b889a0d6f2015f98d65c4b4","src/time.rs":"d77f0f276385603633b2078f05ff9b4dddc8cfb84c595697689876b6996f69d2","tests/aead.rs":"cccac271087fe37d0a890e5da04984bbfacb4bc12331473dfc189e4d6ebff5f2","tests/agent.rs":"4fa8fa803266b985e9b6329e6a218fe7bd779200b8e0cfa94f5813e0ccc10995","tests/ext.rs":"f5edc1f229703f786ec31a8035465c00275223f14a3c4abe52f3c7cf2686cc03","tests/handshake.rs":"bcc687c0e1b485658847faf28a9f5dbfdb297812bed1bd2e80593d5f9e1fee36","tests/hkdf.rs":"0e4853f629050ba4d8069be52b7a441b670d1abaf6b8cd670a8215e0b88beb37","tests/hp.rs":"e6dd3cb4bceebc6fca8f270d8302ef34e14bda6c91fc4f9342ba1681be57ee03","tests/init.rs":"55df7cb95deb629f8701b55a8bcb91e797f30fb10e847a36a0a5a4e80488b002","tests/selfencrypt.rs":"60bfe8a0729cdaa6c2171146083266fa0e625a1d98b5f8735cd22b725d32398b"},"package":null}
|
||||
{"files":{"Cargo.toml":"e72807e07438caec6dc6a21ecfc35d8e4703e66a822ec0194aa2258cef4e753f","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"00ff7348732c956b4f8829f00df2b18b3a7211f5fa2a4cea4ae40c0f859e5f50","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":"eb324a3f076f0079acc0332379bc68ba6fb1232c3f9e44ef63334fe625d569c1","src/aead.rs":"2013408fbcf9e93331ae14d9d6bdd096966f125b3cf48f83e671f537e89d4e77","src/agent.rs":"5f460010eff4a604b23c456b5cff132f995b30767f0188285fdf39d7724ecf6f","src/agentio.rs":"aeb91f3e4c4cc5b8a816307747090c5df02924801511f9523f9d767fe9dd67e9","src/auth.rs":"71ac7e297a5f872d26cf67b6bbd96e4548ea38374bdd84c1094f76a5de4ed1cb","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"e756c07525bd7c2ff271e504708f903b3ede0a3ae821446bd37701055eb11f5f","src/err.rs":"04f38831ca62d29d8aadfe9daf95fd29e68ece184e6d3e00bfb9ee1d12744033","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"bf7b5f23caf26ab14fba3baf0823dd093e4194f759779e4cfd608478312ed58c","src/hkdf.rs":"1bb57806bbf67af74966bb2bb724de9d6b0094c6f5cddbe12d46292d58ba1f16","src/hp.rs":"0384bc676d8cc66a2cfec7be9df176f04557e4f1424c6d19d03ba5687920ac86","src/lib.rs":"49e0ad22fb5aec2e0864b907cb6d419389d53014e33c147f53198b440ec8929f","src/p11.rs":"6e94cbb594b709c3081449bf50d9961d36648b5db95fb824779bff4f45125ad2","src/prio.rs":"bc4e97049563b136cb7b39f5171e7909d56a77ed46690aaacb781eeb4a4743e0","src/replay.rs":"9bc5826cc8be6afe787f0d403b3958245efce9bfbc7b3100734e5aec3f8b9753","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"531ec0de048f55108f2612d8f330bee18ffd58b3b26124ca290cc14cec8671dc","src/selfencrypt.rs":"02e963e8b9ea0802f7ee64384e5ccef3e31420e75bc1aacd02270dd504ffbdb1","src/ssl.rs":"ee0e638bd0a6ce2f01ecb6a1c1a203ac7a7ae8145b889a0d6f2015f98d65c4b4","src/time.rs":"d77f0f276385603633b2078f05ff9b4dddc8cfb84c595697689876b6996f69d2","tests/aead.rs":"cccac271087fe37d0a890e5da04984bbfacb4bc12331473dfc189e4d6ebff5f2","tests/agent.rs":"4fa8fa803266b985e9b6329e6a218fe7bd779200b8e0cfa94f5813e0ccc10995","tests/ext.rs":"f5edc1f229703f786ec31a8035465c00275223f14a3c4abe52f3c7cf2686cc03","tests/handshake.rs":"bcc687c0e1b485658847faf28a9f5dbfdb297812bed1bd2e80593d5f9e1fee36","tests/hkdf.rs":"0e4853f629050ba4d8069be52b7a441b670d1abaf6b8cd670a8215e0b88beb37","tests/hp.rs":"e6dd3cb4bceebc6fca8f270d8302ef34e14bda6c91fc4f9342ba1681be57ee03","tests/init.rs":"55df7cb95deb629f8701b55a8bcb91e797f30fb10e847a36a0a5a4e80488b002","tests/selfencrypt.rs":"60bfe8a0729cdaa6c2171146083266fa0e625a1d98b5f8735cd22b725d32398b"},"package":null}
|
2
third_party/rust/neqo-crypto/Cargo.toml
vendored
2
third_party/rust/neqo-crypto/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-crypto"
|
||||
version = "0.1.14"
|
||||
version = "0.2.0"
|
||||
authors = ["Martin Thomson <mt@lowentropy.net>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"78607779e3698b42d8f05f088fd53cb549d8c30c09f7d3d2ab6dfe2b272ecedf","src/client_events.rs":"8e77e6e92c3d5933621f2baee3baacab230486ad8b6df1eca321ea74ed7cdcbd","src/connection.rs":"8499ea115fc061eb5d2eedb0a5cac6069a255ad756e6e89ce2f6e6a8dc5772fc","src/connection_client.rs":"2c8e7ffc5b67defef0e2a43b0053d1044b2ce4e83cadf1d3ee4d1e313cec35ff","src/connection_server.rs":"a32edf220f4664dccfc80141128a211d9997d86e8e988726c1380836015f1d0e","src/control_stream_local.rs":"319f8277fc4765b31a4a094bfd663e681d71831532925b0043bae5da96202e64","src/control_stream_remote.rs":"c205633af8539cd55f289071c6845b5bb2b0a9778f15976829c5d4a492360e19","src/hframe.rs":"8733c3af83da5ddbc6aa238710662fdba7f790bf266d242b40d727f68315d1cc","src/hsettings_frame.rs":"349a4413ce13f03e05264e6c4b22d231276a1c96e3983aada4478b038ec89dbc","src/lib.rs":"f47849cc5f47945c95aa58a9ed830ff512572512f0b3a7ddb6b545e9e16e08bf","src/server.rs":"212b98c363c0160304eaf02bb73dad6138236f52390ab7664ce4984657fdcca3","src/server_connection_events.rs":"d2b973a095f29cb0ac6fb84705165b034960d09b2dde7693bab96e6b802c6fba","src/server_events.rs":"f997bd329d45115f6a527eba8f0f1ecf21c0dd9a3184f08fc5002e34f4cfe2f0","src/stream_type_reader.rs":"da2b7b0358cb4829493cb964cae67c85e9efdf4127958aade7a56733ddc4f12e","src/transaction_client.rs":"65f0cea42843ad9057f587d6ef0a1751f46fe13db468904434ebaeb27f763a84","src/transaction_server.rs":"8603c3f835f680e2c63c1ed1b5962b208acd476a12e4bb7221d68b36c57c505a","tests/httpconn.rs":"7955f6ac4406b5d770e0fb10258aff529a1c01020374dfc5f85d8608abb68f6f"},"package":null}
|
||||
{"files":{"Cargo.toml":"0306007b0f3347e400f1a355353d1abd129e384c5896974e22856028a060a531","src/client_events.rs":"8e77e6e92c3d5933621f2baee3baacab230486ad8b6df1eca321ea74ed7cdcbd","src/connection.rs":"8499ea115fc061eb5d2eedb0a5cac6069a255ad756e6e89ce2f6e6a8dc5772fc","src/connection_client.rs":"b803756b3a81f16757e672023a1424c1f60b07ca9f5351475258814e92ab0a2c","src/connection_server.rs":"a32edf220f4664dccfc80141128a211d9997d86e8e988726c1380836015f1d0e","src/control_stream_local.rs":"319f8277fc4765b31a4a094bfd663e681d71831532925b0043bae5da96202e64","src/control_stream_remote.rs":"c205633af8539cd55f289071c6845b5bb2b0a9778f15976829c5d4a492360e19","src/hframe.rs":"5b580d431ae9639bebfa1868a8f4f358e46884c34b81011126745e64244e4323","src/hsettings_frame.rs":"349a4413ce13f03e05264e6c4b22d231276a1c96e3983aada4478b038ec89dbc","src/lib.rs":"383bfaacfe138a7cbbd9162973a430016ee0fc59cd3ae087743cf37c148f7edd","src/response_stream.rs":"808c40e0bc51599e2b253cf9d535ae8404abaccc7fd875f8e08eafdfaeab3012","src/server.rs":"212b98c363c0160304eaf02bb73dad6138236f52390ab7664ce4984657fdcca3","src/server_connection_events.rs":"d2b973a095f29cb0ac6fb84705165b034960d09b2dde7693bab96e6b802c6fba","src/server_events.rs":"f997bd329d45115f6a527eba8f0f1ecf21c0dd9a3184f08fc5002e34f4cfe2f0","src/stream_type_reader.rs":"da2b7b0358cb4829493cb964cae67c85e9efdf4127958aade7a56733ddc4f12e","src/transaction_client.rs":"8a96f2acb0cd6f7c09d1e9b92a71171a474d46c7e21b55e546aa4d6c330981d3","src/transaction_server.rs":"1af45a238950acfc563484d2b5ebe805a83bdcc1096f5c03ed8d180c4e7428d5","tests/httpconn.rs":"7955f6ac4406b5d770e0fb10258aff529a1c01020374dfc5f85d8608abb68f6f"},"package":null}
|
2
third_party/rust/neqo-http3/Cargo.toml
vendored
2
third_party/rust/neqo-http3/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-http3"
|
||||
version = "0.1.14"
|
||||
version = "0.2.0"
|
||||
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
236
third_party/rust/neqo-http3/src/connection_client.rs
vendored
236
third_party/rust/neqo-http3/src/connection_client.rs
vendored
@ -709,6 +709,18 @@ mod tests {
|
||||
0x43, 0xd3, 0xc1,
|
||||
];
|
||||
|
||||
const HTTP_HEADER_FRAME_0: &[u8] = &[0x01, 0x06, 0x00, 0x00, 0xd9, 0x54, 0x01, 0x30];
|
||||
|
||||
// The response header from HTTP_HEADER_FRAME (0x01, 0x06, 0x00, 0x00, 0xd9, 0x54, 0x01, 0x30) are
|
||||
// decoded into:
|
||||
fn check_response_header_0(header: Vec<Header>) {
|
||||
let expected_response_header_1 = vec![
|
||||
(String::from(":status"), String::from("200")),
|
||||
(String::from("content-length"), String::from("0")),
|
||||
];
|
||||
assert_eq!(header, expected_response_header_1);
|
||||
}
|
||||
|
||||
const HTTP_RESPONSE_1: &[u8] = &[
|
||||
// headers
|
||||
0x01, 0x06, 0x00, 0x00, 0xd9, 0x54, 0x01, 0x37, // the first data frame
|
||||
@ -2317,11 +2329,10 @@ mod tests {
|
||||
.encoder
|
||||
.encode_header_block(&headers, request_stream_id);
|
||||
let hframe = HFrame::Headers {
|
||||
len: encoded_headers.len() as u64,
|
||||
header_block: encoded_headers.to_vec(),
|
||||
};
|
||||
let mut d = Encoder::default();
|
||||
hframe.encode(&mut d);
|
||||
d.encode(&encoded_headers);
|
||||
let d_frame = HFrame::Data { len: 3 };
|
||||
d_frame.encode(&mut d);
|
||||
d.encode(&[0x61, 0x62, 0x63]);
|
||||
@ -2364,6 +2375,60 @@ mod tests {
|
||||
assert!(recv_header && recv_data);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_frames_header_blocked_with_fin_after_headers() {
|
||||
let (mut hconn, mut server, request_stream_id) = connect_and_send_request(true);
|
||||
|
||||
server.encoder.set_max_capacity(100).unwrap();
|
||||
server.encoder.set_max_blocked_streams(100).unwrap();
|
||||
|
||||
let headers = vec![
|
||||
(String::from(":status"), String::from("200")),
|
||||
(String::from("my-header"), String::from("my-header")),
|
||||
(String::from("content-length"), String::from("0")),
|
||||
];
|
||||
let encoded_headers = server
|
||||
.encoder
|
||||
.encode_header_block(&headers, request_stream_id);
|
||||
let hframe = HFrame::Headers {
|
||||
header_block: encoded_headers.to_vec(),
|
||||
};
|
||||
let mut d = Encoder::default();
|
||||
hframe.encode(&mut d);
|
||||
|
||||
let _ = server.conn.stream_send(request_stream_id, &d[..]);
|
||||
server.conn.stream_close_send(request_stream_id).unwrap();
|
||||
|
||||
// Send response before sending encoder instructions.
|
||||
let out = server.conn.process(None, now());
|
||||
let _out = hconn.process(out.dgram(), now());
|
||||
|
||||
let header_ready_event = |e| matches!(e, Http3ClientEvent::HeaderReady { .. });
|
||||
assert!(!hconn.events().any(header_ready_event));
|
||||
|
||||
// Send encoder instructions to unblock the stream.
|
||||
server.encoder.send(&mut server.conn).unwrap();
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
let _out = hconn.process(out.dgram(), now());
|
||||
let _out = hconn.process(None, now());
|
||||
|
||||
let mut recv_header = false;
|
||||
// Now the stream is unblocked. After headers we will receive a fin.
|
||||
while let Some(e) = hconn.next_event() {
|
||||
if let Http3ClientEvent::HeaderReady { stream_id } = e {
|
||||
assert_eq!(stream_id, request_stream_id);
|
||||
let (h, fin) = hconn.read_response_headers(stream_id).unwrap();
|
||||
assert_eq!(h, headers);
|
||||
assert_eq!(fin, true);
|
||||
recv_header = true;
|
||||
} else {
|
||||
panic!("event {:?}", e);
|
||||
}
|
||||
}
|
||||
assert!(recv_header);
|
||||
}
|
||||
|
||||
fn check_control_qpack_request_streams_resumption(
|
||||
server: &mut Connection,
|
||||
expect_encoder_stream_data: &[u8],
|
||||
@ -2907,4 +2972,171 @@ mod tests {
|
||||
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailers_with_fin_after_headers() {
|
||||
// Make a new connection.
|
||||
let (mut client, mut server, request_stream_id) = connect_and_send_request(true);
|
||||
|
||||
// Send HEADER frame.
|
||||
let _ = server
|
||||
.conn
|
||||
.stream_send(request_stream_id, HTTP_HEADER_FRAME_0);
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
|
||||
// Check response headers.
|
||||
let mut response_headers = false;
|
||||
while let Some(e) = client.next_event() {
|
||||
if let Http3ClientEvent::HeaderReady { stream_id } = e {
|
||||
assert_eq!(stream_id, request_stream_id);
|
||||
let (h, fin) = client.read_response_headers(stream_id).unwrap();
|
||||
check_response_header_0(h);
|
||||
assert_eq!(fin, false);
|
||||
response_headers = true;
|
||||
}
|
||||
}
|
||||
assert!(response_headers);
|
||||
|
||||
// Send trailers
|
||||
let _ = server
|
||||
.conn
|
||||
.stream_send(request_stream_id, HTTP_HEADER_FRAME_0);
|
||||
server.conn.stream_close_send(request_stream_id).unwrap();
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
|
||||
let events: Vec<Http3ClientEvent> = client.events().collect();
|
||||
|
||||
// We already had HeaderReady
|
||||
let header_ready: fn(&Http3ClientEvent) -> _ =
|
||||
|e| matches!(*e, Http3ClientEvent::HeaderReady { .. });
|
||||
assert!(!events.clone().iter().any(header_ready));
|
||||
|
||||
// Check that we have a DataReady event. Reading from the stream will return fin=true.
|
||||
let data_readable: fn(&Http3ClientEvent) -> _ =
|
||||
|e| matches!(*e, Http3ClientEvent::DataReadable { .. });
|
||||
assert!(events.iter().any(data_readable));
|
||||
let mut buf = [0u8; 100];
|
||||
let (len, fin) = client
|
||||
.read_response_data(now(), request_stream_id, &mut buf)
|
||||
.unwrap();
|
||||
assert_eq!(0, len);
|
||||
assert_eq!(fin, true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailers_with_later_fin_after_headers() {
|
||||
// Make a new connection.
|
||||
let (mut client, mut server, request_stream_id) = connect_and_send_request(true);
|
||||
|
||||
// Send HEADER frame.
|
||||
let _ = server
|
||||
.conn
|
||||
.stream_send(request_stream_id, HTTP_HEADER_FRAME_0);
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
|
||||
// Check response headers.
|
||||
let mut response_headers = false;
|
||||
while let Some(e) = client.next_event() {
|
||||
if let Http3ClientEvent::HeaderReady { stream_id } = e {
|
||||
assert_eq!(stream_id, request_stream_id);
|
||||
let (h, fin) = client.read_response_headers(stream_id).unwrap();
|
||||
check_response_header_0(h);
|
||||
assert_eq!(fin, false);
|
||||
response_headers = true;
|
||||
}
|
||||
}
|
||||
assert!(response_headers);
|
||||
|
||||
// Send trailers
|
||||
let _ = server
|
||||
.conn
|
||||
.stream_send(request_stream_id, HTTP_HEADER_FRAME_0);
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
|
||||
// Check that we do not have a DataReady event.
|
||||
let data_readable = |e| matches!(e, Http3ClientEvent::DataReadable { .. });
|
||||
assert!(!client.events().any(data_readable));
|
||||
|
||||
server.conn.stream_close_send(request_stream_id).unwrap();
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
|
||||
let events: Vec<Http3ClientEvent> = client.events().collect();
|
||||
|
||||
// We already had HeaderReady
|
||||
let header_ready: fn(&Http3ClientEvent) -> _ =
|
||||
|e| matches!(*e, Http3ClientEvent::HeaderReady { .. });
|
||||
assert!(!events.clone().iter().any(header_ready));
|
||||
|
||||
// Check that we have a DataReady event. Reading from the stream will return fin=true.
|
||||
let data_readable: fn(&Http3ClientEvent) -> _ =
|
||||
|e| matches!(*e, Http3ClientEvent::DataReadable { .. });
|
||||
assert!(events.iter().any(data_readable));
|
||||
let mut buf = [0u8; 100];
|
||||
let (len, fin) = client
|
||||
.read_response_data(now(), request_stream_id, &mut buf)
|
||||
.unwrap();
|
||||
assert_eq!(0, len);
|
||||
assert_eq!(fin, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_data_after_trailers_after_headers() {
|
||||
// Make a new connection.
|
||||
let (mut client, mut server, request_stream_id) = connect_and_send_request(true);
|
||||
|
||||
// Send HEADER frame.
|
||||
let _ = server
|
||||
.conn
|
||||
.stream_send(request_stream_id, HTTP_HEADER_FRAME_0);
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
|
||||
// Check response headers.
|
||||
let mut response_headers = false;
|
||||
while let Some(e) = client.next_event() {
|
||||
if let Http3ClientEvent::HeaderReady { stream_id } = e {
|
||||
assert_eq!(stream_id, request_stream_id);
|
||||
let (h, fin) = client.read_response_headers(stream_id).unwrap();
|
||||
check_response_header_0(h);
|
||||
assert_eq!(fin, false);
|
||||
response_headers = true;
|
||||
}
|
||||
}
|
||||
assert!(response_headers);
|
||||
|
||||
// Send trailers
|
||||
let _ = server
|
||||
.conn
|
||||
.stream_send(request_stream_id, HTTP_HEADER_FRAME_0);
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
// Check that we do not have a DataReady event.
|
||||
let data_readable = |e| matches!(e, Http3ClientEvent::DataReadable { .. });
|
||||
assert!(!client.events().any(data_readable));
|
||||
|
||||
// Send Data frame.
|
||||
let _ = server.conn.stream_send(
|
||||
request_stream_id,
|
||||
&[
|
||||
// data frame
|
||||
0x0, 0x3, 0x61, 0x62, 0x63,
|
||||
],
|
||||
);
|
||||
|
||||
let out = server.conn.process(None, now());
|
||||
client.process(out.dgram(), now());
|
||||
assert_closed(&client, Error::HttpFrameUnexpected);
|
||||
}
|
||||
}
|
||||
|
57
third_party/rust/neqo-http3/src/hframe.rs
vendored
57
third_party/rust/neqo-http3/src/hframe.rs
vendored
@ -32,14 +32,14 @@ pub enum HStreamType {
|
||||
Push,
|
||||
}
|
||||
|
||||
// data for DATA and header blocks for HEADERS anf PUSH_PROMISE are not read into HFrame.
|
||||
// data for DATA frame is not read into HFrame::Data.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum HFrame {
|
||||
Data {
|
||||
len: u64, // length of the data
|
||||
},
|
||||
Headers {
|
||||
len: u64, // length of the header block
|
||||
header_block: Vec<u8>,
|
||||
},
|
||||
CancelPush {
|
||||
push_id: u64,
|
||||
@ -80,10 +80,13 @@ impl HFrame {
|
||||
enc.encode_varint(self.get_type());
|
||||
|
||||
match self {
|
||||
Self::Data { len } | Self::Headers { len } => {
|
||||
// DATA and HEADERS frames only encode the length here.
|
||||
Self::Data { len } => {
|
||||
// DATA frame only encode the length here.
|
||||
enc.encode_varint(*len);
|
||||
}
|
||||
Self::Headers { header_block } => {
|
||||
enc.encode_vvec(header_block);
|
||||
}
|
||||
Self::CancelPush { push_id } => {
|
||||
enc.encode_vvec_with(|enc_inner| {
|
||||
enc_inner.encode_varint(*push_id);
|
||||
@ -235,10 +238,8 @@ impl HFrameReader {
|
||||
);
|
||||
self.hframe_len = len;
|
||||
self.state = match self.hframe_type {
|
||||
// DATA and HEADERS payload are left on the quic stream and picked up separately
|
||||
H3_FRAME_TYPE_DATA | H3_FRAME_TYPE_HEADERS => {
|
||||
HFrameReaderState::Done
|
||||
}
|
||||
// DATA payload are left on the quic stream and picked up separately
|
||||
H3_FRAME_TYPE_DATA => HFrameReaderState::Done,
|
||||
|
||||
// for other frames get all data before decoding.
|
||||
H3_FRAME_TYPE_CANCEL_PUSH
|
||||
@ -246,7 +247,8 @@ impl HFrameReader {
|
||||
| H3_FRAME_TYPE_GOAWAY
|
||||
| H3_FRAME_TYPE_MAX_PUSH_ID
|
||||
| H3_FRAME_TYPE_DUPLICATE_PUSH
|
||||
| H3_FRAME_TYPE_PUSH_PROMISE => {
|
||||
| H3_FRAME_TYPE_PUSH_PROMISE
|
||||
| H3_FRAME_TYPE_HEADERS => {
|
||||
if len == 0 {
|
||||
HFrameReaderState::Done
|
||||
} else {
|
||||
@ -329,7 +331,7 @@ impl HFrameReader {
|
||||
len: self.hframe_len,
|
||||
},
|
||||
H3_FRAME_TYPE_HEADERS => HFrame::Headers {
|
||||
len: self.hframe_len,
|
||||
header_block: dec.decode_remainder().to_vec(),
|
||||
},
|
||||
H3_FRAME_TYPE_CANCEL_PUSH => HFrame::CancelPush {
|
||||
push_id: match dec.decode_varint() {
|
||||
@ -448,8 +450,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_headers_frame() {
|
||||
let f = HFrame::Headers { len: 3 };
|
||||
enc_dec(&f, "0103010203", 3);
|
||||
let f = HFrame::Headers {
|
||||
header_block: vec![0x01, 0x02, 0x03],
|
||||
};
|
||||
enc_dec(&f, "0103010203", 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -493,10 +497,9 @@ mod tests {
|
||||
enc_dec(&f, "0e0105", 0);
|
||||
}
|
||||
|
||||
// We have 3 code paths in frame_reader:
|
||||
// 1) All frames except DATA, HEADERES and PUSH_PROMISE (here we test SETTING and SETTINGS with larger varints)
|
||||
// 2) PUSH_PROMISE and
|
||||
// 1) DATA and HEADERS frame (for this we will test DATA)
|
||||
// We have 2 code paths in frame_reader:
|
||||
// 1) All frames except DATA (here we test SETTING and SETTINGS with larger varints and PUSH_PROMISE)
|
||||
// 1) DATA
|
||||
|
||||
// Test SETTINGS
|
||||
#[test]
|
||||
@ -914,6 +917,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_complete_and_incomplete_frames() {
|
||||
const FRAME_LEN: usize = 10;
|
||||
const HEADER_BLOCK: &[u8] = &[0x01, 0x02, 0x03, 0x04];
|
||||
|
||||
// H3_FRAME_TYPE_DATA len=0
|
||||
let f = HFrame::Data { len: 0 };
|
||||
@ -932,22 +936,23 @@ mod tests {
|
||||
buf.resize(FRAME_LEN + buf.len(), 0);
|
||||
test_complete_and_incomplete_frame(&buf, 2);
|
||||
|
||||
// H3_FRAME_TYPE_HEADERS len=0
|
||||
let f = HFrame::Data { len: 0 };
|
||||
let mut enc = Encoder::with_capacity(2);
|
||||
// H3_FRAME_TYPE_HEADERS empty header block
|
||||
let f = HFrame::Headers {
|
||||
header_block: Vec::new(),
|
||||
};
|
||||
let mut enc = Encoder::default();
|
||||
f.encode(&mut enc);
|
||||
let buf: Vec<_> = enc.into();
|
||||
test_complete_and_incomplete_frame(&buf, 2);
|
||||
|
||||
// H3_FRAME_TYPE_HEADERS len=FRAME_LEN
|
||||
// H3_FRAME_TYPE_HEADERS
|
||||
let f = HFrame::Headers {
|
||||
len: FRAME_LEN as u64,
|
||||
header_block: HEADER_BLOCK.to_vec(),
|
||||
};
|
||||
let mut enc = Encoder::with_capacity(2);
|
||||
let mut enc = Encoder::default();
|
||||
f.encode(&mut enc);
|
||||
let mut buf: Vec<_> = enc.into();
|
||||
buf.resize(FRAME_LEN + buf.len(), 0);
|
||||
test_complete_and_incomplete_frame(&buf, 2);
|
||||
let buf: Vec<_> = enc.into();
|
||||
test_complete_and_incomplete_frame(&buf, buf.len());
|
||||
|
||||
// H3_FRAME_TYPE_CANCEL_PUSH
|
||||
let f = HFrame::CancelPush { push_id: 5 };
|
||||
@ -968,7 +973,7 @@ mod tests {
|
||||
// H3_FRAME_TYPE_PUSH_PROMISE
|
||||
let f = HFrame::PushPromise {
|
||||
push_id: 4,
|
||||
header_block: vec![0x01, 0x02, 0x03, 0x04],
|
||||
header_block: HEADER_BLOCK.to_vec(),
|
||||
};
|
||||
let mut enc = Encoder::default();
|
||||
f.encode(&mut enc);
|
||||
|
1
third_party/rust/neqo-http3/src/lib.rs
vendored
1
third_party/rust/neqo-http3/src/lib.rs
vendored
@ -15,6 +15,7 @@ mod control_stream_local;
|
||||
mod control_stream_remote;
|
||||
pub mod hframe;
|
||||
mod hsettings_frame;
|
||||
mod response_stream;
|
||||
pub mod server;
|
||||
mod server_connection_events;
|
||||
mod server_events;
|
||||
|
300
third_party/rust/neqo-http3/src/response_stream.rs
vendored
Normal file
300
third_party/rust/neqo-http3/src/response_stream.rs
vendored
Normal file
@ -0,0 +1,300 @@
|
||||
// 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;
|
||||
use crate::hframe::{HFrame, HFrameReader};
|
||||
use crate::{Error, Header, Res};
|
||||
use neqo_common::{matches, qdebug, qinfo, qtrace};
|
||||
use neqo_qpack::decoder::QPackDecoder;
|
||||
use neqo_transport::Connection;
|
||||
use std::cmp::min;
|
||||
use std::mem;
|
||||
|
||||
/*
|
||||
* Response stream state:
|
||||
* WaitingForResponseHeaders : we wait for headers. in this state we can
|
||||
* also get a PUSH_PROMISE frame.
|
||||
* DecodingHeaders : In this step the headers will be decoded. The stream
|
||||
* may be blocked in this state on encoder instructions.
|
||||
* WaitingForData : we got HEADERS, we are waiting for one or more data
|
||||
* frames. In this state we can receive one or more
|
||||
* PUSH_PROMIS frames or a HEADERS frame carrying trailers.
|
||||
* ReadingData : we got a DATA frame, now we letting the app read payload.
|
||||
* From here we will go back to WaitingForData state to wait
|
||||
* for more data frames or to CLosed state
|
||||
* ClosePending : waiting for app to pick up data, after that we can delete
|
||||
* the TransactionClient.
|
||||
* Closed
|
||||
*/
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum ResponseStreamState {
|
||||
WaitingForResponseHeaders,
|
||||
DecodingHeaders { header_block: Vec<u8>, fin: bool },
|
||||
WaitingForData,
|
||||
ReadingData { remaining_data_len: usize },
|
||||
WaitingForFinAfterTrailers,
|
||||
ClosePending, // Close must first be read by application
|
||||
Closed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ResponseHeadersState {
|
||||
NoHeaders,
|
||||
Ready(Option<Vec<Header>>),
|
||||
Read,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ResponseStream {
|
||||
state: ResponseStreamState,
|
||||
frame_reader: HFrameReader,
|
||||
response_headers_state: ResponseHeadersState,
|
||||
conn_events: Http3ClientEvents,
|
||||
stream_id: u64,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for ResponseStream {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "ResponseStream stream_id:{}", self.stream_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseStream {
|
||||
pub fn new(stream_id: u64, conn_events: Http3ClientEvents) -> Self {
|
||||
Self {
|
||||
state: ResponseStreamState::WaitingForResponseHeaders,
|
||||
frame_reader: HFrameReader::new(),
|
||||
response_headers_state: ResponseHeadersState::NoHeaders,
|
||||
conn_events,
|
||||
stream_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_headers_frame(&mut self, header_block: Vec<u8>, fin: bool) -> Res<()> {
|
||||
match self.state {
|
||||
ResponseStreamState::WaitingForResponseHeaders => {
|
||||
if header_block.is_empty() {
|
||||
self.add_headers(None)?;
|
||||
} else {
|
||||
self.state = ResponseStreamState::DecodingHeaders { header_block, fin };
|
||||
}
|
||||
}
|
||||
ResponseStreamState::WaitingForData => {
|
||||
// TODO implement trailers, for now just ignore them.
|
||||
self.state = ResponseStreamState::WaitingForFinAfterTrailers;
|
||||
}
|
||||
ResponseStreamState::WaitingForFinAfterTrailers => {
|
||||
return Err(Error::HttpFrameUnexpected);
|
||||
}
|
||||
_ => unreachable!("This functions is only called in WaitingForResponseHeaders | WaitingForData | WaitingForFinAfterTrailers state.")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_data_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
match self.state {
|
||||
ResponseStreamState::WaitingForResponseHeaders | ResponseStreamState::WaitingForFinAfterTrailers => {
|
||||
return Err(Error::HttpFrameUnexpected);
|
||||
}
|
||||
ResponseStreamState::WaitingForData => {
|
||||
if len > 0 {
|
||||
if fin {
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
self.state = ResponseStreamState::ReadingData {
|
||||
remaining_data_len: len as usize,
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => unreachable!("This functions is only called in WaitingForResponseHeaders | WaitingForData | WaitingForFinAfterTrailers state.")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_headers(&mut self, headers: Option<Vec<Header>>) -> Res<()> {
|
||||
if self.response_headers_state != ResponseHeadersState::NoHeaders {
|
||||
debug_assert!(
|
||||
false,
|
||||
"self.response_headers_state must be in state ResponseHeadersState::NoHeaders."
|
||||
);
|
||||
return Err(Error::HttpInternalError);
|
||||
}
|
||||
self.response_headers_state = ResponseHeadersState::Ready(headers);
|
||||
self.conn_events.header_ready(self.stream_id);
|
||||
self.state = ResponseStreamState::WaitingForData;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_state_to_close_pending(&mut self) {
|
||||
// Stream has received fin. Depending on headers state set header_ready
|
||||
// or data_readable event so that app can pick up the fin.
|
||||
qtrace!(
|
||||
[self],
|
||||
"set_state_to_close_pending: response_headers_state={:?}",
|
||||
self.response_headers_state
|
||||
);
|
||||
match self.response_headers_state {
|
||||
ResponseHeadersState::NoHeaders => {
|
||||
self.conn_events.header_ready(self.stream_id);
|
||||
self.response_headers_state = ResponseHeadersState::Ready(None);
|
||||
}
|
||||
// In Ready state we are already waiting for app to pick up headers
|
||||
// it can also pick up fin, so we do not need a new event.
|
||||
ResponseHeadersState::Ready(..) => {}
|
||||
ResponseHeadersState::Read => self.conn_events.data_readable(self.stream_id),
|
||||
}
|
||||
self.state = ResponseStreamState::ClosePending;
|
||||
}
|
||||
|
||||
fn recv_frame(&mut self, conn: &mut Connection) -> Res<(Option<HFrame>, bool)> {
|
||||
qtrace!([self], "receiving frame header");
|
||||
let fin = self.frame_reader.receive(conn, self.stream_id)?;
|
||||
if !self.frame_reader.done() {
|
||||
Ok((None, fin))
|
||||
} else {
|
||||
qdebug!([self], "A new frame has been received.");
|
||||
Ok((Some(self.frame_reader.get_frame()?), fin))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_response_headers(&mut self) -> Res<(Vec<Header>, bool)> {
|
||||
if let ResponseHeadersState::Ready(ref mut headers) = self.response_headers_state {
|
||||
let hdrs = if let Some(ref mut hdrs) = headers {
|
||||
mem::replace(hdrs, Vec::new())
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
self.response_headers_state = ResponseHeadersState::Read;
|
||||
|
||||
let fin = if self.state == ResponseStreamState::ClosePending {
|
||||
self.state = ResponseStreamState::Closed;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Ok((hdrs, fin))
|
||||
} else {
|
||||
Err(Error::Unavailable)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_response_data(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
buf: &mut [u8],
|
||||
) -> Res<(usize, bool)> {
|
||||
match self.state {
|
||||
ResponseStreamState::ReadingData {
|
||||
ref mut remaining_data_len,
|
||||
} => {
|
||||
let to_read = min(*remaining_data_len, buf.len());
|
||||
let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[..to_read])?;
|
||||
debug_assert!(amount <= to_read);
|
||||
*remaining_data_len -= amount;
|
||||
|
||||
if fin {
|
||||
if *remaining_data_len > 0 {
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
self.state = ResponseStreamState::Closed;
|
||||
} else if *remaining_data_len == 0 {
|
||||
self.state = ResponseStreamState::WaitingForData;
|
||||
}
|
||||
|
||||
Ok((amount, fin))
|
||||
}
|
||||
ResponseStreamState::ClosePending => {
|
||||
self.state = ResponseStreamState::Closed;
|
||||
Ok((0, true))
|
||||
}
|
||||
_ => Ok((0, false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(&mut self, conn: &mut Connection, decoder: &mut QPackDecoder) -> Res<()> {
|
||||
let label = if ::log::log_enabled!(::log::Level::Debug) {
|
||||
format!("{}", self)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
loop {
|
||||
qdebug!([label], "state={:?}.", self.state);
|
||||
match self.state {
|
||||
// In the following 3 states we need to read frames.
|
||||
ResponseStreamState::WaitingForResponseHeaders
|
||||
| ResponseStreamState::WaitingForData
|
||||
| ResponseStreamState::WaitingForFinAfterTrailers => {
|
||||
match self.recv_frame(conn)? {
|
||||
(None, true) => {
|
||||
self.set_state_to_close_pending();
|
||||
break Ok(());
|
||||
}
|
||||
(None, false) => break Ok(()),
|
||||
(Some(frame), fin) => {
|
||||
qinfo!(
|
||||
[self],
|
||||
"A new frame has been received: {:?}; state={:?}",
|
||||
frame,
|
||||
self.state
|
||||
);
|
||||
match frame {
|
||||
HFrame::Headers { header_block } => {
|
||||
self.handle_headers_frame(header_block, fin)?
|
||||
}
|
||||
HFrame::Data { len } => self.handle_data_frame(len, fin)?,
|
||||
HFrame::PushPromise { .. } | HFrame::DuplicatePush { .. } => {
|
||||
break Err(Error::HttpIdError)
|
||||
}
|
||||
_ => break Err(Error::HttpFrameUnexpected),
|
||||
}
|
||||
if fin
|
||||
&& !matches!(self.state, ResponseStreamState::DecodingHeaders{..})
|
||||
{
|
||||
self.set_state_to_close_pending();
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
ResponseStreamState::DecodingHeaders {
|
||||
ref header_block,
|
||||
fin,
|
||||
} => match decoder.decode_header_block(header_block, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.add_headers(Some(headers))?;
|
||||
if fin {
|
||||
self.set_state_to_close_pending();
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
qinfo!([self], "decoding header is blocked.");
|
||||
break Ok(());
|
||||
}
|
||||
},
|
||||
ResponseStreamState::ReadingData { .. } => {
|
||||
self.conn_events.data_readable(self.stream_id);
|
||||
break Ok(());
|
||||
}
|
||||
ResponseStreamState::ClosePending => {
|
||||
panic!("Stream readable after being closed!");
|
||||
}
|
||||
ResponseStreamState::Closed => {
|
||||
panic!("Stream readable after being closed!");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.state == ResponseStreamState::Closed
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
self.state = ResponseStreamState::Closed;
|
||||
}
|
||||
}
|
@ -4,19 +4,19 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::hframe::{HFrame, HFrameReader};
|
||||
use crate::hframe::HFrame;
|
||||
|
||||
use crate::client_events::Http3ClientEvents;
|
||||
use crate::connection::Http3Transaction;
|
||||
use crate::response_stream::ResponseStream;
|
||||
use crate::Header;
|
||||
use neqo_common::{qdebug, qinfo, qtrace, qwarn, Encoder};
|
||||
use neqo_common::{qinfo, Encoder};
|
||||
use neqo_qpack::decoder::QPackDecoder;
|
||||
use neqo_qpack::encoder::QPackEncoder;
|
||||
use neqo_transport::Connection;
|
||||
|
||||
use crate::{Error, Res};
|
||||
use std::cmp::min;
|
||||
use std::mem;
|
||||
|
||||
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)
|
||||
@ -59,13 +59,12 @@ impl Request {
|
||||
}
|
||||
|
||||
qinfo!([self], "Encoding headers for {}/{}", self.host, self.path);
|
||||
let encoded_headers = encoder.encode_header_block(&self.headers, stream_id);
|
||||
let header_block = encoder.encode_header_block(&self.headers, stream_id);
|
||||
let f = HFrame::Headers {
|
||||
len: encoded_headers.len() as u64,
|
||||
header_block: header_block.to_vec(),
|
||||
};
|
||||
let mut d = Encoder::default();
|
||||
f.encode(&mut d);
|
||||
d.encode(&encoded_headers[..]);
|
||||
self.buf = Some(d.into());
|
||||
}
|
||||
|
||||
@ -121,53 +120,12 @@ enum TransactionSendState {
|
||||
Closed,
|
||||
}
|
||||
|
||||
/*
|
||||
* Transaction receive state:
|
||||
* WaitingForResponseHeaders : we wait for headers. in this state we can
|
||||
* also get a PUSH_PROMISE frame.
|
||||
* ReadingHeaders : we have HEADERS frame and now we are reading header
|
||||
* block. This may block on encoder instructions. In this
|
||||
* state we do no read from the stream.
|
||||
* BlockedDecodingHeaders : Decoding headers is blocked on encoder
|
||||
* instructions.
|
||||
* WaitingForData : we got HEADERS, we are waiting for one or more data
|
||||
* frames. In this state we can receive one or more
|
||||
* PUSH_PROMIS frames or a HEADERS frame carrying trailers.
|
||||
* ReadingData : we got a DATA frame, now we letting the app read payload.
|
||||
* From here we will go back to WaitingForData state to wait
|
||||
* for more data frames or to CLosed state
|
||||
* ReadingTrailers : reading trailers.
|
||||
* ClosePending : waiting for app to pick up data, after that we can delete
|
||||
* the TransactionClient.
|
||||
* Closed
|
||||
*/
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum TransactionRecvState {
|
||||
WaitingForResponseHeaders,
|
||||
ReadingHeaders { buf: Vec<u8>, offset: usize },
|
||||
BlockedDecodingHeaders { buf: Vec<u8>, fin: bool },
|
||||
WaitingForData,
|
||||
ReadingData { remaining_data_len: usize },
|
||||
// ReadingTrailers,
|
||||
ClosePending, // Close must first be read by application
|
||||
Closed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ResponseHeadersState {
|
||||
NoHeaders,
|
||||
Ready(Option<Vec<Header>>),
|
||||
Read,
|
||||
}
|
||||
|
||||
// This is used for normal request/responses.
|
||||
#[derive(Debug)]
|
||||
pub struct TransactionClient {
|
||||
send_state: TransactionSendState,
|
||||
recv_state: TransactionRecvState,
|
||||
response_stream: ResponseStream,
|
||||
stream_id: u64,
|
||||
frame_reader: HFrameReader,
|
||||
response_headers_state: ResponseHeadersState,
|
||||
conn_events: Http3ClientEvents,
|
||||
}
|
||||
|
||||
@ -187,10 +145,8 @@ impl TransactionClient {
|
||||
request: Request::new(method, scheme, host, path, headers),
|
||||
fin: false,
|
||||
},
|
||||
recv_state: TransactionRecvState::WaitingForResponseHeaders,
|
||||
response_stream: ResponseStream::new(stream_id, conn_events.clone()),
|
||||
stream_id,
|
||||
response_headers_state: ResponseHeadersState::NoHeaders,
|
||||
frame_reader: HFrameReader::new(),
|
||||
conn_events,
|
||||
}
|
||||
}
|
||||
@ -250,167 +206,6 @@ impl TransactionClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_headers(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qinfo!(
|
||||
[self],
|
||||
"A new frame has been received: {:?}; state={:?}",
|
||||
frame,
|
||||
self.recv_state
|
||||
);
|
||||
match frame {
|
||||
HFrame::Headers { len } => self.handle_headers_frame(len, fin),
|
||||
HFrame::PushPromise { .. } => Err(Error::HttpIdError),
|
||||
_ => Err(Error::HttpFrameUnexpected),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_headers_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
if len == 0 {
|
||||
self.add_headers(None)
|
||||
} else {
|
||||
if fin {
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
self.recv_state = TransactionRecvState::ReadingHeaders {
|
||||
buf: vec![0; len as usize],
|
||||
offset: 0,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_data(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qinfo!(
|
||||
[self],
|
||||
"A new frame has been received: {:?}; state={:?}",
|
||||
frame,
|
||||
self.recv_state
|
||||
);
|
||||
match frame {
|
||||
HFrame::Data { len } => self.handle_data_frame(len, fin),
|
||||
HFrame::PushPromise { .. } => Err(Error::HttpIdError),
|
||||
HFrame::Headers { .. } => {
|
||||
// TODO implement trailers!
|
||||
qwarn!([self], "Received trailers");
|
||||
Err(Error::HttpFrameUnexpected)
|
||||
}
|
||||
_ => Err(Error::HttpFrameUnexpected),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_data_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
if len > 0 {
|
||||
if fin {
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
self.recv_state = TransactionRecvState::ReadingData {
|
||||
remaining_data_len: len as usize,
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_headers(&mut self, headers: Option<Vec<Header>>) -> Res<()> {
|
||||
if self.response_headers_state != ResponseHeadersState::NoHeaders {
|
||||
return Err(Error::HttpInternalError);
|
||||
}
|
||||
self.response_headers_state = ResponseHeadersState::Ready(headers);
|
||||
self.conn_events.header_ready(self.stream_id);
|
||||
self.recv_state = TransactionRecvState::WaitingForData;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_state_to_close_pending(&mut self) {
|
||||
// Stream has received fin. Depending on headers state set header_ready
|
||||
// or data_readable event so that app can pick up the fin.
|
||||
qdebug!(
|
||||
[self],
|
||||
"set_state_to_close_pending: response_headers_state={:?}",
|
||||
self.response_headers_state
|
||||
);
|
||||
match self.response_headers_state {
|
||||
ResponseHeadersState::NoHeaders => {
|
||||
self.conn_events.header_ready(self.stream_id);
|
||||
self.response_headers_state = ResponseHeadersState::Ready(None);
|
||||
}
|
||||
// In Ready state we are already waiting for app to pick up headers
|
||||
// it can also pick up fin, so we do not need a new event.
|
||||
ResponseHeadersState::Ready(..) => {}
|
||||
ResponseHeadersState::Read => self.conn_events.data_readable(self.stream_id),
|
||||
}
|
||||
self.recv_state = TransactionRecvState::ClosePending;
|
||||
}
|
||||
|
||||
fn recv_frame_header(&mut self, conn: &mut Connection) -> Res<Option<(HFrame, bool)>> {
|
||||
qtrace!([self], "receiving frame header");
|
||||
let fin = self.frame_reader.receive(conn, self.stream_id)?;
|
||||
if !self.frame_reader.done() {
|
||||
if fin {
|
||||
//we have received stream fin while waiting for a frame.
|
||||
// !self.frame_reader.done() means that we do not have a new
|
||||
// frame at all. Set state to ClosePending and waith for app
|
||||
// to pick up fin.
|
||||
self.set_state_to_close_pending();
|
||||
}
|
||||
Ok(None)
|
||||
} else {
|
||||
qdebug!([self], "A new frame has been received.");
|
||||
Ok(Some((self.frame_reader.get_frame()?, fin)))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_headers_frame_body(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
decoder: &mut QPackDecoder,
|
||||
) -> Res<bool> {
|
||||
let label = if ::log::log_enabled!(::log::Level::Debug) {
|
||||
format!("{}", self)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
if let TransactionRecvState::ReadingHeaders {
|
||||
ref mut buf,
|
||||
ref mut offset,
|
||||
} = self.recv_state
|
||||
{
|
||||
let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[*offset..])?;
|
||||
qdebug!([label], "read_headers: read {} bytes fin={}.", amount, fin);
|
||||
*offset += amount as usize;
|
||||
if *offset < buf.len() {
|
||||
if fin {
|
||||
// Malformated frame
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// we have read the headers, try decoding them.
|
||||
qinfo!(
|
||||
[label],
|
||||
"read_headers: read all headers, try decoding them."
|
||||
);
|
||||
match decoder.decode_header_block(buf, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.add_headers(Some(headers))?;
|
||||
if fin {
|
||||
self.set_state_to_close_pending();
|
||||
}
|
||||
Ok(fin)
|
||||
}
|
||||
None => {
|
||||
let mut tmp: Vec<u8> = Vec::new();
|
||||
mem::swap(&mut tmp, buf);
|
||||
self.recv_state =
|
||||
TransactionRecvState::BlockedDecodingHeaders { buf: tmp, fin };
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("This is only called when recv_state is ReadingHeaders.");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_sending_closed(&self) -> bool {
|
||||
match self.send_state {
|
||||
TransactionSendState::SendingHeaders { fin, .. } => fin,
|
||||
@ -420,21 +215,7 @@ impl TransactionClient {
|
||||
}
|
||||
|
||||
pub fn read_response_headers(&mut self) -> Res<(Vec<Header>, bool)> {
|
||||
if let ResponseHeadersState::Ready(ref mut headers) = self.response_headers_state {
|
||||
let mut tmp = Vec::new();
|
||||
if let Some(ref mut hdrs) = headers {
|
||||
mem::swap(&mut tmp, hdrs);
|
||||
}
|
||||
self.response_headers_state = ResponseHeadersState::Read;
|
||||
let mut fin = false;
|
||||
if self.recv_state == TransactionRecvState::ClosePending {
|
||||
fin = true;
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
}
|
||||
Ok((tmp, fin))
|
||||
} else {
|
||||
Err(Error::Unavailable)
|
||||
}
|
||||
self.response_stream.read_response_headers()
|
||||
}
|
||||
|
||||
pub fn read_response_data(
|
||||
@ -442,36 +223,7 @@ impl TransactionClient {
|
||||
conn: &mut Connection,
|
||||
buf: &mut [u8],
|
||||
) -> Res<(usize, bool)> {
|
||||
match self.recv_state {
|
||||
TransactionRecvState::ReadingData {
|
||||
ref mut remaining_data_len,
|
||||
} => {
|
||||
let to_read = if *remaining_data_len > buf.len() {
|
||||
buf.len()
|
||||
} else {
|
||||
*remaining_data_len
|
||||
};
|
||||
let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[..to_read])?;
|
||||
debug_assert!(amount <= to_read);
|
||||
*remaining_data_len -= amount;
|
||||
|
||||
if fin {
|
||||
if *remaining_data_len > 0 {
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
} else if *remaining_data_len == 0 {
|
||||
self.recv_state = TransactionRecvState::WaitingForData;
|
||||
}
|
||||
|
||||
Ok((amount, fin))
|
||||
}
|
||||
TransactionRecvState::ClosePending => {
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
Ok((0, true))
|
||||
}
|
||||
_ => Ok((0, false)),
|
||||
}
|
||||
self.response_stream.read_response_data(conn, buf)
|
||||
}
|
||||
|
||||
pub fn is_state_sending_data(&self) -> bool {
|
||||
@ -513,76 +265,7 @@ impl Http3Transaction for TransactionClient {
|
||||
}
|
||||
|
||||
fn receive(&mut self, conn: &mut Connection, decoder: &mut QPackDecoder) -> Res<()> {
|
||||
let label = if ::log::log_enabled!(::log::Level::Debug) {
|
||||
format!("{}", self)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
loop {
|
||||
qdebug!(
|
||||
[label],
|
||||
"send_state={:?} recv_state={:?}.",
|
||||
self.send_state,
|
||||
self.recv_state
|
||||
);
|
||||
match self.recv_state {
|
||||
TransactionRecvState::WaitingForResponseHeaders => {
|
||||
match self.recv_frame_header(conn)? {
|
||||
None => break Ok(()),
|
||||
Some((f, fin)) => {
|
||||
self.handle_frame_in_state_waiting_for_headers(f, fin)?;
|
||||
if fin {
|
||||
self.set_state_to_close_pending();
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
TransactionRecvState::ReadingHeaders { .. } => {
|
||||
if self.read_headers_frame_body(conn, decoder)? {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
TransactionRecvState::BlockedDecodingHeaders { ref buf, fin } => {
|
||||
match decoder.decode_header_block(buf, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.add_headers(Some(headers))?;
|
||||
if fin {
|
||||
self.set_state_to_close_pending();
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
qinfo!([self], "decoding header is blocked.");
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
TransactionRecvState::WaitingForData => {
|
||||
match self.recv_frame_header(conn)? {
|
||||
None => break Ok(()),
|
||||
Some((f, fin)) => {
|
||||
self.handle_frame_in_state_waiting_for_data(f, fin)?;
|
||||
if fin {
|
||||
self.set_state_to_close_pending();
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
TransactionRecvState::ReadingData { .. } => {
|
||||
self.conn_events.data_readable(self.stream_id);
|
||||
break Ok(());
|
||||
}
|
||||
// TransactionRecvState::ReadingTrailers => break Ok(()),
|
||||
TransactionRecvState::ClosePending => {
|
||||
panic!("Stream readable after being closed!");
|
||||
}
|
||||
TransactionRecvState::Closed => {
|
||||
panic!("Stream readable after being closed!");
|
||||
}
|
||||
};
|
||||
}
|
||||
self.response_stream.receive(conn, decoder)
|
||||
}
|
||||
|
||||
fn has_data_to_send(&self) -> bool {
|
||||
@ -594,7 +277,7 @@ impl Http3Transaction for TransactionClient {
|
||||
}
|
||||
|
||||
fn reset_receiving_side(&mut self) {
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
self.response_stream.close();
|
||||
}
|
||||
|
||||
fn stop_sending(&mut self) {
|
||||
@ -602,8 +285,7 @@ impl Http3Transaction for TransactionClient {
|
||||
}
|
||||
|
||||
fn done(&self) -> bool {
|
||||
self.send_state == TransactionSendState::Closed
|
||||
&& self.recv_state == TransactionRecvState::Closed
|
||||
self.send_state == TransactionSendState::Closed && self.response_stream.is_closed()
|
||||
}
|
||||
|
||||
fn close_send(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
|
@ -18,8 +18,7 @@ use std::mem;
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum TransactionRecvState {
|
||||
WaitingForHeaders,
|
||||
ReadingHeaders { buf: Vec<u8>, offset: usize },
|
||||
BlockedDecodingHeaders { buf: Vec<u8>, fin: bool },
|
||||
DecodingHeaders { header_block: Vec<u8>, fin: bool },
|
||||
WaitingForData,
|
||||
ReadingData { remaining_data_len: usize },
|
||||
Closed,
|
||||
@ -55,13 +54,12 @@ impl TransactionServer {
|
||||
|
||||
pub fn set_response(&mut self, headers: &[Header], data: Vec<u8>, encoder: &mut QPackEncoder) {
|
||||
qdebug!([self], "Encoding headers");
|
||||
let encoded_headers = encoder.encode_header_block(&headers, self.stream_id);
|
||||
let header_block = encoder.encode_header_block(&headers, self.stream_id);
|
||||
let hframe = HFrame::Headers {
|
||||
len: encoded_headers.len() as u64,
|
||||
header_block: header_block.to_vec(),
|
||||
};
|
||||
let mut d = Encoder::default();
|
||||
hframe.encode(&mut d);
|
||||
d.encode(&encoded_headers);
|
||||
if !data.is_empty() {
|
||||
qdebug!([self], "Encoding data");
|
||||
let d_frame = HFrame::Data {
|
||||
@ -74,8 +72,8 @@ impl TransactionServer {
|
||||
self.send_state = TransactionSendState::SendingResponse { buf: d.into() };
|
||||
}
|
||||
|
||||
fn recv_frame_header(&mut self, conn: &mut Connection) -> Res<(Option<HFrame>, bool)> {
|
||||
qtrace!([self], "receiving frame header");
|
||||
fn recv_frame(&mut self, conn: &mut Connection) -> Res<(Option<HFrame>, bool)> {
|
||||
qtrace!([self], "receiving a frame");
|
||||
let fin = self.frame_reader.receive(conn, self.stream_id)?;
|
||||
if !self.frame_reader.done() {
|
||||
Ok((None, fin))
|
||||
@ -85,92 +83,6 @@ impl TransactionServer {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_headers_frame_body(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
decoder: &mut QPackDecoder,
|
||||
) -> Res<bool> {
|
||||
let label = if ::log::log_enabled!(::log::Level::Debug) {
|
||||
format!("{}", self)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
if let TransactionRecvState::ReadingHeaders {
|
||||
ref mut buf,
|
||||
ref mut offset,
|
||||
} = self.recv_state
|
||||
{
|
||||
let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[*offset..])?;
|
||||
qdebug!([label], "read_headers: read {} bytes fin={}.", amount, fin);
|
||||
*offset += amount as usize;
|
||||
if *offset < buf.len() {
|
||||
if fin {
|
||||
// Malformed frame
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// we have read the headers, try decoding them.
|
||||
qinfo!(
|
||||
[label],
|
||||
"read_headers: read all headers, try decoding them."
|
||||
);
|
||||
match decoder.decode_header_block(buf, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.conn_events.headers(self.stream_id, headers, fin);
|
||||
if fin {
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
} else {
|
||||
self.recv_state = TransactionRecvState::WaitingForData;
|
||||
}
|
||||
Ok(fin)
|
||||
}
|
||||
None => {
|
||||
let mut tmp: Vec<u8> = Vec::new();
|
||||
mem::swap(&mut tmp, buf);
|
||||
self.recv_state =
|
||||
TransactionRecvState::BlockedDecodingHeaders { buf: tmp, fin };
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("This is only called when recv_state is ReadingHeaders.");
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_headers(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qdebug!([self], "A new frame has been received: {:?}", frame);
|
||||
match frame {
|
||||
HFrame::Headers { len } => self.handle_headers_frame(len, fin),
|
||||
_ => Err(Error::HttpFrameUnexpected),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_data(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qdebug!([self], "A new frame has been received: {:?}", frame);
|
||||
match frame {
|
||||
HFrame::Data { len } => self.handle_data_frame(len, fin),
|
||||
_ => Err(Error::HttpFrameUnexpected),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_headers_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
qinfo!([self], "A new header frame len={} fin={}", len, fin);
|
||||
if len == 0 {
|
||||
self.conn_events.headers(self.stream_id, Vec::new(), fin);
|
||||
} else {
|
||||
if fin {
|
||||
return Err(Error::HttpFrameError);
|
||||
}
|
||||
self.recv_state = TransactionRecvState::ReadingHeaders {
|
||||
buf: vec![0; len as usize],
|
||||
offset: 0,
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_data_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
qinfo!([self], "A new data frame len={} fin={}", len, fin);
|
||||
if len > 0 {
|
||||
@ -233,58 +145,76 @@ impl Http3Transaction for TransactionServer {
|
||||
);
|
||||
match self.recv_state {
|
||||
TransactionRecvState::WaitingForHeaders => {
|
||||
let (f, fin) = self.recv_frame_header(conn)?;
|
||||
match f {
|
||||
None => {
|
||||
if fin {
|
||||
self.conn_events.headers(self.stream_id, Vec::new(), true);
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
}
|
||||
match self.recv_frame(conn)? {
|
||||
(None, true) => {
|
||||
// Stream has been closed without any data, just ignore it.
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
return Ok(());
|
||||
}
|
||||
Some(new_f) => {
|
||||
self.handle_frame_in_state_waiting_for_headers(new_f, fin)?;
|
||||
if fin {
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TransactionRecvState::ReadingHeaders { .. } => {
|
||||
if self.read_headers_frame_body(conn, decoder)? {
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
TransactionRecvState::BlockedDecodingHeaders { ref mut buf, fin } => {
|
||||
match decoder.decode_header_block(buf, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.conn_events.headers(self.stream_id, headers, fin);
|
||||
if fin {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
qinfo!([self], "decoding header is blocked.");
|
||||
(None, false) => {
|
||||
// We do not have a complete frame.
|
||||
return Ok(());
|
||||
}
|
||||
(Some(HFrame::Headers { header_block }), fin) => {
|
||||
if !header_block.is_empty() {
|
||||
// Next step decoding headers.
|
||||
self.recv_state =
|
||||
TransactionRecvState::DecodingHeaders { header_block, fin };
|
||||
} else {
|
||||
self.conn_events.headers(self.stream_id, Vec::new(), fin);
|
||||
if fin {
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
return Ok(());
|
||||
} else {
|
||||
self.recv_state = TransactionRecvState::WaitingForData;
|
||||
}
|
||||
}
|
||||
}
|
||||
// server can only receive a Header frame at this point.
|
||||
_ => {
|
||||
return Err(Error::HttpFrameUnexpected);
|
||||
}
|
||||
}
|
||||
}
|
||||
TransactionRecvState::DecodingHeaders {
|
||||
ref mut header_block,
|
||||
fin,
|
||||
} => match decoder.decode_header_block(header_block, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.conn_events.headers(self.stream_id, headers, fin);
|
||||
if fin {
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
return Ok(());
|
||||
} else {
|
||||
self.recv_state = TransactionRecvState::WaitingForData;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
qinfo!([self], "decoding header is blocked.");
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
TransactionRecvState::WaitingForData => {
|
||||
let (f, fin) = self.recv_frame_header(conn)?;
|
||||
match f {
|
||||
None => {
|
||||
if fin {
|
||||
self.conn_events.data(self.stream_id, Vec::new(), true);
|
||||
}
|
||||
match self.recv_frame(conn)? {
|
||||
(None, true) => {
|
||||
// Inform the app tthat tthe stream is done.
|
||||
self.conn_events.data(self.stream_id, Vec::new(), true);
|
||||
self.recv_state = TransactionRecvState::Closed;
|
||||
return Ok(());
|
||||
}
|
||||
Some(new_f) => {
|
||||
self.handle_frame_in_state_waiting_for_data(new_f, fin)?;
|
||||
(None, false) => {
|
||||
// Still reading a frame.
|
||||
return Ok(());
|
||||
}
|
||||
(Some(HFrame::Data { len }), fin) => {
|
||||
self.handle_data_frame(len, fin)?;
|
||||
if fin {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::HttpFrameUnexpected);
|
||||
}
|
||||
};
|
||||
}
|
||||
TransactionRecvState::ReadingData {
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"302de4e70e8ee1213674d0bb3334ad505bf2e3b4205c43d95912e236e4922b2f","src/decoder.rs":"aac6d5b3dfb19779351c2568a4c54c551e2de83d0e458246c818a6af15514477","src/encoder.rs":"992bb211273d48b9d85ab4bc6bad5c0dbc5c12e7f9e7c1bb35f1b0db5eb7cffe","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"fa5b76f6b7db74904fe0317bbc1214292494365328c2efa06b4146cbd2ee6c1b","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"1043a6e0761d9ff05a35dfab3b5a0e871d1b1666e83bc4fbd9e97383ca44e59e"},"package":null}
|
||||
{"files":{"Cargo.toml":"7f54a2ebb0f59739f00a094404ae39d3ba61efbdd6e0ef416187f857e0726362","src/decoder.rs":"aac6d5b3dfb19779351c2568a4c54c551e2de83d0e458246c818a6af15514477","src/encoder.rs":"992bb211273d48b9d85ab4bc6bad5c0dbc5c12e7f9e7c1bb35f1b0db5eb7cffe","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"fa5b76f6b7db74904fe0317bbc1214292494365328c2efa06b4146cbd2ee6c1b","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"1043a6e0761d9ff05a35dfab3b5a0e871d1b1666e83bc4fbd9e97383ca44e59e"},"package":null}
|
2
third_party/rust/neqo-qpack/Cargo.toml
vendored
2
third_party/rust/neqo-qpack/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-qpack"
|
||||
version = "0.1.14"
|
||||
version = "0.2.0"
|
||||
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"b8d9d003559098683d11011382a1232f0982679348f133e57b9c9995e945505b","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/cc.rs":"9fa6bebf5fc6d9dab2b53cff38f1ea88e6cc20b1c7dc9c55a30bc75599306c34","src/cid.rs":"4161a5add9285a9f670c4d0b88ac84833b710cd99cbd5ec080f4d2f097200abf","src/connection.rs":"5300a6a55bf32fd3abdd0857455ea10a28b93e1f6ae69ef81a283915b90be49d","src/crypto.rs":"2cf82dcdac073a5bd318c6ad2843fd48faf3ce752ae5e613cc1dbac60cd0367d","src/dump.rs":"d69ccb0e3b240823b886a791186afbac9f2e26d1f1f67a55dbf86f8cd3e6203e","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"0b1c6e7587e411635723207ecface6c62d1243599dd017745c61eb94805b9886","src/frame.rs":"2859a30e4889fd6b4124b9f88affcec5956f8f3914ccc7684525bfad085ef076","src/lib.rs":"dbaaf47b1025a5d976ceff86989e6d8729e993e525a3ef1d59046d45c0a09bf1","src/packet.rs":"a3b0b0414e8ddaddfe098fa343a89449b42fbb1ae44468d04994becebd7ab5cc","src/recovery.rs":"887a963dbc6e987caba0d74c0ce6b71212b96f87078cb1086ded560c4b930834","src/recv_stream.rs":"0a0c44a3414e6088a704c1a245fd98dd8a8ed502d80bfab90d2defe039bd37cb","src/send_stream.rs":"0c3e401bb6a7ea7babe47234d7a05c993f4a3c67f07f4130d81a8476085e746f","src/server.rs":"ca82b8bbfae29cf2fb6aadf4298d8482a734edbd460e569766d16b596aac0554","src/stats.rs":"a276bd9902939091578d3bcc95aa7dd0b32f5d29e528c12e7b93a0ab88474478","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"4b328b0b146f06d805fbc77748f9cb578f9ee4a0c63565158bf36d7bd3151020","src/tracking.rs":"0df46cd244afc32ca3aef1dcd8eb9abcce364a330bd8053a2484740bb5b2b3fd","tests/conn_vectors.rs":"d42db769518162bb3e39667a999ab467541c72d7a7d42e92adbd39c16eca0811","tests/connection.rs":"a93985c199a9ef987106f4a20b35ebf803cdbbb855c07b1362b403eed7101ef8","tests/server.rs":"d516bf134a63377c98ff4ac2cca2d4cc6562f48ea262b10a23866d38c4c82af3"},"package":null}
|
||||
{"files":{"Cargo.toml":"1cd6e9064d96f19d54607b31f5b64c9d67f088fcbc4cb773febc9fdbd79c2d87","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/cc.rs":"b4639a63f4c4112a42223f164e71bd230419bd2a0777cbdfc1852d2a32ba3f3d","src/cid.rs":"4161a5add9285a9f670c4d0b88ac84833b710cd99cbd5ec080f4d2f097200abf","src/connection.rs":"8ef7ab9e35463ac10b565a710115b3739614b87166a42fc951d8d2cf1212791f","src/crypto.rs":"2cf82dcdac073a5bd318c6ad2843fd48faf3ce752ae5e613cc1dbac60cd0367d","src/dump.rs":"d69ccb0e3b240823b886a791186afbac9f2e26d1f1f67a55dbf86f8cd3e6203e","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"0b1c6e7587e411635723207ecface6c62d1243599dd017745c61eb94805b9886","src/frame.rs":"2859a30e4889fd6b4124b9f88affcec5956f8f3914ccc7684525bfad085ef076","src/lib.rs":"59d5c510d688763a88d7a4d7c0df9e0fcc86df3f474168312677dca6c7537a1a","src/packet.rs":"17178610c50f855de175dea23047a4bfab7b998b859905247dc5cf70f5d19662","src/path.rs":"829f5fd788f21525bbc6698abf04651594cfa79380f0ab1c6152a5d391669e58","src/recovery.rs":"887a963dbc6e987caba0d74c0ce6b71212b96f87078cb1086ded560c4b930834","src/recv_stream.rs":"0a0c44a3414e6088a704c1a245fd98dd8a8ed502d80bfab90d2defe039bd37cb","src/send_stream.rs":"0c3e401bb6a7ea7babe47234d7a05c993f4a3c67f07f4130d81a8476085e746f","src/server.rs":"ca82b8bbfae29cf2fb6aadf4298d8482a734edbd460e569766d16b596aac0554","src/stats.rs":"a276bd9902939091578d3bcc95aa7dd0b32f5d29e528c12e7b93a0ab88474478","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"ef0e8d42ebd51f9494198525060c215ab8fe723c569dc25186de0af558034b66","src/tracking.rs":"0df46cd244afc32ca3aef1dcd8eb9abcce364a330bd8053a2484740bb5b2b3fd","tests/conn_vectors.rs":"b541537a360886f4b9d7e85105bd38faeba83f1ef85b1b1f9ae79891481348a5","tests/connection.rs":"a93985c199a9ef987106f4a20b35ebf803cdbbb855c07b1362b403eed7101ef8","tests/server.rs":"d516bf134a63377c98ff4ac2cca2d4cc6562f48ea262b10a23866d38c4c82af3"},"package":null}
|
2
third_party/rust/neqo-transport/Cargo.toml
vendored
2
third_party/rust/neqo-transport/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-transport"
|
||||
version = "0.1.14"
|
||||
version = "0.2.0"
|
||||
authors = ["EKR <ekr@rtfm.com>", "Andy Grover <agrover@mozilla.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
5
third_party/rust/neqo-transport/src/cc.rs
vendored
5
third_party/rust/neqo-transport/src/cc.rs
vendored
@ -10,10 +10,11 @@ use std::cmp::max;
|
||||
use std::fmt::{self, Display};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::path::PATH_MTU_V6;
|
||||
use crate::tracking::SentPacket;
|
||||
use neqo_common::{const_max, const_min, qdebug, qinfo, qtrace};
|
||||
|
||||
pub const MAX_DATAGRAM_SIZE: usize = 1232; // For ipv6, smaller than ipv4 (1252)
|
||||
pub const MAX_DATAGRAM_SIZE: usize = PATH_MTU_V6;
|
||||
pub const INITIAL_CWND_PKTS: usize = 10;
|
||||
const INITIAL_WINDOW: usize = const_min(
|
||||
INITIAL_CWND_PKTS * MAX_DATAGRAM_SIZE,
|
||||
@ -140,7 +141,7 @@ impl CongestionControl {
|
||||
}
|
||||
|
||||
pub fn discard(&mut self, pkt: &SentPacket) {
|
||||
if pkt.in_flight {
|
||||
if pkt.in_flight && pkt.time_declared_lost.is_none() {
|
||||
assert!(self.bytes_in_flight >= pkt.size);
|
||||
self.bytes_in_flight -= pkt.size;
|
||||
qtrace!([self], "Ignore pkt with size {}", pkt.size);
|
||||
|
327
third_party/rust/neqo-transport/src/connection.rs
vendored
327
third_party/rust/neqo-transport/src/connection.rs
vendored
@ -31,13 +31,14 @@ use crate::events::{ConnectionEvent, ConnectionEvents};
|
||||
use crate::flow_mgr::FlowMgr;
|
||||
use crate::frame::{AckRange, Frame, FrameType, StreamType, TxMode};
|
||||
use crate::packet::{DecryptedPacket, PacketBuilder, PacketNumber, PacketType, PublicPacket};
|
||||
use crate::path::Path;
|
||||
use crate::recovery::{LossRecovery, RecoveryToken};
|
||||
use crate::recv_stream::{RecvStream, RecvStreams, RX_STREAM_DATA_WINDOW};
|
||||
use crate::send_stream::{SendStream, SendStreams};
|
||||
use crate::stats::Stats;
|
||||
use crate::stream_id::{StreamId, StreamIndex, StreamIndexes};
|
||||
use crate::tparams::{
|
||||
tp_constants, TransportParameter, TransportParameters, TransportParametersHandler,
|
||||
self, TransportParameter, TransportParameterId, TransportParameters, TransportParametersHandler,
|
||||
};
|
||||
use crate::tracking::{AckTracker, PNSpace, SentPacket};
|
||||
use crate::{AppError, ConnectionError, Error, Res, LOCAL_IDLE_TIMEOUT};
|
||||
@ -130,38 +131,6 @@ enum ZeroRttState {
|
||||
Rejected,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
struct Path {
|
||||
local: SocketAddr,
|
||||
remote: SocketAddr,
|
||||
local_cids: Vec<ConnectionId>,
|
||||
remote_cid: ConnectionId,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
// Used to create a path when receiving a packet.
|
||||
pub fn new(d: &Datagram, remote_cid: ConnectionId) -> Self {
|
||||
Self {
|
||||
local: d.destination(),
|
||||
remote: d.source(),
|
||||
local_cids: Vec::new(),
|
||||
remote_cid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn received_on(&self, d: &Datagram) -> bool {
|
||||
self.local == d.destination() && self.remote == d.source()
|
||||
}
|
||||
|
||||
fn mtu(&self) -> usize {
|
||||
if self.local.is_ipv4() {
|
||||
1252
|
||||
} else {
|
||||
1232 // IPv6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// Type returned from process() and `process_output()`. Users are required to
|
||||
/// call these repeatedly until `Callback` or `None` is returned.
|
||||
@ -402,19 +371,14 @@ impl Connection {
|
||||
remote_addr: SocketAddr,
|
||||
) -> Res<Self> {
|
||||
let dcid = ConnectionId::generate_initial();
|
||||
let local_cids = vec![cid_manager.borrow_mut().generate_cid()];
|
||||
let scid = cid_manager.borrow_mut().generate_cid();
|
||||
let mut c = Self::new(
|
||||
Role::Client,
|
||||
Client::new(server_name)?.into(),
|
||||
cid_manager,
|
||||
None,
|
||||
protocols,
|
||||
Some(Path {
|
||||
local: local_addr,
|
||||
remote: remote_addr,
|
||||
local_cids,
|
||||
remote_cid: dcid.clone(),
|
||||
}),
|
||||
Some(Path::new(local_addr, remote_addr, scid, dcid.clone())),
|
||||
);
|
||||
c.crypto.states.init(Role::Client, &dcid);
|
||||
c.retry_info = Some(RetryInfo::new(dcid));
|
||||
@ -440,31 +404,22 @@ impl Connection {
|
||||
|
||||
fn set_tp_defaults(tps: &mut TransportParameters) {
|
||||
tps.set_integer(
|
||||
tp_constants::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
|
||||
tparams::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
|
||||
RX_STREAM_DATA_WINDOW,
|
||||
);
|
||||
tps.set_integer(
|
||||
tp_constants::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
|
||||
tparams::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
|
||||
RX_STREAM_DATA_WINDOW,
|
||||
);
|
||||
tps.set_integer(tparams::INITIAL_MAX_STREAM_DATA_UNI, RX_STREAM_DATA_WINDOW);
|
||||
tps.set_integer(tparams::INITIAL_MAX_STREAMS_BIDI, LOCAL_STREAM_LIMIT_BIDI);
|
||||
tps.set_integer(tparams::INITIAL_MAX_STREAMS_UNI, LOCAL_STREAM_LIMIT_UNI);
|
||||
tps.set_integer(tparams::INITIAL_MAX_DATA, LOCAL_MAX_DATA);
|
||||
tps.set_integer(
|
||||
tp_constants::INITIAL_MAX_STREAM_DATA_UNI,
|
||||
RX_STREAM_DATA_WINDOW,
|
||||
);
|
||||
tps.set_integer(
|
||||
tp_constants::INITIAL_MAX_STREAMS_BIDI,
|
||||
LOCAL_STREAM_LIMIT_BIDI,
|
||||
);
|
||||
tps.set_integer(
|
||||
tp_constants::INITIAL_MAX_STREAMS_UNI,
|
||||
LOCAL_STREAM_LIMIT_UNI,
|
||||
);
|
||||
tps.set_integer(tp_constants::INITIAL_MAX_DATA, LOCAL_MAX_DATA);
|
||||
tps.set_integer(
|
||||
tp_constants::IDLE_TIMEOUT,
|
||||
tparams::IDLE_TIMEOUT,
|
||||
u64::try_from(LOCAL_IDLE_TIMEOUT.as_millis()).unwrap(),
|
||||
);
|
||||
tps.set_empty(tp_constants::DISABLE_MIGRATION);
|
||||
tps.set_empty(tparams::DISABLE_MIGRATION);
|
||||
}
|
||||
|
||||
fn new(
|
||||
@ -509,12 +464,12 @@ impl Connection {
|
||||
}
|
||||
|
||||
/// Set a local transport parameter, possibly overriding a default value.
|
||||
pub fn set_local_tparam(&self, key: u16, value: TransportParameter) -> Res<()> {
|
||||
pub fn set_local_tparam(&self, tp: TransportParameterId, value: TransportParameter) -> Res<()> {
|
||||
if matches!(
|
||||
(self.role(), self.state()),
|
||||
(Role::Client, State::Init) | (Role::Server, State::WaitInitial)
|
||||
) {
|
||||
self.tps.borrow_mut().local.set(key, value);
|
||||
self.tps.borrow_mut().local.set(tp, value);
|
||||
Ok(())
|
||||
} else {
|
||||
qerror!("Current state: {:?}", self.state());
|
||||
@ -529,7 +484,7 @@ impl Connection {
|
||||
self.tps
|
||||
.borrow_mut()
|
||||
.local
|
||||
.set_bytes(tp_constants::ORIGINAL_CONNECTION_ID, odcid.to_vec());
|
||||
.set_bytes(tparams::ORIGINAL_CONNECTION_ID, odcid.to_vec());
|
||||
}
|
||||
|
||||
/// Set ALPN preferences. Strings that appear earlier in the list are given
|
||||
@ -798,9 +753,7 @@ impl Connection {
|
||||
}
|
||||
|
||||
fn is_valid_cid(&self, cid: &ConnectionIdRef) -> bool {
|
||||
let check = |c| c == cid;
|
||||
self.valid_cids.iter().any(check)
|
||||
|| self.path.iter().any(|p| p.local_cids.iter().any(check))
|
||||
self.valid_cids.iter().any(|c| c == cid) || self.path.iter().any(|p| p.valid_local_cid(cid))
|
||||
}
|
||||
|
||||
fn handle_retry(&mut self, packet: PublicPacket) -> Res<()> {
|
||||
@ -823,7 +776,7 @@ impl Connection {
|
||||
}
|
||||
if let Some(p) = &mut self.path {
|
||||
// At this point, we shouldn't have a remote connection ID for the path.
|
||||
p.remote_cid = ConnectionId::from(packet.scid());
|
||||
p.set_remote_cid(packet.scid());
|
||||
} else {
|
||||
qinfo!([self], "No path, but we received a Retry");
|
||||
return Err(Error::InternalError);
|
||||
@ -1016,9 +969,8 @@ impl Connection {
|
||||
self.valid_cids.push(ConnectionId::from(packet.dcid()));
|
||||
// Install a path.
|
||||
assert!(self.path.is_none());
|
||||
let mut p = Path::new(&d, ConnectionId::from(packet.scid()));
|
||||
p.local_cids
|
||||
.push(self.cid_manager.borrow_mut().generate_cid());
|
||||
let mut p = Path::from_datagram(&d, ConnectionId::from(packet.scid()));
|
||||
p.add_local_cid(self.cid_manager.borrow_mut().generate_cid());
|
||||
self.path = Some(p);
|
||||
|
||||
self.zero_rtt_state = match self.crypto.enable_0rtt(self.role) {
|
||||
@ -1035,7 +987,7 @@ impl Connection {
|
||||
.iter_mut()
|
||||
.find(|p| p.received_on(&d))
|
||||
.expect("should have a path for sending Initial");
|
||||
p.remote_cid = ConnectionId::from(packet.scid());
|
||||
p.set_remote_cid(packet.scid());
|
||||
}
|
||||
self.set_state(State::Handshaking);
|
||||
Ok(())
|
||||
@ -1099,22 +1051,17 @@ impl Connection {
|
||||
}
|
||||
};
|
||||
let mut builder = if pt == PacketType::Short {
|
||||
qdebug!("Building Short dcid {}", &path.remote_cid,);
|
||||
PacketBuilder::short(encoder, tx.key_phase(), &path.remote_cid)
|
||||
qdebug!("Building Short dcid {}", path.remote_cid());
|
||||
PacketBuilder::short(encoder, tx.key_phase(), path.remote_cid())
|
||||
} else {
|
||||
qdebug!(
|
||||
"Building {:?} dcid {} scid {}",
|
||||
pt,
|
||||
&path.remote_cid,
|
||||
path.local_cids.first().unwrap()
|
||||
path.remote_cid(),
|
||||
path.local_cid(),
|
||||
);
|
||||
|
||||
PacketBuilder::long(
|
||||
encoder,
|
||||
pt,
|
||||
&path.remote_cid,
|
||||
path.local_cids.first().unwrap(),
|
||||
)
|
||||
PacketBuilder::long(encoder, pt, path.remote_cid(), path.local_cid())
|
||||
};
|
||||
if pt == PacketType::Initial {
|
||||
builder.initial_token(if let Some(info) = retry_info {
|
||||
@ -1174,7 +1121,7 @@ impl Connection {
|
||||
if close_sent {
|
||||
self.state_signaling.close_sent();
|
||||
}
|
||||
Ok(Some(Datagram::new(path.local, path.remote, encoder)))
|
||||
Ok(Some(path.datagram(encoder)))
|
||||
}
|
||||
|
||||
/// Add frames to the provided builder and
|
||||
@ -1239,6 +1186,7 @@ impl Connection {
|
||||
/// Build a datagram, possibly from multiple packets (for different PN
|
||||
/// spaces) and each containing 1+ frames.
|
||||
fn output_path(&mut self, path: &mut Path, now: Instant) -> Res<Option<Datagram>> {
|
||||
let mut initial_sent = None;
|
||||
let mut needs_padding = false;
|
||||
|
||||
// Check whether we are sending packets in PTO mode.
|
||||
@ -1296,17 +1244,10 @@ impl Connection {
|
||||
dump_packet(self, "TX ->", pt, pn, &builder[payload_start..]);
|
||||
|
||||
qdebug!("Need to send a packet: {:?}", pt);
|
||||
match pt {
|
||||
// Packets containing Initial packets need padding.
|
||||
PacketType::Initial => needs_padding = true,
|
||||
PacketType::ZeroRtt => (),
|
||||
// ...unless they include higher epochs.
|
||||
_ => needs_padding = false,
|
||||
}
|
||||
|
||||
self.stats.packets_tx += 1;
|
||||
encoder = builder.build(self.crypto.states.tx(*space).unwrap())?;
|
||||
assert!(encoder.len() <= path.mtu());
|
||||
debug_assert!(encoder.len() <= path.mtu());
|
||||
|
||||
if tx_mode != TxMode::Pto && ack_eliciting {
|
||||
self.idle_timeout.on_packet_sent(now);
|
||||
@ -1326,34 +1267,45 @@ impl Connection {
|
||||
encoder.len() - header_start,
|
||||
in_flight,
|
||||
);
|
||||
self.loss_recovery.on_packet_sent(*space, pn, sent);
|
||||
|
||||
if *space == PNSpace::Handshake && self.role == Role::Client {
|
||||
// Client can send Handshake packets -> discard Initial keys and states
|
||||
self.discard_keys(PNSpace::Initial);
|
||||
if pt == PacketType::Initial && self.role == Role::Client {
|
||||
// Packets containing Initial packets might need padding, and we want to
|
||||
// track that padding along with the Initial packet. So defer tracking.
|
||||
initial_sent = Some((pn, sent));
|
||||
needs_padding = true;
|
||||
} else {
|
||||
if pt != PacketType::ZeroRtt {
|
||||
needs_padding = false;
|
||||
}
|
||||
self.loss_recovery.on_packet_sent(*space, pn, sent);
|
||||
}
|
||||
|
||||
if *space == PNSpace::Handshake
|
||||
&& self.role == Role::Server
|
||||
&& self.state == State::Confirmed
|
||||
{
|
||||
// We could discard handshake keys in set_state, but we are waiting to send an ack.
|
||||
self.discard_keys(PNSpace::Handshake);
|
||||
if *space == PNSpace::Handshake {
|
||||
if self.role == Role::Client {
|
||||
// Client can send Handshake packets -> discard Initial keys and states
|
||||
self.discard_keys(PNSpace::Initial);
|
||||
} else if self.state == State::Confirmed {
|
||||
// We could discard handshake keys in set_state, but wait until after sending an ACK.
|
||||
self.discard_keys(PNSpace::Handshake);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if encoder.len() == 0 {
|
||||
assert!(tx_mode != TxMode::Pto);
|
||||
debug_assert!(tx_mode != TxMode::Pto);
|
||||
Ok(None)
|
||||
} else {
|
||||
debug_assert!(encoder.len() <= path.mtu());
|
||||
// Pad Initial packets sent by the client to mtu bytes.
|
||||
let mut packets: Vec<u8> = encoder.into();
|
||||
if self.role == Role::Client && needs_padding {
|
||||
qdebug!([self], "pad Initial to max_datagram_size");
|
||||
packets.resize(path.mtu(), 0);
|
||||
if let Some((initial_pn, mut initial)) = initial_sent.take() {
|
||||
if needs_padding {
|
||||
qdebug!([self], "pad Initial to path MTU {}", path.mtu());
|
||||
initial.size += path.mtu() - packets.len();
|
||||
packets.resize(path.mtu(), 0);
|
||||
}
|
||||
self.loss_recovery
|
||||
.on_packet_sent(PNSpace::Initial, initial_pn, initial);
|
||||
}
|
||||
Ok(Some(Datagram::new(path.local, path.remote, packets)))
|
||||
Ok(Some(path.datagram(packets)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1406,12 +1358,12 @@ impl Connection {
|
||||
let tps = self.tps.borrow();
|
||||
let remote = tps.remote();
|
||||
self.indexes.remote_max_stream_bidi =
|
||||
StreamIndex::new(remote.get_integer(tp_constants::INITIAL_MAX_STREAMS_BIDI));
|
||||
StreamIndex::new(remote.get_integer(tparams::INITIAL_MAX_STREAMS_BIDI));
|
||||
self.indexes.remote_max_stream_uni =
|
||||
StreamIndex::new(remote.get_integer(tp_constants::INITIAL_MAX_STREAMS_UNI));
|
||||
StreamIndex::new(remote.get_integer(tparams::INITIAL_MAX_STREAMS_UNI));
|
||||
self.flow_mgr
|
||||
.borrow_mut()
|
||||
.conn_increase_max_credit(remote.get_integer(tp_constants::INITIAL_MAX_DATA));
|
||||
.conn_increase_max_credit(remote.get_integer(tparams::INITIAL_MAX_DATA));
|
||||
}
|
||||
|
||||
fn validate_odcid(&mut self) -> Res<()> {
|
||||
@ -1421,7 +1373,7 @@ impl Connection {
|
||||
Ok(())
|
||||
} else {
|
||||
let tph = self.tps.borrow();
|
||||
let tp = tph.remote().get_bytes(tp_constants::ORIGINAL_CONNECTION_ID);
|
||||
let tp = tph.remote().get_bytes(tparams::ORIGINAL_CONNECTION_ID);
|
||||
if let Some(odcid_tp) = tp {
|
||||
if odcid_tp[..] == info.odcid[..] {
|
||||
Ok(())
|
||||
@ -1667,7 +1619,7 @@ impl Connection {
|
||||
self.set_state(State::Closed(error_code.into()));
|
||||
}
|
||||
Frame::HandshakeDone => {
|
||||
if self.role == Role::Server {
|
||||
if self.role == Role::Server || !self.state.connected() {
|
||||
return Err(Error::ProtocolViolation);
|
||||
}
|
||||
self.set_state(State::Confirmed);
|
||||
@ -1898,7 +1850,7 @@ impl Connection {
|
||||
self.tps
|
||||
.borrow()
|
||||
.local
|
||||
.get_integer(tp_constants::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE)
|
||||
.get_integer(tparams::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE)
|
||||
} else {
|
||||
if stream_idx > self.indexes.local_max_stream_uni {
|
||||
qwarn!(
|
||||
@ -1912,7 +1864,7 @@ impl Connection {
|
||||
self.tps
|
||||
.borrow()
|
||||
.local
|
||||
.get_integer(tp_constants::INITIAL_MAX_STREAM_DATA_UNI)
|
||||
.get_integer(tparams::INITIAL_MAX_STREAM_DATA_UNI)
|
||||
};
|
||||
|
||||
loop {
|
||||
@ -1940,7 +1892,7 @@ impl Connection {
|
||||
.tps
|
||||
.borrow()
|
||||
.remote()
|
||||
.get_integer(tp_constants::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL);
|
||||
.get_integer(tparams::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL);
|
||||
self.send_streams.insert(
|
||||
next_stream_id,
|
||||
SendStream::new(
|
||||
@ -2007,7 +1959,7 @@ impl Connection {
|
||||
.tps
|
||||
.borrow()
|
||||
.remote()
|
||||
.get_integer(tp_constants::INITIAL_MAX_STREAM_DATA_UNI);
|
||||
.get_integer(tparams::INITIAL_MAX_STREAM_DATA_UNI);
|
||||
|
||||
self.send_streams.insert(
|
||||
new_id,
|
||||
@ -2046,7 +1998,7 @@ impl Connection {
|
||||
.tps
|
||||
.borrow()
|
||||
.remote()
|
||||
.get_integer(tp_constants::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE);
|
||||
.get_integer(tparams::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE);
|
||||
|
||||
self.send_streams.insert(
|
||||
new_id,
|
||||
@ -2065,7 +2017,7 @@ impl Connection {
|
||||
.tps
|
||||
.borrow()
|
||||
.local
|
||||
.get_integer(tp_constants::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL);
|
||||
.get_integer(tparams::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL);
|
||||
|
||||
self.recv_streams.insert(
|
||||
new_id,
|
||||
@ -2158,8 +2110,10 @@ impl ::std::fmt::Display for Connection {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cc::{INITIAL_CWND_PKTS, MAX_DATAGRAM_SIZE, MIN_CONG_WINDOW};
|
||||
use crate::cc::{INITIAL_CWND_PKTS, MIN_CONG_WINDOW};
|
||||
use crate::frame::{CloseError, StreamType};
|
||||
use crate::path::PATH_MTU_V6;
|
||||
|
||||
use neqo_common::matches;
|
||||
use std::mem;
|
||||
use test_fixture::{self, assertions, fixture_init, loopback, now};
|
||||
@ -2172,23 +2126,14 @@ mod tests {
|
||||
// These are a direct copy of those functions.
|
||||
pub fn default_client() -> Connection {
|
||||
fixture_init();
|
||||
let mut c = Connection::new_client(
|
||||
Connection::new_client(
|
||||
test_fixture::DEFAULT_SERVER_NAME,
|
||||
test_fixture::DEFAULT_ALPN,
|
||||
Rc::new(RefCell::new(FixedConnectionIdManager::new(3))),
|
||||
loopback(),
|
||||
loopback(),
|
||||
)
|
||||
.expect("create a default client");
|
||||
|
||||
// limit dcid to a constant value to make testing easier
|
||||
let mut modded_path = c.path.take().unwrap();
|
||||
let mut modded_cid = modded_path.remote_cid.to_vec();
|
||||
modded_cid.truncate(8);
|
||||
modded_path.remote_cid = ConnectionId::from(&modded_cid[..]);
|
||||
c.path = Some(modded_path);
|
||||
c.crypto.states.init(Role::Client, &modded_cid);
|
||||
c
|
||||
.expect("create a default client")
|
||||
}
|
||||
pub fn default_server() -> Connection {
|
||||
fixture_init();
|
||||
@ -2282,7 +2227,7 @@ mod tests {
|
||||
let mut client = default_client();
|
||||
let out = client.process(None, now());
|
||||
assert!(out.as_dgram_ref().is_some());
|
||||
assert_eq!(out.as_dgram_ref().unwrap().len(), 1232);
|
||||
assert_eq!(out.as_dgram_ref().unwrap().len(), PATH_MTU_V6);
|
||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||
|
||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||
@ -2520,7 +2465,7 @@ mod tests {
|
||||
let mut client = default_client();
|
||||
let out = client.process(None, now());
|
||||
assert!(out.as_dgram_ref().is_some());
|
||||
assert_eq!(out.as_dgram_ref().unwrap().len(), 1232);
|
||||
assert_eq!(out.as_dgram_ref().unwrap().len(), PATH_MTU_V6);
|
||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||
|
||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||
@ -2953,7 +2898,7 @@ mod tests {
|
||||
|
||||
server
|
||||
.set_local_tparam(
|
||||
tp_constants::INITIAL_MAX_DATA,
|
||||
tparams::INITIAL_MAX_DATA,
|
||||
TransportParameter::Integer(SMALL_MAX_DATA),
|
||||
)
|
||||
.unwrap();
|
||||
@ -3052,10 +2997,7 @@ mod tests {
|
||||
let client = default_client();
|
||||
|
||||
client
|
||||
.set_local_tparam(
|
||||
tp_constants::INITIAL_MAX_DATA,
|
||||
TransportParameter::Integer(55),
|
||||
)
|
||||
.set_local_tparam(tparams::INITIAL_MAX_DATA, TransportParameter::Integer(55))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@ -3316,7 +3258,7 @@ mod tests {
|
||||
let mut client = default_client();
|
||||
let pkt1 = client.process(None, now).dgram();
|
||||
assert!(pkt1.is_some());
|
||||
assert_eq!(pkt1.clone().unwrap().len(), 1232);
|
||||
assert_eq!(pkt1.clone().unwrap().len(), PATH_MTU_V6);
|
||||
|
||||
let out = client.process(None, now);
|
||||
assert_eq!(out, Output::Callback(Duration::from_millis(120)));
|
||||
@ -3325,7 +3267,7 @@ mod tests {
|
||||
now += Duration::from_millis(120);
|
||||
let pkt2 = client.process(None, now).dgram();
|
||||
assert!(pkt2.is_some());
|
||||
assert_eq!(pkt2.unwrap().len(), 1232);
|
||||
assert_eq!(pkt2.unwrap().len(), PATH_MTU_V6);
|
||||
|
||||
let out = client.process(None, now);
|
||||
// PTO has doubled.
|
||||
@ -3559,7 +3501,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Absent path PTU discovery, max v6 packet size should be 1232.
|
||||
// Absent path PTU discovery, max v6 packet size should be PATH_MTU_V6.
|
||||
fn verify_pkt_honors_mtu() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
@ -3575,7 +3517,7 @@ mod tests {
|
||||
assert_eq!(client.stream_send(2, &[0xbb; 2000]).unwrap(), 2000);
|
||||
let pkt0 = client.process(None, now);
|
||||
assert!(matches!(pkt0, Output::Datagram(_)));
|
||||
assert_eq!(pkt0.as_dgram_ref().unwrap().len(), 1232);
|
||||
assert_eq!(pkt0.as_dgram_ref().unwrap().len(), PATH_MTU_V6);
|
||||
}
|
||||
|
||||
// Handle sending a bunch of bytes from one connection to another, until
|
||||
@ -3593,7 +3535,9 @@ mod tests {
|
||||
loop {
|
||||
let pkt = src.process_output(now);
|
||||
match pkt {
|
||||
Output::Datagram(dgram) => total_dgrams.push(dgram),
|
||||
Output::Datagram(dgram) => {
|
||||
total_dgrams.push(dgram);
|
||||
}
|
||||
Output::Callback(_) => break,
|
||||
_ => panic!(),
|
||||
}
|
||||
@ -3636,14 +3580,30 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
/// This magic number is the size of the Handshake packets sent
|
||||
/// by the client and acknowledged by the server.
|
||||
/// This magic number is the size of the client's CWND after the handshake completes.
|
||||
/// This includes the initial congestion window, as increased as a result
|
||||
/// receiving acknowledgments for Initial and Handshake packets, which is
|
||||
/// at least one full packet (the first Initial) and a little extra.
|
||||
///
|
||||
/// As we change how we build packets, or even as NSS changes,
|
||||
/// this number might be different. The tests that depend on this
|
||||
/// value could fail as a result of variations, so it's OK to just
|
||||
/// change this value, but it is good to first understand where the
|
||||
/// change came from.
|
||||
const HANDSHAKE_CWND_INCREASE: usize = 631;
|
||||
const POST_HANDSHAKE_CWND: usize = PATH_MTU_V6 * (INITIAL_CWND_PKTS + 1) + 75;
|
||||
|
||||
/// Determine the number of packets required to fill the CWND.
|
||||
const fn cwnd_packets(data: usize) -> usize {
|
||||
(data + PATH_MTU_V6 - 1) / PATH_MTU_V6
|
||||
}
|
||||
|
||||
/// Assert that the set of packets fill the CWND.
|
||||
fn assert_full_cwnd(packets: &[Datagram], cwnd: usize) {
|
||||
assert_eq!(packets.len(), cwnd_packets(cwnd));
|
||||
let (last, rest) = packets.split_last().unwrap();
|
||||
assert!(rest.iter().all(|d| d.len() == PATH_MTU_V6));
|
||||
assert_eq!(last.len(), cwnd % PATH_MTU_V6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Verify initial CWND is honored.
|
||||
@ -3653,7 +3613,7 @@ mod tests {
|
||||
|
||||
server
|
||||
.set_local_tparam(
|
||||
tp_constants::INITIAL_MAX_DATA,
|
||||
tparams::INITIAL_MAX_DATA,
|
||||
TransportParameter::Integer(65536),
|
||||
)
|
||||
.unwrap();
|
||||
@ -3664,13 +3624,7 @@ mod tests {
|
||||
// Try to send a lot of data
|
||||
assert_eq!(client.stream_create(StreamType::UniDi).unwrap(), 2);
|
||||
let c_tx_dgrams = send_bytes(&mut client, 2, now);
|
||||
|
||||
// Init/Handshake acks have increased cwnd so we actually can
|
||||
// send 11 with the last being shorter
|
||||
assert_eq!(c_tx_dgrams.len(), INITIAL_CWND_PKTS + 1);
|
||||
let (last, rest) = c_tx_dgrams.split_last().unwrap();
|
||||
assert!(rest.iter().all(|d| d.len() == MAX_DATAGRAM_SIZE));
|
||||
assert_eq!(last.len(), HANDSHAKE_CWND_INCREASE);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
assert_eq!(client.loss_recovery.cwnd_avail(), 0);
|
||||
}
|
||||
|
||||
@ -3688,14 +3642,8 @@ mod tests {
|
||||
|
||||
// Buffer up lot of data and generate packets
|
||||
let c_tx_dgrams = send_bytes(&mut client, 0, now);
|
||||
|
||||
// Initial/Handshake acks have already increased cwnd so 11 packets are
|
||||
// allowed
|
||||
assert_eq!(c_tx_dgrams.len(), INITIAL_CWND_PKTS + 1);
|
||||
assert_eq!(
|
||||
c_tx_dgrams.iter().map(|d| d.len()).sum::<usize>(),
|
||||
(INITIAL_CWND_PKTS * MAX_DATAGRAM_SIZE) + HANDSHAKE_CWND_INCREASE
|
||||
);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
let flight1_largest: PacketNumber = u64::try_from(c_tx_dgrams.len()).unwrap() - 1;
|
||||
|
||||
// Server: Receive and generate ack
|
||||
let (s_tx_dgram, _recvd_frames) = ack_bytes(&mut server, 0, c_tx_dgrams, now);
|
||||
@ -3703,23 +3651,24 @@ mod tests {
|
||||
// Client: Process ack
|
||||
let recvd_frames = client.test_process_input(s_tx_dgram, now);
|
||||
|
||||
const INITIAL_CWND_PKTS_U64: u64 = INITIAL_CWND_PKTS as u64;
|
||||
// Verify that server-sent frame was what we thought
|
||||
assert!(matches!(
|
||||
recvd_frames[0],
|
||||
(
|
||||
Frame::Ack {
|
||||
largest_acknowledged: INITIAL_CWND_PKTS_U64,
|
||||
..
|
||||
},
|
||||
PNSpace::ApplicationData,
|
||||
)
|
||||
));
|
||||
// Verify that server-sent frame was what we thought.
|
||||
if let (
|
||||
Frame::Ack {
|
||||
largest_acknowledged,
|
||||
..
|
||||
},
|
||||
PNSpace::ApplicationData,
|
||||
) = recvd_frames[0]
|
||||
{
|
||||
assert_eq!(largest_acknowledged, flight1_largest);
|
||||
} else {
|
||||
panic!("Expected an application ACK");
|
||||
}
|
||||
|
||||
// Client: send more
|
||||
let mut c_tx_dgrams = send_bytes(&mut client, 0, now);
|
||||
|
||||
assert_eq!(c_tx_dgrams.len(), INITIAL_CWND_PKTS * 2 + 1);
|
||||
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
|
||||
c_tx_dgrams.remove(0);
|
||||
@ -3728,17 +3677,19 @@ mod tests {
|
||||
// Client: Process ack
|
||||
let recvd_frames = client.test_process_input(s_tx_dgram, now);
|
||||
|
||||
// Verify that server-sent frame was what we thought
|
||||
assert!(matches!(
|
||||
recvd_frames[0],
|
||||
(
|
||||
Frame::Ack {
|
||||
largest_acknowledged: 31,
|
||||
..
|
||||
},
|
||||
PNSpace::ApplicationData,
|
||||
)
|
||||
));
|
||||
// Verify that server-sent frame was what we thought.
|
||||
if let (
|
||||
Frame::Ack {
|
||||
largest_acknowledged,
|
||||
..
|
||||
},
|
||||
PNSpace::ApplicationData,
|
||||
) = recvd_frames[0]
|
||||
{
|
||||
assert_eq!(largest_acknowledged, flight2_largest);
|
||||
} else {
|
||||
panic!("Expected an application ACK");
|
||||
}
|
||||
|
||||
// If we just triggered cong avoidance, these should be equal
|
||||
assert_eq!(client.loss_recovery.cwnd(), client.loss_recovery.ssthresh());
|
||||
@ -3759,10 +3710,10 @@ mod tests {
|
||||
|
||||
// Buffer up lot of data and generate packets
|
||||
let mut c_tx_dgrams = send_bytes(&mut client, 0, now);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
|
||||
// Drop 0th packet. When acked, this should put client into CARP.
|
||||
c_tx_dgrams.remove(0);
|
||||
assert_eq!(c_tx_dgrams.len(), 10);
|
||||
|
||||
let c_tx_dgrams2 = c_tx_dgrams.split_off(5);
|
||||
|
||||
@ -3852,7 +3803,7 @@ mod tests {
|
||||
|
||||
// Buffer up lot of data and generate packets
|
||||
let c_tx_dgrams = send_bytes(&mut client, 0, now);
|
||||
assert_eq!(c_tx_dgrams.len(), 11);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
|
||||
// Server: Receive and generate ack
|
||||
now += Duration::from_millis(100);
|
||||
@ -3901,7 +3852,7 @@ mod tests {
|
||||
|
||||
// Buffer up lot of data and generate packets
|
||||
let c_tx_dgrams = send_bytes(&mut client, 0, now);
|
||||
assert_eq!(c_tx_dgrams.len(), 11);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
|
||||
// Server: Receive and generate ack
|
||||
now += Duration::from_millis(100);
|
||||
@ -3955,7 +3906,7 @@ mod tests {
|
||||
|
||||
// Buffer up lot of data and generate packets
|
||||
let c_tx_dgrams = send_bytes(&mut client, 0, now);
|
||||
assert_eq!(c_tx_dgrams.len(), 11);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
|
||||
// Server: Receive and generate ack
|
||||
now += Duration::from_millis(100);
|
||||
@ -4025,7 +3976,7 @@ mod tests {
|
||||
let mut client = default_client();
|
||||
let init_pkt_c = client.process(None, now()).dgram();
|
||||
assert!(init_pkt_c.is_some());
|
||||
assert_eq!(init_pkt_c.as_ref().unwrap().len(), 1232);
|
||||
assert_eq!(init_pkt_c.as_ref().unwrap().len(), PATH_MTU_V6);
|
||||
|
||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||
let mut server = default_server();
|
||||
|
6
third_party/rust/neqo-transport/src/lib.rs
vendored
6
third_party/rust/neqo-transport/src/lib.rs
vendored
@ -19,13 +19,14 @@ mod events;
|
||||
mod flow_mgr;
|
||||
mod frame;
|
||||
mod packet;
|
||||
mod path;
|
||||
mod recovery;
|
||||
mod recv_stream;
|
||||
mod send_stream;
|
||||
pub mod server;
|
||||
mod stats;
|
||||
mod stream_id;
|
||||
mod tparams;
|
||||
pub mod tparams;
|
||||
mod tracking;
|
||||
|
||||
pub use self::cid::ConnectionIdManager;
|
||||
@ -33,11 +34,10 @@ pub use self::connection::{Connection, FixedConnectionIdManager, Output, Role, S
|
||||
pub use self::events::{ConnectionEvent, ConnectionEvents};
|
||||
pub use self::frame::CloseError;
|
||||
pub use self::frame::StreamType;
|
||||
pub use self::tparams::{tp_constants, TransportParameter};
|
||||
|
||||
/// The supported version of the QUIC protocol.
|
||||
pub type Version = u32;
|
||||
pub const QUIC_VERSION: Version = 0xff00_0000 + 25;
|
||||
pub const QUIC_VERSION: Version = 0xff00_0000 + 27;
|
||||
|
||||
const LOCAL_IDLE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60); // 1 minute
|
||||
|
||||
|
24
third_party/rust/neqo-transport/src/packet.rs
vendored
24
third_party/rust/neqo-transport/src/packet.rs
vendored
@ -549,20 +549,24 @@ impl<'a> PublicPacket<'a> {
|
||||
PACKET_HP_MASK_LONG
|
||||
};
|
||||
let first_byte = self.data[0] ^ (mask[0] & bits);
|
||||
let pn_len = usize::from((first_byte & 0x3) + 1);
|
||||
|
||||
// Make a copy of the header to work on.
|
||||
let mut hdrbytes = self.data[..self.header_len + pn_len].to_vec();
|
||||
let mut hdrbytes = self.data[..self.header_len + 4].to_vec();
|
||||
hdrbytes[0] = first_byte;
|
||||
|
||||
// Unmask the PN.
|
||||
let mut pn_encoded: u64 = 0;
|
||||
for i in 0..pn_len {
|
||||
for i in 0..4 {
|
||||
hdrbytes[self.header_len + i] ^= mask[1 + i];
|
||||
pn_encoded <<= 8;
|
||||
pn_encoded += u64::from(hdrbytes[self.header_len + i]);
|
||||
}
|
||||
|
||||
// Now decode the packet number length and apply it, hopefully in constant time.
|
||||
let pn_len = usize::from((first_byte & 0x3) + 1);
|
||||
hdrbytes.truncate(self.header_len + pn_len);
|
||||
pn_encoded >>= 8 * (4 - pn_len);
|
||||
|
||||
qtrace!("unmasked hdr={}", hex(&hdrbytes));
|
||||
|
||||
let key_phase = self.packet_type == PacketType::Short
|
||||
@ -671,15 +675,15 @@ mod tests {
|
||||
0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
|
||||
];
|
||||
const SAMPLE_INITIAL: &[u8] = &[
|
||||
0xc9, 0xff, 0x00, 0x00, 0x19, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0xc9, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x00, 0x40, 0x74, 0x16, 0x8b, 0xf2, 0x2b, 0x70, 0x02, 0x59, 0x6f, 0x99, 0xae, 0x67, 0xab,
|
||||
0xf6, 0x5a, 0x58, 0x52, 0xf5, 0x4f, 0x58, 0xc3, 0x7c, 0x80, 0x86, 0x82, 0xe2, 0xe4, 0x04,
|
||||
0x92, 0xd8, 0xa3, 0x89, 0x9f, 0xb0, 0x4f, 0xc0, 0xaf, 0xe9, 0xaa, 0xbc, 0x87, 0x67, 0xb1,
|
||||
0x8a, 0x0a, 0xa4, 0x93, 0x53, 0x74, 0x26, 0x37, 0x3b, 0x48, 0xd5, 0x02, 0x21, 0x4d, 0xd8,
|
||||
0x56, 0xd6, 0x3b, 0x78, 0xce, 0xe3, 0x7b, 0xc6, 0x64, 0xb3, 0xfe, 0x86, 0xd4, 0x87, 0xac,
|
||||
0x7a, 0x77, 0xc5, 0x30, 0x38, 0xa3, 0xcd, 0x32, 0xf0, 0xb5, 0x00, 0x4d, 0x9f, 0x57, 0x54,
|
||||
0xc4, 0xf7, 0xf2, 0xd1, 0xf3, 0x5c, 0xf3, 0xf7, 0x11, 0x63, 0x51, 0xc9, 0x2b, 0x99, 0xc8,
|
||||
0xae, 0x58, 0x33, 0x22, 0x5c, 0xb5, 0x18, 0x55, 0x20, 0xd6, 0x1e, 0x68, 0xcf, 0x5f,
|
||||
0xc4, 0xf7, 0xf2, 0xd1, 0xf3, 0x5c, 0xf3, 0xf7, 0x11, 0x63, 0x51, 0xc9, 0x2b, 0xd8, 0xc3,
|
||||
0xa9, 0x52, 0x8d, 0x2b, 0x6a, 0xca, 0x20, 0xf0, 0x80, 0x47, 0xd9, 0xf0, 0x17, 0xf0,
|
||||
];
|
||||
|
||||
#[test]
|
||||
@ -824,9 +828,9 @@ mod tests {
|
||||
}
|
||||
|
||||
const SAMPLE_RETRY: &[u8] = &[
|
||||
0xff, 0xff, 0x00, 0x00, 0x19, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1e, 0x5e, 0xc5, 0xb0, 0x14, 0xcb, 0xb1, 0xf0, 0xfd, 0x93,
|
||||
0xdf, 0x40, 0x48, 0xc4, 0x46, 0xa6,
|
||||
0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b, 0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69,
|
||||
0xf2, 0x93, 0xa1, 0x35, 0x9d, 0x8e,
|
||||
];
|
||||
const RETRY_TOKEN: &[u8] = b"token";
|
||||
|
||||
@ -907,7 +911,7 @@ mod tests {
|
||||
|
||||
const SAMPLE_VN: &[u8] = &[
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x08,
|
||||
0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0xff, 0x00, 0x00, 0x19, 0x0a, 0x0a, 0x0a,
|
||||
0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0xff, 0x00, 0x00, 0x1b, 0x0a, 0x0a, 0x0a,
|
||||
0x0a,
|
||||
];
|
||||
|
||||
|
97
third_party/rust/neqo-transport/src/path.rs
vendored
Normal file
97
third_party/rust/neqo-transport/src/path.rs
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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 std::net::SocketAddr;
|
||||
|
||||
use crate::cid::{ConnectionId, ConnectionIdRef};
|
||||
|
||||
use neqo_common::Datagram;
|
||||
|
||||
/// This is the MTU that we assume when using IPv6.
|
||||
/// We use this size for Initial packets, so we don't need to worry about probing for support.
|
||||
/// If the path doesn't support this MTU, we will assume that it doesn't support QUIC.
|
||||
///
|
||||
/// This is a multiple of 16 greater than the largest possible short header (1 + 20 + 4).
|
||||
pub const PATH_MTU_V6: usize = 1337;
|
||||
/// The path MTU for IPv4 can be 20 bytes larger than for v6.
|
||||
pub const PATH_MTU_V4: usize = PATH_MTU_V6 + 20;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Path {
|
||||
local: SocketAddr,
|
||||
remote: SocketAddr,
|
||||
local_cids: Vec<ConnectionId>,
|
||||
remote_cid: ConnectionId,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
/// Create a path from addresses and connection IDs.
|
||||
pub fn new(
|
||||
local: SocketAddr,
|
||||
remote: SocketAddr,
|
||||
local_cid: ConnectionId,
|
||||
remote_cid: ConnectionId,
|
||||
) -> Self {
|
||||
Self {
|
||||
local,
|
||||
remote,
|
||||
local_cids: vec![local_cid],
|
||||
remote_cid,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a path based on a received packet.
|
||||
pub fn from_datagram(d: &Datagram, remote_cid: ConnectionId) -> Self {
|
||||
Self {
|
||||
local: d.destination(),
|
||||
remote: d.source(),
|
||||
local_cids: Vec::new(),
|
||||
remote_cid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn received_on(&self, d: &Datagram) -> bool {
|
||||
self.local == d.destination() && self.remote == d.source()
|
||||
}
|
||||
|
||||
pub fn mtu(&self) -> usize {
|
||||
if self.local.is_ipv4() {
|
||||
PATH_MTU_V4
|
||||
} else {
|
||||
PATH_MTU_V6 // IPv6
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a connection ID to the local set.
|
||||
pub fn add_local_cid(&mut self, cid: ConnectionId) {
|
||||
self.local_cids.push(cid);
|
||||
}
|
||||
|
||||
/// Determine if the given connection ID is valid.
|
||||
pub fn valid_local_cid(&self, cid: &ConnectionIdRef) -> bool {
|
||||
self.local_cids.iter().any(|c| c == cid)
|
||||
}
|
||||
|
||||
/// Get the first local connection ID.
|
||||
pub fn local_cid(&self) -> &ConnectionId {
|
||||
self.local_cids.first().as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Set the remote connection ID based on the peer's valid.
|
||||
pub fn set_remote_cid(&mut self, cid: &ConnectionIdRef) {
|
||||
self.remote_cid = ConnectionId::from(cid);
|
||||
}
|
||||
|
||||
/// Access the remote connection ID.
|
||||
pub fn remote_cid(&self) -> &ConnectionId {
|
||||
&self.remote_cid
|
||||
}
|
||||
|
||||
/// Make a datagram.
|
||||
pub fn datagram<V: Into<Vec<u8>>>(&self, payload: V) -> Datagram {
|
||||
Datagram::new(self.local, self.remote, payload)
|
||||
}
|
||||
}
|
150
third_party/rust/neqo-transport/src/tparams.rs
vendored
150
third_party/rust/neqo-transport/src/tparams.rs
vendored
@ -14,40 +14,35 @@ use neqo_crypto::ext::{ExtensionHandler, ExtensionHandlerResult, ExtensionWriter
|
||||
use neqo_crypto::{HandshakeMessage, ZeroRttCheckResult, ZeroRttChecker};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::rc::Rc;
|
||||
|
||||
struct PreferredAddress {
|
||||
// TODO(ekr@rtfm.com): Implement.
|
||||
}
|
||||
|
||||
pub mod tp_constants {
|
||||
pub type TransportParameterId = u16;
|
||||
macro_rules! tpids {
|
||||
pub type TransportParameterId = u64;
|
||||
macro_rules! tpids {
|
||||
{ $($n:ident = $v:expr),+ $(,)? } => {
|
||||
$(pub const $n: TransportParameterId = $v as TransportParameterId;)+
|
||||
};
|
||||
}
|
||||
tpids! {
|
||||
ORIGINAL_CONNECTION_ID = 0,
|
||||
IDLE_TIMEOUT = 1,
|
||||
STATELESS_RESET_TOKEN = 2,
|
||||
MAX_PACKET_SIZE = 3,
|
||||
INITIAL_MAX_DATA = 4,
|
||||
INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 5,
|
||||
INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 6,
|
||||
INITIAL_MAX_STREAM_DATA_UNI = 7,
|
||||
INITIAL_MAX_STREAMS_BIDI = 8,
|
||||
INITIAL_MAX_STREAMS_UNI = 9,
|
||||
ACK_DELAY_EXPONENT = 10,
|
||||
MAX_ACK_DELAY = 11,
|
||||
DISABLE_MIGRATION = 12,
|
||||
PREFERRED_ADDRESS = 13,
|
||||
}
|
||||
tpids! {
|
||||
ORIGINAL_CONNECTION_ID = 0,
|
||||
IDLE_TIMEOUT = 1,
|
||||
STATELESS_RESET_TOKEN = 2,
|
||||
MAX_PACKET_SIZE = 3,
|
||||
INITIAL_MAX_DATA = 4,
|
||||
INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 5,
|
||||
INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 6,
|
||||
INITIAL_MAX_STREAM_DATA_UNI = 7,
|
||||
INITIAL_MAX_STREAMS_BIDI = 8,
|
||||
INITIAL_MAX_STREAMS_UNI = 9,
|
||||
ACK_DELAY_EXPONENT = 10,
|
||||
MAX_ACK_DELAY = 11,
|
||||
DISABLE_MIGRATION = 12,
|
||||
PREFERRED_ADDRESS = 13,
|
||||
}
|
||||
|
||||
use self::tp_constants::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum TransportParameter {
|
||||
Bytes(Vec<u8>),
|
||||
@ -56,41 +51,41 @@ pub enum TransportParameter {
|
||||
}
|
||||
|
||||
impl TransportParameter {
|
||||
fn encode(&self, enc: &mut Encoder, tipe: u16) {
|
||||
enc.encode_uint(2, tipe);
|
||||
fn encode(&self, enc: &mut Encoder, tp: TransportParameterId) {
|
||||
enc.encode_varint(tp);
|
||||
match self {
|
||||
Self::Bytes(a) => {
|
||||
enc.encode_vec(2, a);
|
||||
enc.encode_vvec(a);
|
||||
}
|
||||
Self::Integer(a) => {
|
||||
enc.encode_vec_with(2, |enc_inner| {
|
||||
enc.encode_vvec_with(|enc_inner| {
|
||||
enc_inner.encode_varint(*a);
|
||||
});
|
||||
}
|
||||
Self::Empty => {
|
||||
enc.encode_uint(2, 0_u64);
|
||||
enc.encode_varint(0_u64);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn decode(dec: &mut Decoder) -> Res<Option<(u16, Self)>> {
|
||||
let tipe = match dec.decode_uint(2) {
|
||||
Some(v) => v.try_into()?,
|
||||
_ => return Err(Error::NoMoreData),
|
||||
};
|
||||
let content = match dec.decode_vec(2) {
|
||||
fn decode(dec: &mut Decoder) -> Res<Option<(TransportParameterId, Self)>> {
|
||||
let tp = match dec.decode_varint() {
|
||||
Some(v) => v,
|
||||
_ => return Err(Error::NoMoreData),
|
||||
};
|
||||
qtrace!("TP {:x} length {:x}", tipe, content.len());
|
||||
let content = match dec.decode_vvec() {
|
||||
Some(v) => v,
|
||||
_ => return Err(Error::NoMoreData),
|
||||
};
|
||||
qtrace!("TP {:x} length {:x}", tp, content.len());
|
||||
let mut d = Decoder::from(content);
|
||||
let tp = match tipe {
|
||||
ORIGINAL_CONNECTION_ID => Self::Bytes(d.decode_remainder().to_vec()), // TODO(mt) unnecessary copy
|
||||
let value = match tp {
|
||||
ORIGINAL_CONNECTION_ID => Self::Bytes(d.decode_remainder().to_vec()),
|
||||
STATELESS_RESET_TOKEN => {
|
||||
if d.remaining() != 16 {
|
||||
return Err(Error::TransportParameterError);
|
||||
}
|
||||
Self::Bytes(d.decode_remainder().to_vec()) // TODO(mt) unnecessary copy
|
||||
Self::Bytes(d.decode_remainder().to_vec())
|
||||
}
|
||||
IDLE_TIMEOUT
|
||||
| INITIAL_MAX_DATA
|
||||
@ -121,40 +116,35 @@ impl TransportParameter {
|
||||
if d.remaining() > 0 {
|
||||
return Err(Error::TooMuchData);
|
||||
}
|
||||
qtrace!("TP decoded; type {:x} val {:?}", tipe, tp);
|
||||
Ok(Some((tipe, tp)))
|
||||
qtrace!("TP decoded; type {:x} val {:?}", tp, value);
|
||||
Ok(Some((tp, value)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct TransportParameters {
|
||||
params: HashMap<u16, TransportParameter>,
|
||||
params: HashMap<TransportParameterId, TransportParameter>,
|
||||
}
|
||||
|
||||
impl TransportParameters {
|
||||
/// Set a value.
|
||||
pub fn set(&mut self, k: u16, v: TransportParameter) {
|
||||
pub fn set(&mut self, k: TransportParameterId, v: TransportParameter) {
|
||||
self.params.insert(k, v);
|
||||
}
|
||||
|
||||
/// Clear a key.
|
||||
pub fn remove(&mut self, k: u16) {
|
||||
pub fn remove(&mut self, k: TransportParameterId) {
|
||||
self.params.remove(&k);
|
||||
}
|
||||
|
||||
/// Decode is a static function that parses transport parameters
|
||||
/// using the provided decoder.
|
||||
pub fn decode(d: &mut Decoder) -> Res<Self> {
|
||||
pub(crate) fn decode(d: &mut Decoder) -> Res<Self> {
|
||||
let mut tps = Self::default();
|
||||
qtrace!("Parsed fixed TP header");
|
||||
|
||||
let params = match d.decode_vec(2) {
|
||||
Some(v) => v,
|
||||
_ => return Err(Error::TransportParameterError),
|
||||
};
|
||||
let mut d2 = Decoder::from(params);
|
||||
while d2.remaining() > 0 {
|
||||
match TransportParameter::decode(&mut d2) {
|
||||
while d.remaining() > 0 {
|
||||
match TransportParameter::decode(d) {
|
||||
Ok(Some((tipe, tp))) => {
|
||||
tps.set(tipe, tp);
|
||||
}
|
||||
@ -165,17 +155,15 @@ impl TransportParameters {
|
||||
Ok(tps)
|
||||
}
|
||||
|
||||
pub fn encode(&self, enc: &mut Encoder) {
|
||||
enc.encode_vec_with(2, |mut enc_inner| {
|
||||
for (tipe, tp) in &self.params {
|
||||
tp.encode(&mut enc_inner, *tipe);
|
||||
}
|
||||
});
|
||||
pub(crate) fn encode(&self, enc: &mut Encoder) {
|
||||
for (tipe, tp) in &self.params {
|
||||
tp.encode(enc, *tipe);
|
||||
}
|
||||
}
|
||||
|
||||
// Get an integer type or a default.
|
||||
pub fn get_integer(&self, tipe: u16) -> u64 {
|
||||
let default = match tipe {
|
||||
pub fn get_integer(&self, tp: TransportParameterId) -> u64 {
|
||||
let default = match tp {
|
||||
IDLE_TIMEOUT
|
||||
| INITIAL_MAX_DATA
|
||||
| INITIAL_MAX_STREAM_DATA_BIDI_LOCAL
|
||||
@ -188,7 +176,7 @@ impl TransportParameters {
|
||||
MAX_ACK_DELAY => 25,
|
||||
_ => panic!("Transport parameter not known or not an Integer"),
|
||||
};
|
||||
match self.params.get(&tipe) {
|
||||
match self.params.get(&tp) {
|
||||
None => default,
|
||||
Some(TransportParameter::Integer(x)) => *x,
|
||||
_ => panic!("Internal error"),
|
||||
@ -196,8 +184,8 @@ impl TransportParameters {
|
||||
}
|
||||
|
||||
// Get an integer type or a default.
|
||||
pub fn set_integer(&mut self, tipe: u16, value: u64) {
|
||||
match tipe {
|
||||
pub fn set_integer(&mut self, tp: TransportParameterId, value: u64) {
|
||||
match tp {
|
||||
IDLE_TIMEOUT
|
||||
| INITIAL_MAX_DATA
|
||||
| INITIAL_MAX_STREAM_DATA_BIDI_LOCAL
|
||||
@ -208,38 +196,38 @@ impl TransportParameters {
|
||||
| MAX_PACKET_SIZE
|
||||
| ACK_DELAY_EXPONENT
|
||||
| MAX_ACK_DELAY => {
|
||||
self.set(tipe, TransportParameter::Integer(value));
|
||||
self.set(tp, TransportParameter::Integer(value));
|
||||
}
|
||||
_ => panic!("Transport parameter not known"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bytes(&self, tipe: u16) -> Option<Vec<u8>> {
|
||||
match tipe {
|
||||
pub fn get_bytes(&self, tp: TransportParameterId) -> Option<Vec<u8>> {
|
||||
match tp {
|
||||
ORIGINAL_CONNECTION_ID | STATELESS_RESET_TOKEN => {}
|
||||
_ => panic!("Transport parameter not known or not type bytes"),
|
||||
}
|
||||
|
||||
match self.params.get(&tipe) {
|
||||
match self.params.get(&tp) {
|
||||
None => None,
|
||||
Some(TransportParameter::Bytes(x)) => Some(x.to_vec()),
|
||||
_ => panic!("Internal error"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_bytes(&mut self, tipe: u16, value: Vec<u8>) {
|
||||
match tipe {
|
||||
pub fn set_bytes(&mut self, tp: TransportParameterId, value: Vec<u8>) {
|
||||
match tp {
|
||||
ORIGINAL_CONNECTION_ID | STATELESS_RESET_TOKEN => {
|
||||
self.set(tipe, TransportParameter::Bytes(value));
|
||||
self.set(tp, TransportParameter::Bytes(value));
|
||||
}
|
||||
_ => panic!("Transport parameter not known or not type bytes"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_empty(&mut self, tipe: u16) {
|
||||
match tipe {
|
||||
pub fn set_empty(&mut self, tp: TransportParameterId) {
|
||||
match tp {
|
||||
DISABLE_MIGRATION => {
|
||||
self.set(tipe, TransportParameter::Empty);
|
||||
self.set(tp, TransportParameter::Empty);
|
||||
}
|
||||
_ => panic!("Transport parameter not known or not type empty"),
|
||||
}
|
||||
@ -248,7 +236,7 @@ impl TransportParameters {
|
||||
/// Return true if the remembered transport parameters are OK for 0-RTT.
|
||||
/// Generally this means that any value that is currently in effect is greater than
|
||||
/// or equal to the promised value.
|
||||
pub fn ok_for_0rtt(&self, remembered: &Self) -> bool {
|
||||
pub(crate) fn ok_for_0rtt(&self, remembered: &Self) -> bool {
|
||||
for (k, v_rem) in &remembered.params {
|
||||
// Skip checks for these, which don't affect 0-RTT.
|
||||
if matches!(
|
||||
@ -277,16 +265,16 @@ impl TransportParameters {
|
||||
true
|
||||
}
|
||||
|
||||
fn was_sent(&self, tipe: u16) -> bool {
|
||||
self.params.contains_key(&tipe)
|
||||
fn was_sent(&self, tp: TransportParameterId) -> bool {
|
||||
self.params.contains_key(&tp)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct TransportParametersHandler {
|
||||
pub local: TransportParameters,
|
||||
pub remote: Option<TransportParameters>,
|
||||
pub remote_0rtt: Option<TransportParameters>,
|
||||
pub(crate) local: TransportParameters,
|
||||
pub(crate) remote: Option<TransportParameters>,
|
||||
pub(crate) remote_0rtt: Option<TransportParameters>,
|
||||
}
|
||||
|
||||
impl TransportParametersHandler {
|
||||
@ -337,7 +325,7 @@ impl ExtensionHandler for TransportParametersHandler {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TpZeroRttChecker {
|
||||
pub(crate) struct TpZeroRttChecker {
|
||||
handler: Rc<RefCell<TransportParametersHandler>>,
|
||||
}
|
||||
|
||||
@ -482,10 +470,4 @@ mod tests {
|
||||
assert!(!tps_b.ok_for_0rtt(&tps_a));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_apple_tps() {
|
||||
let enc = Encoder::from_hex("0049000100011e00020010449aeef472626f18a5bba2d51ae473be0003000244b0000400048015f9000005000480015f900006000480015f90000700048004000000080001080009000108");
|
||||
let tps2 = TransportParameters::decode(&mut enc.as_decoder()).unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use neqo_common::{Datagram, Encoder};
|
||||
use neqo_transport::State;
|
||||
use test_fixture::*;
|
||||
|
||||
const INITIAL_PACKET: &str = "c0ff000019088394c8f03e5157080000\
|
||||
const INITIAL_PACKET: &str = "c0ff00001b088394c8f03e5157080000\
|
||||
449e3b343aa8535064a4268a0d9d7b1c\
|
||||
9d250ae355162276e9b1e3011ef6bbc0\
|
||||
ab48ad5bcc2681e953857ca62becd752\
|
||||
@ -86,7 +86,7 @@ const INITIAL_PACKET: &str = "c0ff000019088394c8f03e5157080000\
|
||||
d2bee680d8f41a597c262648bb18bcfc\
|
||||
13c8b3d97b1a77b2ac3af745d61a34cc\
|
||||
4709865bac824a94bb19058015e4e42d\
|
||||
aebe13f98ec51170a4aad0a8324bb768";
|
||||
38d3b779d72edc00c5cd088eff802b05";
|
||||
|
||||
#[test]
|
||||
fn process_client_initial() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user