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:
Andy Grover 2020-03-03 17:03:45 +00:00
parent cdad6a0be8
commit 948bb52d09
28 changed files with 992 additions and 810 deletions

View File

@ -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
View File

@ -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",

View File

@ -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 {

View File

@ -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

View File

@ -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"]

View File

@ -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}

View File

@ -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"

View File

@ -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}

View File

@ -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"

View File

@ -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}

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View 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;
}
}

View File

@ -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<()> {

View File

@ -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 {

View File

@ -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}

View File

@ -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"

View File

@ -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}

View File

@ -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"

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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,
];

View 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)
}
}

View File

@ -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();
}
}

View File

@ -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() {