Repository: c410-f3r/wtx (language: rust)

Issue:
[HTTP] Header names should be interpreted as strings instead of bytes
The current status-quo is a technical debt originated from the initial iterations of the project.


Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 700c0814..77e70251 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -172,6 +172,15 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "as-slice"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
+dependencies = [
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "atomic-polyfill"
 version = "1.0.3"
@@ -181,6 +190,18 @@ dependencies = [
  "critical-section",
 ]
 
+[[package]]
+name = "atomic-pool"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c5fc22e05ec2884db458bf307dc7b278c9428888d2b6e6fad9c0ae7804f5f6"
+dependencies = [
+ "as-slice 0.1.5",
+ "as-slice 0.2.1",
+ "atomic-polyfill",
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.4.0"
@@ -230,6 +251,12 @@ dependencies = [
  "smallvec",
 ]
 
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
 [[package]]
 name = "bitvec"
 version = "1.0.1"
@@ -289,7 +316,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -427,7 +454,7 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -450,9 +477,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
 dependencies = [
  "libc",
 ]
@@ -541,7 +568,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -551,16 +578,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
  "block-buffer",
+ "const-oid",
  "crypto-common 0.1.6",
  "subtle",
 ]
 
+[[package]]
+name = "document-features"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
+dependencies = [
+ "litrs",
+]
+
 [[package]]
 name = "dotenv"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
 
+[[package]]
+name = "ecdsa"
+version = "0.16.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
+dependencies = [
+ "der",
+ "digest",
+ "elliptic-curve",
+ "rfc6979",
+ "signature",
+]
+
 [[package]]
 name = "elliptic-curve"
 version = "0.13.8"
@@ -580,6 +630,105 @@ dependencies = [
  "zeroize",
 ]
 
+[[package]]
+name = "embassy-net"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cf91dd36dfd623de32242af711fd294d41159f02130052fc93c5c5ba93febe"
+dependencies = [
+ "as-slice 0.2.1",
+ "atomic-pool",
+ "document-features",
+ "embassy-net-driver",
+ "embassy-sync",
+ "embassy-time",
+ "embedded-io-async",
+ "embedded-nal-async",
+ "futures",
+ "generic-array 0.14.7",
+ "heapless 0.8.0",
+ "managed",
+ "smoltcp",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "embassy-net-driver"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d"
+
+[[package]]
+name = "embassy-sync"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec"
+dependencies = [
+ "cfg-if",
+ "critical-section",
+ "embedded-io-async",
+ "futures-util",
+ "heapless 0.8.0",
+]
+
+[[package]]
+name = "embassy-time"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309"
+dependencies = [
+ "cfg-if",
+ "critical-section",
+ "document-features",
+ "embassy-time-driver",
+ "embassy-time-queue-driver",
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0",
+ "embedded-hal-async",
+ "futures-util",
+ "heapless 0.8.0",
+]
+
+[[package]]
+name = "embassy-time-driver"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24"
+dependencies = [
+ "document-features",
+]
+
+[[package]]
+name = "embassy-time-queue-driver"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0"
+
+[[package]]
+name = "embedded-hal"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
+dependencies = [
+ "nb 0.1.3",
+ "void",
+]
+
+[[package]]
+name = "embedded-hal"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
+
+[[package]]
+name = "embedded-hal-async"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
+dependencies = [
+ "embedded-hal 1.0.0",
+]
+
 [[package]]
 name = "embedded-io"
 version = "0.6.1"
@@ -596,14 +745,34 @@ dependencies = [
 ]
 
 [[package]]
-name = "embedded-tls"
-version = "0.17.0"
+name = "embedded-nal"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6efb76fdd004a4ef787640177237b83449e6c5847765ea50bf15900061fd601"
+checksum = "b8a943fad5ed3d3f8a00f1e80f6bba371f1e7f0df28ec38477535eb318dc19cc"
+dependencies = [
+ "nb 1.1.0",
+ "no-std-net",
+]
+
+[[package]]
+name = "embedded-nal-async"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72229137a4fc12d239b0b7f50f04b30790678da6d782a0f3f1909bf57ec4b759"
+dependencies = [
+ "embedded-io-async",
+ "embedded-nal",
+ "no-std-net",
+]
+
+[[package]]
+name = "embedded-tls"
+version = "0.17.1"
+source = "git+https://github.com/drogue-iot/embedded-tls#7936bc11c123260065b5b9776b584308ad2e8f8a"
 dependencies = [
  "aes-gcm 0.10.3",
- "atomic-polyfill",
  "digest",
+ "ecdsa",
  "embedded-io",
  "embedded-io-async",
  "generic-array 0.14.7",
@@ -612,8 +781,10 @@ dependencies = [
  "hkdf",
  "hmac",
  "p256",
+ "portable-atomic",
  "rand_core",
  "sha2",
+ "signature",
  "typenum",
 ]
 
@@ -662,6 +833,79 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
 
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-core",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.12.4"
@@ -788,7 +1032,7 @@ version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
 dependencies = [
- "as-slice",
+ "as-slice 0.1.5",
  "generic-array 0.14.7",
  "hash32 0.1.1",
  "stable_deref_trait",
@@ -909,9 +1153,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.11"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2"
 
 [[package]]
 name = "jobserver"
@@ -939,9 +1183,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.162"
+version = "0.2.164"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
+checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
 
 [[package]]
 name = "libfuzzer-sys"
@@ -962,12 +1206,24 @@ dependencies = [
  "zlib-rs",
 ]
 
+[[package]]
+name = "litrs"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
+
 [[package]]
 name = "log"
 version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
+[[package]]
+name = "managed"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
+
 [[package]]
 name = "matchers"
 version = "0.1.0"
@@ -1016,6 +1272,27 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "nb"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
+dependencies = [
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "nb"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+
+[[package]]
+name = "no-std-net"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
+
 [[package]]
 name = "nom"
 version = "7.1.3"
@@ -1071,8 +1348,10 @@ version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
 dependencies = [
+ "ecdsa",
  "elliptic-curve",
  "primeorder",
+ "sha2",
 ]
 
 [[package]]
@@ -1112,6 +1391,12 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
 
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
 [[package]]
 name = "polyval"
 version = "0.6.2"
@@ -1138,15 +1423,15 @@ dependencies = [
 
 [[package]]
 name = "portable-atomic"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
 
 [[package]]
 name = "portable-atomic-util"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90a7d5beecc52a491b54d6dd05c7a45ba1801666a5baad9fdbfc6fef8d2d206c"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
 dependencies = [
  "portable-atomic",
 ]
@@ -1180,9 +1465,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.89"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -1314,6 +1599,16 @@ dependencies = [
  "bytecheck",
 ]
 
+[[package]]
+name = "rfc6979"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
+dependencies = [
+ "hmac",
+ "subtle",
+]
+
 [[package]]
 name = "ring"
 version = "0.17.8"
@@ -1382,9 +1677,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustls"
-version = "0.23.16"
+version = "0.23.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
+checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
 dependencies = [
  "once_cell",
  "ring",
@@ -1462,14 +1757,14 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.132"
+version = "1.0.133"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
 dependencies = [
  "itoa",
  "memchr",
@@ -1529,6 +1824,7 @@ version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
 dependencies = [
+ "digest",
  "rand_core",
 ]
 
@@ -1544,6 +1840,19 @@ version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
+[[package]]
+name = "smoltcp"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a1a996951e50b5971a2c8c0fa05a381480d70a933064245c4a223ddc87ccc97"
+dependencies = [
+ "bitflags",
+ "byteorder",
+ "cfg-if",
+ "heapless 0.8.0",
+ "managed",
+]
+
 [[package]]
 name = "socket2"
 version = "0.5.7"
@@ -1595,9 +1904,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.87"
+version = "2.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
+checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1642,7 +1951,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -1694,7 +2003,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -1761,7 +2070,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -1823,9 +2132,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.13"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "universal-hash"
@@ -1871,6 +2180,12 @@ version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -1899,7 +2214,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
  "wasm-bindgen-shared",
 ]
 
@@ -1921,7 +2236,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -1934,9 +2249,9 @@ checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
 
 [[package]]
 name = "webpki-roots"
-version = "0.26.6"
+version = "0.26.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958"
+checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e"
 dependencies = [
  "rustls-pki-types",
 ]
@@ -2063,6 +2378,7 @@ dependencies = [
  "cl-aux",
  "crypto-common 0.1.6",
  "digest",
+ "embassy-net",
  "embedded-io-async",
  "embedded-tls",
  "fastrand",
@@ -2189,7 +2505,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
@@ -2209,7 +2525,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.87",
+ "syn 2.0.89",
 ]
 
 [[package]]
diff --git a/wtx-docs/src/web-socket/README.md b/wtx-docs/src/web-socket/README.md
index 3386cf75..524a569a 100644
--- a/wtx-docs/src/web-socket/README.md
+++ b/wtx-docs/src/web-socket/README.md
@@ -2,6 +2,8 @@
 
 Implementation of [RFC6455](https://datatracker.ietf.org/doc/html/rfc6455) and [RFC7692](https://datatracker.ietf.org/doc/html/rfc7692). WebSocket is a communication protocol that enables full-duplex communication between a client (typically a web browser) and a server over a single TCP connection. Unlike traditional HTTP, which is request-response based, WebSocket allows real-time data exchange without the need for polling.
 
+In-house benchmarks are available at <https://c410-f3r.github.io/wtx-bench>. If you are aware of other benchmark tools, please open an discussion in the GitHub project.
+
 To use this functionality, it is necessary to activate the `web-socket` feature.
 
 ![WebSocket Benchmark](https://i.imgur.com/Iv2WzJV.jpg)
@@ -21,7 +23,7 @@ To get the most performance possible, try compiling your program with `RUSTFLAGS
 
 Although not officially endorsed, the `no-masking` parameter described at <https://datatracker.ietf.org/doc/html/draft-damjanovic-websockets-nomasking-02> is supported to increase performance. If such a thing is not desirable, please make sure to check the handshake parameters to avoid accidental scenarios.
 
-To make everything work as intended both partys, client and server, need to implement this feature. For example, web browser won't stop masking frames.
+To make everything work as intended both parties, client and server, need to implement this feature. For example, web browser won't stop masking frames.
 
 ## Client Example
 
diff --git a/wtx-instances/Cargo.toml b/wtx-instances/Cargo.toml
index e83329a1..868c4d90 100644
--- a/wtx-instances/Cargo.toml
+++ b/wtx-instances/Cargo.toml
@@ -99,7 +99,7 @@ required-features = ["wtx/http-server-framework"]
 [[example]]
 name = "http-server-framework-session"
 path = "http-server-framework-examples/http-server-framework-session.rs"
-required-features = ["argon2", "rand_chacha", "rand_core", "serde", "serde_json", "wtx/argon2", "wtx/http-server-framework", "wtx/http-session", "wtx/pool", "wtx/postgres", "wtx/rand_chacha"]
+required-features = ["argon2", "rand_chacha", "rand_core", "serde", "serde_json", "wtx/argon2", "wtx/http-server-framework", "wtx/http-session", "wtx/pool", "wtx/postgres", "wtx/rand_chacha", "wtx-macros"]
 
 # HTTP/2 Examples
 
diff --git a/wtx-instances/http-server-framework-examples/http-server-framework-session.rs b/wtx-instances/http-server-framework-examples/http-server-framework-session.rs
index a91b715f..1a348432 100644
--- a/wtx-instances/http-server-framework-examples/http-server-framework-session.rs
+++ b/wtx-instances/http-server-framework-examples/http-server-framework-session.rs
@@ -27,33 +27,39 @@ use wtx::{
   database::{Executor, Record},
   http::{
     server_framework::{get, post, Router, ServerFrameworkBuilder, State, StateClean},
-    ReqResBuffer, ReqResData, SessionDecoder, SessionEnforcer, SessionTokio, StatusCode,
+    ReqResBuffer, ReqResData, SessionDecoder, SessionEnforcer, SessionManagerTokio, SessionState,
+    StatusCode,
   },
   misc::{argon2_pwd, Vector},
   pool::{PostgresRM, SimplePoolTokio},
 };
 
-type ConnAux = (Session, ChaCha20Rng);
 type Pool = SimplePoolTokio<PostgresRM<wtx::Error, TcpStream>>;
-type Session = SessionTokio<u32, wtx::Error, Pool>;
+type SessionManager = SessionManagerTokio<u32, wtx::Error>;
 
 #[tokio::main]
 async fn main() -> wtx::Result<()> {
-  let pool = Pool::new(4, PostgresRM::tokio("postgres://USER:PASSWORD@localhost/DB_NAME".into()));
+  let uri = "postgres://USER:PASSWORD@localhost/DB_NAME";
+  let mut pool = Pool::new(4, PostgresRM::tokio(uri.into()));
   let mut rng = ChaCha20Rng::from_entropy();
-  let (expired_sessions, session) = Session::builder(pool).build_generating_key(&mut rng);
+  let (expired, sm) = SessionManager::builder().build_generating_key(&mut rng, &mut pool);
   let router = Router::new(
     wtx::paths!(("/login", post(login)), ("/logout", get(logout)),),
-    (SessionDecoder::new(session.clone()), SessionEnforcer::new(["/admin"], session.clone())),
+    (SessionDecoder::new(sm.clone(), pool.clone()), SessionEnforcer::new(["/admin"])),
   )?;
   tokio::spawn(async move {
-    if let Err(err) = expired_sessions.await {
+    if let Err(err) = expired.await {
       eprintln!("{err}");
     }
   });
   let rng_clone = rng.clone();
   ServerFrameworkBuilder::new(router)
-    .with_conn_aux(move || (session.clone(), rng_clone.clone()))
+    .with_conn_aux(move || ConnAux {
+      pool: pool.clone(),
+      rng: rng_clone.clone(),
+      session_manager: sm.clone(),
+      session_state: None,
+    })
     .tokio("0.0.0.0:9000", rng, |err| eprintln!("{err:?}"), |_| Ok(()))
     .await?;
   Ok(())
@@ -61,14 +67,14 @@ async fn main() -> wtx::Result<()> {
 
 #[inline]
 async fn login(state: State<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<StatusCode> {
-  let (Session { manager, store }, rng) = state.conn_aux;
-  if manager.inner.lock().await.state().is_some() {
-    manager.delete_session_cookie(&mut state.req.rrd, store).await?;
+  let ConnAux { pool, rng, session_manager, session_state } = state.conn_aux;
+  if session_state.is_some() {
+    session_manager.delete_session_cookie(&mut state.req.rrd, session_state, pool).await?;
     return Ok(StatusCode::Forbidden);
   }
   let user: UserLoginReq<'_> = serde_json::from_slice(state.req.rrd.body())?;
-  let mut guard = store.get().await?;
-  let record = guard
+  let mut pool_guard = pool.get().await?;
+  let record = pool_guard
     .fetch_with_stmt("SELECT id,first_name,password,salt FROM user WHERE email = $1", (user.email,))
     .await?;
   let id = record.decode::<_, u32>(0)?;
@@ -81,18 +87,26 @@ async fn login(state: State<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<Statu
     return Ok(StatusCode::Unauthorized);
   }
   serde_json::to_writer(&mut state.req.rrd.body, &UserLoginRes { id, name: first_name })?;
-  drop(guard);
-  manager.set_session_cookie(id, rng, &mut state.req.rrd, store).await?;
+  drop(pool_guard);
+  session_manager.set_session_cookie(id, rng, &mut state.req.rrd, pool).await?;
   Ok(StatusCode::Ok)
 }
 
 #[inline]
 async fn logout(state: StateClean<'_, ConnAux, (), ReqResBuffer>) -> wtx::Result<StatusCode> {
-  let (Session { manager, store }, _) = state.conn_aux;
-  manager.delete_session_cookie(&mut state.req.rrd, store).await?;
+  let ConnAux { pool, rng: _, session_manager, session_state } = state.conn_aux;
+  session_manager.delete_session_cookie(&mut state.req.rrd, session_state, pool).await?;
   Ok(StatusCode::Ok)
 }
 
+#[derive(Clone, Debug, wtx_macros::ConnAux)]
+struct ConnAux {
+  pool: Pool,
+  rng: ChaCha20Rng,
+  session_manager: SessionManager,
+  session_state: Option<SessionState<u32>>,
+}
+
 #[derive(Debug, serde::Deserialize)]
 struct UserLoginReq<'req> {
   email: &'req str,
diff --git a/wtx-instances/src/lib.rs b/wtx-instances/src/lib.rs
index 8151c769..e3f8faa6 100644
--- a/wtx-instances/src/lib.rs
+++ b/wtx-instances/src/lib.rs
@@ -39,8 +39,6 @@ pub static ROOT_CA: &[u8] = include_bytes!("../../.certs/root-ca.crt");
 pub async fn executor_postgres(
   uri_str: &str,
 ) -> wtx::Result<Executor<wtx::Error, ExecutorBuffer, TcpStream>> {
-  use std::usize;
-
   let uri = Uri::new(uri_str);
   let mut rng = Xorshift64::from(simple_seed());
   Executor::connect(
diff --git a/wtx-macros/Cargo.toml b/wtx-macros/Cargo.toml
index 8619906d..3fd7b073 100644
--- a/wtx-macros/Cargo.toml
+++ b/wtx-macros/Cargo.toml
@@ -1,7 +1,7 @@
 [dependencies]
 proc-macro2 = { default-features = false, version = "1.0" }
 quote = { default-features = false, features = ["proc-macro"], version = "1.0" }
-syn = { default-features = false, features = ["extra-traits", "full", "parsing", "printing", "proc-macro"], version = "1.0" }
+syn = { default-features = false, features = ["derive", "extra-traits", "full", "parsing", "printing", "proc-macro"], version = "1.0" }
 
 [dev-dependencies]
 trybuild = { default-features = false, version = "1.0" }
diff --git a/wtx-macros/src/client_api_framework.rs b/wtx-macros/src/client_api_framework.rs
new file mode 100644
index 00000000..ea239822
--- /dev/null
+++ b/wtx-macros/src/client_api_framework.rs
@@ -0,0 +1,6 @@
+pub(crate) mod api_params;
+pub(crate) mod contained_attrs;
+pub(crate) mod item_with_attr_span;
+pub(crate) mod owned_or_ref;
+pub(crate) mod pkg;
+pub(crate) mod transport_group;
diff --git a/wtx-macros/src/api_params.rs b/wtx-macros/src/client_api_framework/api_params.rs
similarity index 97%
rename from wtx-macros/src/api_params.rs
rename to wtx-macros/src/client_api_framework/api_params.rs
index a9879372..4703c0ed 100644
--- a/wtx-macros/src/api_params.rs
+++ b/wtx-macros/src/client_api_framework/api_params.rs
@@ -1,6 +1,9 @@
 mod attrs;
 
-use crate::{misc::create_ident, owned_or_ref::OwnedOrRef, transport_group::TransportGroup};
+use crate::{
+  client_api_framework::{owned_or_ref::OwnedOrRef, transport_group::TransportGroup},
+  misc::create_ident,
+};
 use proc_macro2::{Ident, Span};
 use quote::ToTokens;
 use syn::{
diff --git a/wtx-macros/src/api_params/attrs.rs b/wtx-macros/src/client_api_framework/api_params/attrs.rs
similarity index 95%
rename from wtx-macros/src/api_params/attrs.rs
rename to wtx-macros/src/client_api_framework/api_params/attrs.rs
index cbc4c976..5829762e 100644
--- a/wtx-macros/src/api_params/attrs.rs
+++ b/wtx-macros/src/client_api_framework/api_params/attrs.rs
@@ -1,4 +1,4 @@
-use crate::transport_group::TransportGroup;
+use crate::client_api_framework::transport_group::TransportGroup;
 use syn::{Meta, MetaList, NestedMeta, Path};
 
 #[derive(Debug)]
diff --git a/wtx-macros/src/contained_attrs.rs b/wtx-macros/src/client_api_framework/contained_attrs.rs
similarity index 100%
rename from wtx-macros/src/contained_attrs.rs
rename to wtx-macros/src/client_api_framework/contained_attrs.rs
diff --git a/wtx-macros/src/item_with_attr_span.rs b/wtx-macros/src/client_api_framework/item_with_attr_span.rs
similarity index 100%
rename from wtx-macros/src/item_with_attr_span.rs
rename to wtx-macros/src/client_api_framework/item_with_attr_span.rs
diff --git a/wtx-macros/src/owned_or_ref.rs b/wtx-macros/src/client_api_framework/owned_or_ref.rs
similarity index 100%
rename from wtx-macros/src/owned_or_ref.rs
rename to wtx-macros/src/client_api_framework/owned_or_ref.rs
diff --git a/wtx-macros/src/pkg.rs b/wtx-macros/src/client_api_framework/pkg.rs
similarity index 95%
rename from wtx-macros/src/pkg.rs
rename to wtx-macros/src/client_api_framework/pkg.rs
index 08f13a3b..1397563e 100644
--- a/wtx-macros/src/pkg.rs
+++ b/wtx-macros/src/client_api_framework/pkg.rs
@@ -23,9 +23,11 @@ use syn::{
 };
 
 use crate::{
-  item_with_attr_span::ItemWithAttrSpan,
+  client_api_framework::{
+    item_with_attr_span::ItemWithAttrSpan,
+    pkg::{fir::fir_after_sending_item_values::FirAfterSendingItemValues, misc::unit_type},
+  },
   misc::push_doc,
-  pkg::{fir::fir_after_sending_item_values::FirAfterSendingItemValues, misc::unit_type},
 };
 
 pub(crate) fn pkg(
diff --git a/wtx-macros/src/pkg/data_format.rs b/wtx-macros/src/client_api_framework/pkg/data_format.rs
similarity index 97%
rename from wtx-macros/src/pkg/data_format.rs
rename to wtx-macros/src/client_api_framework/pkg/data_format.rs
index dff4f649..c9b883ee 100644
--- a/wtx-macros/src/pkg/data_format.rs
+++ b/wtx-macros/src/client_api_framework/pkg/data_format.rs
@@ -1,4 +1,6 @@
-use crate::{pkg::data_format_elems::DataFormatElems, transport_group::TransportGroup};
+use crate::client_api_framework::{
+  pkg::data_format_elems::DataFormatElems, transport_group::TransportGroup,
+};
 use proc_macro2::{Ident, Span, TokenStream};
 use syn::{Lit, Meta, NestedMeta};
 
diff --git a/wtx-macros/src/pkg/data_format_elems.rs b/wtx-macros/src/client_api_framework/pkg/data_format_elems.rs
similarity index 100%
rename from wtx-macros/src/pkg/data_format_elems.rs
rename to wtx-macros/src/client_api_framework/pkg/data_format_elems.rs
diff --git a/wtx-macros/src/pkg/enum_struct_or_type.rs b/wtx-macros/src/client_api_framework/pkg/enum_struct_or_type.rs
similarity index 100%
rename from wtx-macros/src/pkg/enum_struct_or_type.rs
rename to wtx-macros/src/client_api_framework/pkg/enum_struct_or_type.rs
diff --git a/wtx-macros/src/pkg/fir.rs b/wtx-macros/src/client_api_framework/pkg/fir.rs
similarity index 100%
rename from wtx-macros/src/pkg/fir.rs
rename to wtx-macros/src/client_api_framework/pkg/fir.rs
diff --git a/wtx-macros/src/pkg/fir/fir_after_sending_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_after_sending_item_values.rs
similarity index 100%
rename from wtx-macros/src/pkg/fir/fir_after_sending_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_after_sending_item_values.rs
diff --git a/wtx-macros/src/pkg/fir/fir_aux_field_attr.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_aux_field_attr.rs
similarity index 94%
rename from wtx-macros/src/pkg/fir/fir_aux_field_attr.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_aux_field_attr.rs
index 3f3feb44..567f2c1b 100644
--- a/wtx-macros/src/pkg/fir/fir_aux_field_attr.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_aux_field_attr.rs
@@ -1,4 +1,4 @@
-use crate::pkg::keywords;
+use crate::client_api_framework::pkg::keywords;
 use syn::{
   parse::{Parse, ParseStream},
   spanned::Spanned,
diff --git a/wtx-macros/src/pkg/fir/fir_aux_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_aux_item_values.rs
similarity index 98%
rename from wtx-macros/src/pkg/fir/fir_aux_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_aux_item_values.rs
index a4df623c..753f69ac 100644
--- a/wtx-macros/src/pkg/fir/fir_aux_item_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_aux_item_values.rs
@@ -1,4 +1,4 @@
-use crate::{
+use crate::client_api_framework::{
   item_with_attr_span::ItemWithAttrSpan,
   pkg::{
     fir::fir_aux_field_attr::FirAuxFieldAttr,
diff --git a/wtx-macros/src/pkg/fir/fir_before_sending_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_before_sending_item_values.rs
similarity index 100%
rename from wtx-macros/src/pkg/fir/fir_before_sending_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_before_sending_item_values.rs
diff --git a/wtx-macros/src/pkg/fir/fir_custom_field_attr.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_attr.rs
similarity index 87%
rename from wtx-macros/src/pkg/fir/fir_custom_field_attr.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_attr.rs
index 52122eac..9bff4d81 100644
--- a/wtx-macros/src/pkg/fir/fir_custom_field_attr.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_attr.rs
@@ -1,4 +1,6 @@
-use crate::pkg::{fir::fir_custom_field_field_attr::FirCustomFieldFieldAttr, keywords};
+use crate::client_api_framework::pkg::{
+  fir::fir_custom_field_field_attr::FirCustomFieldFieldAttr, keywords,
+};
 use syn::{
   parse::{Parse, ParseStream},
   spanned::Spanned,
diff --git a/wtx-macros/src/pkg/fir/fir_custom_field_field_attr.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_field_attr.rs
similarity index 94%
rename from wtx-macros/src/pkg/fir/fir_custom_field_field_attr.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_field_attr.rs
index 16758efe..be542fae 100644
--- a/wtx-macros/src/pkg/fir/fir_custom_field_field_attr.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_custom_field_field_attr.rs
@@ -1,4 +1,4 @@
-use crate::pkg::keywords;
+use crate::client_api_framework::pkg::keywords;
 use proc_macro2::Ident;
 use syn::{
   parse::{Parse, ParseStream},
diff --git a/wtx-macros/src/pkg/fir/fir_custom_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_custom_item_values.rs
similarity index 97%
rename from wtx-macros/src/pkg/fir/fir_custom_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_custom_item_values.rs
index 8b1567a5..1e92f610 100644
--- a/wtx-macros/src/pkg/fir/fir_custom_item_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_custom_item_values.rs
@@ -1,4 +1,4 @@
-use crate::pkg::{
+use crate::client_api_framework::pkg::{
   enum_struct_or_type::EnumStructOrType, fir::fir_custom_field_field_attr::FirCustomFieldFieldAttr,
 };
 use syn::{punctuated::Punctuated, GenericParam, Ident, Token, Type, WherePredicate};
@@ -26,9 +26,9 @@ macro_rules! create_fir_custom_item_values {
     $($cb:expr)?,
   ) => {
     use crate::{
-      item_with_attr_span::ItemWithAttrSpan,
+      client_api_framework::item_with_attr_span::ItemWithAttrSpan,
       misc::push_doc_if_inexistent,
-      pkg::{
+      client_api_framework::pkg::{
         enum_struct_or_type::EnumStructOrType,
         fir::{
           fir_custom_field_attr::FirCustomFieldAttr,
diff --git a/wtx-macros/src/pkg/fir/fir_hook_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_hook_item_values.rs
similarity index 95%
rename from wtx-macros/src/pkg/fir/fir_hook_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_hook_item_values.rs
index 52e4a452..076a4281 100644
--- a/wtx-macros/src/pkg/fir/fir_hook_item_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_hook_item_values.rs
@@ -7,7 +7,7 @@ macro_rules! create_fir_hook_item_values {
     $fn_args_idents:expr,
     $error:ident,
   ) => {
-    use crate::item_with_attr_span::ItemWithAttrSpan;
+    use crate::client_api_framework::item_with_attr_span::ItemWithAttrSpan;
     use proc_macro2::TokenStream;
     use syn::{punctuated::Punctuated, FnArg, Item, ItemFn, Pat, Token};
 
diff --git a/wtx-macros/src/pkg/fir/fir_item_attr.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_item_attr.rs
similarity index 97%
rename from wtx-macros/src/pkg/fir/fir_item_attr.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_item_attr.rs
index 85834c1f..eb334d5f 100644
--- a/wtx-macros/src/pkg/fir/fir_item_attr.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_item_attr.rs
@@ -1,4 +1,4 @@
-use crate::pkg::keywords;
+use crate::client_api_framework::pkg::keywords;
 use proc_macro2::Span;
 use syn::{
   parse::{Parse, ParseBuffer, ParseStream},
diff --git a/wtx-macros/src/pkg/fir/fir_items_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_items_values.rs
similarity index 98%
rename from wtx-macros/src/pkg/fir/fir_items_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_items_values.rs
index 8de2d4c8..b62f5c3d 100644
--- a/wtx-macros/src/pkg/fir/fir_items_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_items_values.rs
@@ -1,4 +1,4 @@
-use crate::{
+use crate::client_api_framework::{
   contained_attrs::ContainedAttrs,
   item_with_attr_span::ItemWithAttrSpan,
   pkg::{
diff --git a/wtx-macros/src/pkg/fir/fir_params_items_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_params_items_values.rs
similarity index 100%
rename from wtx-macros/src/pkg/fir/fir_params_items_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_params_items_values.rs
diff --git a/wtx-macros/src/pkg/fir/fir_pkg_attr.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_pkg_attr.rs
similarity index 100%
rename from wtx-macros/src/pkg/fir/fir_pkg_attr.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_pkg_attr.rs
diff --git a/wtx-macros/src/pkg/fir/fir_req_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_req_item_values.rs
similarity index 100%
rename from wtx-macros/src/pkg/fir/fir_req_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_req_item_values.rs
diff --git a/wtx-macros/src/pkg/fir/fir_res_item_values.rs b/wtx-macros/src/client_api_framework/pkg/fir/fir_res_item_values.rs
similarity index 90%
rename from wtx-macros/src/pkg/fir/fir_res_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/fir/fir_res_item_values.rs
index c3e055f3..ddacd134 100644
--- a/wtx-macros/src/pkg/fir/fir_res_item_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/fir/fir_res_item_values.rs
@@ -1,4 +1,6 @@
-use crate::{item_with_attr_span::ItemWithAttrSpan, misc::push_doc_if_inexistent};
+use crate::{
+  client_api_framework::item_with_attr_span::ItemWithAttrSpan, misc::push_doc_if_inexistent,
+};
 use proc_macro2::Ident;
 use syn::Item;
 
diff --git a/wtx-macros/src/pkg/keywords.rs b/wtx-macros/src/client_api_framework/pkg/keywords.rs
similarity index 100%
rename from wtx-macros/src/pkg/keywords.rs
rename to wtx-macros/src/client_api_framework/pkg/keywords.rs
diff --git a/wtx-macros/src/pkg/misc.rs b/wtx-macros/src/client_api_framework/pkg/misc.rs
similarity index 100%
rename from wtx-macros/src/pkg/misc.rs
rename to wtx-macros/src/client_api_framework/pkg/misc.rs
diff --git a/wtx-macros/src/pkg/sir.rs b/wtx-macros/src/client_api_framework/pkg/sir.rs
similarity index 100%
rename from wtx-macros/src/pkg/sir.rs
rename to wtx-macros/src/client_api_framework/pkg/sir.rs
diff --git a/wtx-macros/src/pkg/sir/sir_aux_item_values.rs b/wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values.rs
similarity index 99%
rename from wtx-macros/src/pkg/sir/sir_aux_item_values.rs
rename to wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values.rs
index 24c73daf..999fd433 100644
--- a/wtx-macros/src/pkg/sir/sir_aux_item_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values.rs
@@ -2,8 +2,7 @@ mod sir_items_values_creators;
 mod sir_items_values_pushers;
 
 use crate::{
-  misc::{create_ident, extend_with_tmp_suffix},
-  pkg::{
+  client_api_framework::pkg::{
     fir::{
       fir_aux_item_values::FirAuxItemValues, fir_custom_item_values::FirCustomItemValuesRef,
       fir_params_items_values::FirParamsItemValues, fir_req_item_values::FirReqItemValues,
@@ -11,6 +10,7 @@ use crate::{
     misc::{from_camel_case_to_snake_case, split_params, EMPTY_GEN_PARAMS},
     sir::sir_pkg_attr::SirPkaAttr,
   },
+  misc::{create_ident, extend_with_tmp_suffix},
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use syn::{
diff --git a/wtx-macros/src/pkg/sir/sir_aux_item_values/sir_items_values_creators.rs b/wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values/sir_items_values_creators.rs
similarity index 99%
rename from wtx-macros/src/pkg/sir/sir_aux_item_values/sir_items_values_creators.rs
rename to wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values/sir_items_values_creators.rs
index bbb663b4..e8c3fae0 100644
--- a/wtx-macros/src/pkg/sir/sir_aux_item_values/sir_items_values_creators.rs
+++ b/wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values/sir_items_values_creators.rs
@@ -1,4 +1,4 @@
-use crate::pkg::{
+use crate::client_api_framework::pkg::{
   enum_struct_or_type::EnumStructOrType,
   fir::{fir_aux_item_values::FirAuxItemValues, fir_custom_item_values::FirCustomItemValuesRef},
   misc::{
diff --git a/wtx-macros/src/pkg/sir/sir_aux_item_values/sir_items_values_pushers.rs b/wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values/sir_items_values_pushers.rs
similarity index 99%
rename from wtx-macros/src/pkg/sir/sir_aux_item_values/sir_items_values_pushers.rs
rename to wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values/sir_items_values_pushers.rs
index 70aed661..a272d6f0 100644
--- a/wtx-macros/src/pkg/sir/sir_aux_item_values/sir_items_values_pushers.rs
+++ b/wtx-macros/src/client_api_framework/pkg/sir/sir_aux_item_values/sir_items_values_pushers.rs
@@ -1,4 +1,4 @@
-use crate::pkg::{
+use crate::client_api_framework::pkg::{
   data_format::DataFormat,
   fir::{
     fir_aux_item_values::FirAuxItemValues, fir_params_items_values::FirParamsItemValues,
diff --git a/wtx-macros/src/pkg/sir/sir_final_values.rs b/wtx-macros/src/client_api_framework/pkg/sir/sir_final_values.rs
similarity index 99%
rename from wtx-macros/src/pkg/sir/sir_final_values.rs
rename to wtx-macros/src/client_api_framework/pkg/sir/sir_final_values.rs
index 2986f9f0..f8d969fc 100644
--- a/wtx-macros/src/pkg/sir/sir_final_values.rs
+++ b/wtx-macros/src/client_api_framework/pkg/sir/sir_final_values.rs
@@ -1,4 +1,4 @@
-use crate::{
+use crate::client_api_framework::{
   pkg::{
     data_format_elems::DataFormatElems,
     fir::{
diff --git a/wtx-macros/src/pkg/sir/sir_pkg_attr.rs b/wtx-macros/src/client_api_framework/pkg/sir/sir_pkg_attr.rs
similarity index 96%
rename from wtx-macros/src/pkg/sir/sir_pkg_attr.rs
rename to wtx-macros/src/client_api_framework/pkg/sir/sir_pkg_attr.rs
index ab702f2a..e45940e8 100644
--- a/wtx-macros/src/pkg/sir/sir_pkg_attr.rs
+++ b/wtx-macros/src/client_api_framework/pkg/sir/sir_pkg_attr.rs
@@ -1,4 +1,4 @@
-use crate::{
+use crate::client_api_framework::{
   pkg::{data_format::DataFormat, fir::fir_pkg_attr::FirPkgAttr},
   transport_group::TransportGroup,
 };
diff --git a/wtx-macros/src/transport_group.rs b/wtx-macros/src/client_api_framework/transport_group.rs
similarity index 100%
rename from wtx-macros/src/transport_group.rs
rename to wtx-macros/src/client_api_framework/transport_group.rs
diff --git a/wtx-macros/src/error.rs b/wtx-macros/src/error.rs
index 102bcf7e..aa0fd7ef 100644
--- a/wtx-macros/src/error.rs
+++ b/wtx-macros/src/error.rs
@@ -21,6 +21,7 @@ pub(crate) enum Error {
   Syn(syn::Error),
   UnknownDataFormat,
   UnknownTransport(Span),
+  UnsupportedStructure,
 }
 
 impl From<syn::Error> for Error {
@@ -98,6 +99,7 @@ impl From<Error> for syn::Error {
       Error::Syn(error) => error,
       Error::UnknownDataFormat => syn::Error::new(Span::call_site(), "Unknown data format."),
       Error::UnknownTransport(span) => syn::Error::new(span, "Unknown transport."),
+      Error::UnsupportedStructure => syn::Error::new(Span::call_site(), "Unsupported structure."),
     }
   }
 }
diff --git a/wtx-macros/src/http.rs b/wtx-macros/src/http.rs
new file mode 100644
index 00000000..0f98935a
--- /dev/null
+++ b/wtx-macros/src/http.rs
@@ -0,0 +1,48 @@
+use quote::quote;
+use syn::{parse_macro_input, Data, DeriveInput, Fields};
+
+pub(crate) fn conn_aux(item: proc_macro::TokenStream) -> crate::Result<proc_macro::TokenStream> {
+  let input = parse_macro_input::parse::<DeriveInput>(item)?;
+  let name = input.ident;
+  let mut field_names = Vec::new();
+  let mut field_tys = Vec::new();
+  match input.data {
+    Data::Struct(data) => match data.fields {
+      Fields::Named(fields) => {
+        for elem in fields.named {
+          field_names.push(elem.ident);
+          field_tys.push(elem.ty);
+        }
+      }
+      _ => return Err(crate::Error::UnsupportedStructure),
+    },
+    _ => return Err(crate::Error::UnsupportedStructure),
+  }
+  let expanded = quote! {
+    impl wtx::http::server_framework::ConnAux for #name {
+        type Init = Self;
+
+        #[inline]
+        fn conn_aux(init: Self::Init) -> wtx::Result<Self> {
+          Ok(init)
+        }
+      }
+
+      #(
+        impl wtx::misc::Lease<#field_tys> for #name {
+          #[inline]
+          fn lease(&self) -> &#field_tys {
+            &self.#field_names
+          }
+        }
+
+        impl wtx::misc::LeaseMut<#field_tys> for #name {
+            #[inline]
+            fn lease_mut(&mut self) -> &mut #field_tys {
+              &mut self.#field_names
+            }
+          }
+      )*
+  };
+  Ok(proc_macro::TokenStream::from(expanded))
+}
diff --git a/wtx-macros/src/lib.rs b/wtx-macros/src/lib.rs
index 549d029f..444f6ddf 100644
--- a/wtx-macros/src/lib.rs
+++ b/wtx-macros/src/lib.rs
@@ -2,14 +2,10 @@
 
 #![expect(clippy::too_many_lines, reason = "Unimportant")]
 
-mod api_params;
-mod contained_attrs;
+mod client_api_framework;
 mod error;
-mod item_with_attr_span;
+mod http;
 mod misc;
-mod owned_or_ref;
-mod pkg;
-mod transport_group;
 
 use error::Error;
 
@@ -24,7 +20,16 @@ pub fn api_params(
   attrs: proc_macro::TokenStream,
   item: proc_macro::TokenStream,
 ) -> proc_macro::TokenStream {
-  match api_params::api_params(attrs, item) {
+  match client_api_framework::api_params::api_params(attrs, item) {
+    Err(err) => syn::Error::from(err).to_compile_error().into(),
+    Ok(elem) => elem,
+  }
+}
+
+/// Connection Auxiliary
+#[proc_macro_derive(ConnAux)]
+pub fn conn_aux(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
+  match http::conn_aux(item) {
     Err(err) => syn::Error::from(err).to_compile_error().into(),
     Ok(elem) => elem,
   }
@@ -56,7 +61,7 @@ pub fn pkg(
   attr: proc_macro::TokenStream,
   item: proc_macro::TokenStream,
 ) -> proc_macro::TokenStream {
-  match pkg::pkg(attr, item) {
+  match client_api_framework::pkg::pkg(attr, item) {
     Err(err) => syn::Error::from(err).to_compile_error().into(),
     Ok(elem) => elem,
   }
diff --git a/wtx-ui/src/http_client.rs b/wtx-ui/src/http_client.rs
index e31e9c62..051b927a 100644
--- a/wtx-ui/src/http_client.rs
+++ b/wtx-ui/src/http_client.rs
@@ -23,7 +23,7 @@ pub(crate) async fn http_client(http_client: HttpClient) {
     rrb
       .headers
       .push_from_iter(Header::from_name_and_value(
-        name.trim().as_bytes(),
+        name.trim(),
         values.split(',').map(|el| el.trim().as_bytes()),
       ))
       .unwrap();
diff --git a/wtx/Cargo.toml b/wtx/Cargo.toml
index f9816e56..e4f304b7 100644
--- a/wtx/Cargo.toml
+++ b/wtx/Cargo.toml
@@ -8,8 +8,9 @@ chrono = { default-features = false, optional = true, version = "0.4" }
 cl-aux = { default-features = false, optional = true, features = ["alloc"], version = "5.0" }
 crypto-common = { default-features = false, optional = true, version = "0.1" }
 digest = { default-features = false, features = ["mac"], optional = true, version = "0.10" }
+embassy-net = { default-features = false, features = ["tcp"], optional = true, version = "0.4" }
 embedded-io-async = { default-features = false, optional = true, version = "0.6" }
-embedded-tls = { default-features = false, optional = true, version = "0.17" }
+embedded-tls = { default-features = false, optional = true, git = "https://github.com/drogue-iot/embedded-tls" }
 fastrand = { default-features = false, optional = true, version = "2.0" }
 flate2 = { default-features = false, features = ["zlib-rs"], optional = true, version = "1.0" }
 foldhash = { default-features = false, optional = true, version = "0.1" }
@@ -129,6 +130,7 @@ x509-certificate = ["dep:x509-certificate"]
 
 _async-tests = ["tokio/macros", "tokio/net", "tokio/rt-multi-thread", "tokio/time"]
 _bench = []
+_hack = ["embassy-net?/medium-ip", "embassy-net?/proto-ipv4"]
 _integration-tests = ["serde_json?/raw_value"]
 _tracing-tree = ["tracing", "tracing-subscriber", "dep:tracing-tree"]
 
diff --git a/wtx/src/database/client/postgres/config.rs b/wtx/src/database/client/postgres/config.rs
index a2f393bd..61685cf2 100644
--- a/wtx/src/database/client/postgres/config.rs
+++ b/wtx/src/database/client/postgres/config.rs
@@ -1,6 +1,6 @@
 use crate::{
   database::client::postgres::PostgresError,
-  misc::{into_rslt, str_split1, FromRadix10, UriRef},
+  misc::{into_rslt, str_split1, str_split_once1, FromRadix10, UriRef},
 };
 use core::time::Duration;
 
@@ -29,8 +29,8 @@ impl<'data> Config<'data> {
       app_name: "",
       channel_binding: ChannelBinding::Prefer,
       connect_timeout: Duration::ZERO,
-      db: uri.relative_reference().get(1..).unwrap_or_default(),
-      host: uri.host(),
+      db: uri.path().get(1..).unwrap_or_default(),
+      host: uri.hostname(),
       keepalives: true,
       load_balance_hosts: LoadBalanceHosts::Disable,
       password: uri.password(),
@@ -39,9 +39,15 @@ impl<'data> Config<'data> {
       tcp_user_timeout: Duration::ZERO,
       user: uri.user(),
     };
-    for key_value in str_split1(uri.query_and_fragment(), b'&') {
-      let mut iter = str_split1(key_value, b':');
-      if let [Some(key), Some(value)] = [iter.next(), iter.next()] {
+    let mut pair_iter = str_split1(uri.query_and_fragment(), b'&');
+    if let Some(mut key_value) = pair_iter.next() {
+      key_value = key_value.get(1..).unwrap_or_default();
+      if let Some((key, value)) = str_split_once1(key_value, b'=') {
+        this.set_param(key, value)?;
+      }
+    }
+    for key_value in pair_iter {
+      if let Some((key, value)) = str_split_once1(key_value, b'=') {
         this.set_param(key, value)?;
       }
     }
@@ -111,3 +117,23 @@ pub(crate) enum TargetSessionAttrs {
   Any,
   ReadWrite,
 }
+
+#[cfg(test)]
+mod tests {
+  use crate::{
+    database::client::postgres::{config::ChannelBinding, Config},
+    misc::Uri,
+  };
+
+  #[test]
+  fn from_uri() {
+    let uri = Uri::new("postgres://ab:cd@ef:5432/gh?application_name=ij&channel_binding=disable");
+    let config = Config::from_uri(&uri).unwrap();
+    assert_eq!(config.app_name, "ij");
+    assert_eq!(config.channel_binding, ChannelBinding::Disable);
+    assert_eq!(config.db, "gh");
+    assert_eq!(config.host, "ef");
+    assert_eq!(config.password, "cd");
+    assert_eq!(config.user, "ab");
+  }
+}
diff --git a/wtx/src/database/client/postgres/executor.rs b/wtx/src/database/client/postgres/executor.rs
index e65d8ce1..8b314c6e 100644
--- a/wtx/src/database/client/postgres/executor.rs
+++ b/wtx/src/database/client/postgres/executor.rs
@@ -54,8 +54,8 @@ where
   pub async fn connect_encrypted<F, IS, RNG>(
     config: &Config<'_>,
     mut eb: EB,
-    mut initial_stream: IS,
     rng: &mut RNG,
+    mut stream: IS,
     cb: impl FnOnce(IS) -> F,
   ) -> crate::Result<Self>
   where
@@ -68,14 +68,14 @@ where
     {
       let mut fbw = FilledBufferWriter::from(&mut eb.lease_mut().nb);
       encrypted_conn(&mut fbw)?;
-      initial_stream.write_all(fbw._curr_bytes()).await?;
+      stream.write_all(fbw._curr_bytes()).await?;
     }
     let mut buf = [0];
-    let _ = initial_stream.read(&mut buf).await?;
+    let _ = stream.read(&mut buf).await?;
     if buf[0] != b'S' {
       return Err(PostgresError::ServerDoesNotSupportEncryption.into());
     }
-    let stream = cb(initial_stream).await?;
+    let stream = cb(stream).await?;
     let tls_server_end_point = stream.tls_server_end_point()?;
     Self::do_connect(config, eb, rng, stream, tls_server_end_point.as_ref().map(Lease::lease)).await
   }
diff --git a/wtx/src/database/client/postgres/executor/authentication.rs b/wtx/src/database/client/postgres/executor/authentication.rs
index 8ce9c7b4..178c3f1e 100644
--- a/wtx/src/database/client/postgres/executor/authentication.rs
+++ b/wtx/src/database/client/postgres/executor/authentication.rs
@@ -76,10 +76,10 @@ where
         let (method_bytes, method_header) = match (is_scram, is_scram_plus, config.channel_binding)
         {
           (false, false, _) => return Err(PostgresError::UnknownAuthenticationMethod.into()),
-          (true, false | true, ChannelBinding::Disable) | (true, false, ChannelBinding::Prefer) => {
+          (true, _, ChannelBinding::Disable) | (true, false, ChannelBinding::Prefer) => {
             (scram_sha_256!().as_slice(), b"n,,".as_slice())
           }
-          (false | true, true, ChannelBinding::Prefer | ChannelBinding::Require) => {
+          (_, true, ChannelBinding::Prefer | ChannelBinding::Require) => {
             (scram_sha_256_plus!().as_slice(), b"p=tls-server-end-point,,".as_slice())
           }
           (false, true, ChannelBinding::Disable) => {
diff --git a/wtx/src/error.rs b/wtx/src/error.rs
index 2617e5cf..496c28af 100644
--- a/wtx/src/error.rs
+++ b/wtx/src/error.rs
@@ -36,6 +36,8 @@ pub enum Error {
   DecodeError(base64::DecodeError),
   #[cfg(feature = "base64")]
   DecodeSliceError(base64::DecodeSliceError),
+  #[cfg(feature = "embassy-net")]
+  EmbassyNet(embassy_net::tcp::Error),
   #[cfg(feature = "base64")]
   EncodeSliceError(base64::EncodeSliceError),
   #[cfg(feature = "flate2")]
@@ -244,6 +246,14 @@ impl From<base64::DecodeSliceError> for Error {
   }
 }
 
+#[cfg(feature = "embassy-net")]
+impl From<embassy_net::tcp::Error> for Error {
+  #[inline]
+  fn from(from: embassy_net::tcp::Error) -> Self {
+    Self::EmbassyNet(from)
+  }
+}
+
 #[cfg(feature = "base64")]
 impl From<base64::EncodeSliceError> for Error {
   #[inline]
diff --git a/wtx/src/grpc/grpc_middleware.rs b/wtx/src/grpc/grpc_middleware.rs
index fb4394ad..0c3b2b02 100644
--- a/wtx/src/grpc/grpc_middleware.rs
+++ b/wtx/src/grpc/grpc_middleware.rs
@@ -38,7 +38,7 @@ where
       Header {
         is_sensitive: false,
         is_trailer: true,
-        name: b"grpc-status",
+        name: "grpc-status",
         value: [stream_aux.status_code_mut().number_as_str().as_bytes()].into_iter(),
       },
     ])?;
diff --git a/wtx/src/http/header_name.rs b/wtx/src/http/header_name.rs
index b36141b6..364855dc 100644
--- a/wtx/src/http/header_name.rs
+++ b/wtx/src/http/header_name.rs
@@ -40,17 +40,10 @@ macro_rules! create_statics {
       }
     }
 
-    impl From<KnownHeaderName> for HeaderNameStaticBytes {
+    impl From<KnownHeaderName> for HeaderName<&str> {
       #[inline]
       fn from(from: KnownHeaderName) -> Self {
-        HeaderNameStaticBytes::new(<&[u8]>::from(from))
-      }
-    }
-
-    impl From<KnownHeaderName> for HeaderNameStaticStr {
-      #[inline]
-      fn from(from: KnownHeaderName) -> Self {
-        HeaderNameStaticStr::new(<&str>::from(from))
+        Self(<&str>::from(from))
       }
     }
 
@@ -71,21 +64,23 @@ macro_rules! create_statics {
 
     impl<S> TryFrom<HeaderName<S>> for KnownHeaderName
     where
-      S: Lease<[u8]>
+      S: Lease<str>
     {
       type Error = HttpError;
 
       #[inline]
       fn try_from(from: HeaderName<S>) -> Result<Self, Self::Error> {
-        KnownHeaderName::try_from(from.bytes())
+        KnownHeaderName::try_from(from.str().as_bytes())
       }
     }
   };
 }
 
+use core::str;
+
 use crate::misc::Lease;
 
-const HTTP2P_TABLE: &[u8; 256] = &[
+const TABLE: &[u8; 256] = &[
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, b'!', b'"', b'#', b'$', b'%', b'&', b'\'', 0, 0, b'*', b'+', 0, b'-', b'.', 0, b'0', b'1',
   b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -100,57 +95,69 @@ const HTTP2P_TABLE: &[u8; 256] = &[
 
 use crate::http::HttpError;
 
-/// [`HeaderName`] composed by static bytes.
-pub type HeaderNameStaticBytes = HeaderName<&'static [u8]>;
-/// [`HeaderName`] composed by a static string.
-pub type HeaderNameStaticStr = HeaderName<&'static str>;
-
 /// HTTP header name
-#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub struct HeaderName<S>(S);
 
 impl<S> HeaderName<S>
 where
-  S: Lease<[u8]>,
+  S: Lease<str>,
 {
-  /// HTTP/2 Plus
-  ///
-  /// Expects a valid HTTP/2 or HTTP/3 content.
+  /// New generic instance that doesn't verify `content`.
   #[inline]
-  pub fn http2p(content: S) -> Result<Self, HttpError> {
-    _iter4!(content.lease(), {}, |byte| {
-      if let Some(elem) = HTTP2P_TABLE.get(usize::from(*byte)).copied() {
-        if elem == 0 {
-          return Err(HttpError::InvalidHttp2pContent);
-        }
-      }
-    });
-    Ok(Self(content))
+  pub const fn new_unchecked(content: S) -> Self {
+    Self(content)
   }
 
-  /// Instance from a generic type content.
+  /// Generic type content.
   #[inline]
-  pub const fn new(content: S) -> Self {
-    Self(content)
+  pub const fn content(&self) -> &S {
+    &self.0
   }
 
-  /// Generic type content in bytes form
+  /// Generic type content in string form
   #[inline]
-  pub fn bytes(&self) -> &[u8] {
+  pub fn str(&self) -> &str {
     self.0.lease()
   }
 
-  /// Generic type content.
   #[inline]
-  pub const fn content(&self) -> &S {
-    &self.0
+  const fn check(content: &[u8]) -> Result<&str, HttpError> {
+    let mut idx: usize = 0;
+    loop {
+      if idx >= content.len() {
+        break;
+      }
+      #[expect(clippy::as_conversions, reason = "Lack of const traits")]
+      #[expect(
+        clippy::indexing_slicing,
+        reason = "An array of 256 elements will never panic with a 0..255 index"
+      )]
+      if TABLE[content[idx] as usize] == 0 {
+        return Err(HttpError::InvalidHttp2pContent);
+      }
+      idx = idx.wrapping_add(1);
+    }
+    // SAFETY: `TABLE` is a subset of ASCII
+    unsafe { Ok(str::from_utf8_unchecked(content)) }
+  }
+}
+
+impl<'this> HeaderName<&'this str> {
+  /// New instance from a set of bytes
+  #[inline]
+  pub const fn from_bytes(content: &'this [u8]) -> Result<Self, HttpError> {
+    match Self::check(content) {
+      Ok(elem) => Ok(HeaderName(elem)),
+      Err(err) => Err(err),
+    }
   }
 }
 
 impl<'hn> From<HeaderName<&'hn str>> for HeaderName<&'hn [u8]> {
   #[inline]
   fn from(from: HeaderName<&'hn str>) -> Self {
-    Self::new(from.0.as_bytes())
+    Self(from.0.as_bytes())
   }
 }
 
@@ -230,20 +237,3 @@ create_statics! {
   Warning = "warning";
   WwwAuthenticate = "www-authenticate";
 }
-
-#[cfg(all(feature = "_bench", test))]
-mod bench {
-  use crate::{http::HeaderName, misc::Vector};
-
-  #[bench]
-  fn http2p(b: &mut test::Bencher) {
-    const LEN: usize = 32;
-    let mut data: Vector<u8> = Vector::with_capacity(LEN).unwrap();
-    for idx in 0..LEN {
-      data.push(idx.clamp(106, 122).try_into().unwrap()).unwrap();
-    }
-    b.iter(|| {
-      let _ = HeaderName::http2p(&data).unwrap();
-    });
-  }
-}
diff --git a/wtx/src/http/headers.rs b/wtx/src/http/headers.rs
index 71fb3c20..d95b266d 100644
--- a/wtx/src/http/headers.rs
+++ b/wtx/src/http/headers.rs
@@ -1,5 +1,5 @@
-use crate::misc::{BytesFmt, Lease, LeaseMut, Vector};
-use core::{fmt::Arguments, ptr};
+use crate::misc::{Lease, LeaseMut, Vector};
+use core::{fmt::Arguments, ptr, str};
 
 /// Determines how trailers are placed in the headers
 #[derive(Clone, Copy, Debug)]
@@ -58,7 +58,7 @@ impl Headers {
   /// ```rust
   /// use wtx::http::{Header, Headers};
   /// let mut headers = Headers::new();
-  /// headers.push_from_iter(Header::from_name_and_value(b"name", ["value".as_bytes()])).unwrap();
+  /// headers.push_from_iter(Header::from_name_and_value("name", ["value".as_bytes()])).unwrap();
   /// assert_eq!(headers.bytes_len(), 9);
   /// assert_eq!(headers.headers_len(), 1);
   /// headers.clear();
@@ -82,7 +82,7 @@ impl Headers {
   /// Returns the header that is referenced by `name`, if any.
   #[inline]
   pub fn get_by_name(&self, name: &[u8]) -> Option<Header<'_, &[u8]>> {
-    self.iter().find(|el| el.name == name)
+    self.iter().find(|el| el.name.as_bytes() == name)
   }
 
   /// Returns all first optional headers that are referenced by `names`.
@@ -90,7 +90,7 @@ impl Headers {
   /// ```rust
   /// use wtx::http::{Header, Headers};
   /// let mut headers = Headers::new();
-  /// headers.push_from_iter(Header::from_name_and_value(b"name0", [])).unwrap();
+  /// headers.push_from_iter(Header::from_name_and_value("name0", [])).unwrap();
   /// let array = headers.get_many_by_name(["name0".as_bytes(), "name1".as_bytes()]);
   /// assert!(array[0].is_some());
   /// assert!(array[1].is_none());
@@ -103,7 +103,7 @@ impl Headers {
     let mut rslt = [None; N];
     for header in self.iter() {
       for (name, opt) in names.into_iter().zip(&mut rslt) {
-        if name == header.name {
+        if name == header.name.as_bytes() {
           *opt = Some(header);
           break;
         }
@@ -129,7 +129,7 @@ impl Headers {
   /// ```rust
   /// use wtx::http::{Header, Headers};
   /// let mut headers = Headers::new();
-  /// headers.push_from_iter(Header::from_name_and_value(b"name", ["value".as_bytes()])).unwrap();
+  /// headers.push_from_iter(Header::from_name_and_value("name", ["value".as_bytes()])).unwrap();
   /// assert_eq!(headers.bytes_len(), 9);
   /// assert_eq!(headers.headers_len(), 1);
   /// let _ = headers.pop();
@@ -154,8 +154,8 @@ impl Headers {
   /// ```rust
   /// use wtx::http::{Header, Headers};
   /// let mut headers = Headers::new();
-  /// headers.push_from_fmt(Header::from_name_and_value(b"name", format_args!("{}", 1))).unwrap();
-  /// assert_eq!(headers.get_by_idx(0).unwrap(), Header::from_name_and_value(b"name", "1".as_bytes()));
+  /// headers.push_from_fmt(Header::from_name_and_value("name", format_args!("{}", 1))).unwrap();
+  /// assert_eq!(headers.get_by_idx(0).unwrap(), Header::from_name_and_value("name", "1".as_bytes()));
   /// ```
   #[inline(always)]
   pub fn push_from_fmt(&mut self, header: Header<'_, Arguments<'_>>) -> crate::Result<()> {
@@ -163,12 +163,12 @@ impl Headers {
     #[cfg(feature = "std")]
     {
       use std::io::Write;
-      self.bytes.write_fmt(format_args!("{}{}", BytesFmt(header.name), header.value))?;
+      self.bytes.write_fmt(format_args!("{}{}", header.name, header.value))?;
     }
     #[cfg(not(feature = "std"))]
     {
       use core::fmt::Write;
-      self.bytes.write_fmt(format_args!("{}{}", BytesFmt(header.name), header.value))?;
+      self.bytes.write_fmt(format_args!("{}{}", header.name, header.value))?;
     }
     let prev_len = self.headers_parts.len();
     self.headers_parts.push(HeaderParts {
@@ -188,8 +188,8 @@ impl Headers {
   /// ```rust
   /// use wtx::http::{Header, Headers};
   /// let mut headers = Headers::new();
-  /// headers.push_from_iter(Header::from_name_and_value(b"name", ["value0".as_bytes(), "_value1".as_bytes()])).unwrap();
-  /// assert_eq!(headers.get_by_idx(0).unwrap(), Header::from_name_and_value(b"name", "value0_value1".as_bytes()));
+  /// headers.push_from_iter(Header::from_name_and_value("name", ["value0".as_bytes(), "_value1".as_bytes()])).unwrap();
+  /// assert_eq!(headers.get_by_idx(0).unwrap(), Header::from_name_and_value("name", "value0_value1".as_bytes()));
   /// ```
   #[inline(always)]
   pub fn push_from_iter<'bytes, V>(&mut self, header: Header<'bytes, V>) -> crate::Result<()>
@@ -214,7 +214,7 @@ impl Headers {
     let header_begin = self.bytes.len();
     let ptr = self.bytes.as_ptr_mut();
     let mut header_end = header_begin;
-    copy(&mut header_end, ptr, header.name);
+    copy(&mut header_end, ptr, header.name.as_bytes());
     let header_name_end = header_end;
     for value in iter {
       copy(&mut header_end, ptr, value);
@@ -274,7 +274,7 @@ impl Headers {
   }
 
   #[inline]
-  fn header_len<'bytes>(header_name: &[u8], iter: impl Iterator<Item = &'bytes [u8]>) -> usize {
+  fn header_len<'bytes>(header_name: &str, iter: impl Iterator<Item = &'bytes [u8]>) -> usize {
     let mut header_len = header_name.len();
     for elem in iter {
       header_len = header_len.wrapping_add(elem.len());
@@ -311,7 +311,11 @@ impl Headers {
     Header {
       is_sensitive,
       is_trailer,
-      name: bytes.get(header_begin..header_name_end).unwrap_or_default(),
+      name: {
+        let str = bytes.get(header_begin..header_name_end).unwrap_or_default();
+        // SAFETY: Input methods only accept UTF-8 data
+        unsafe { str::from_utf8_unchecked(str) }
+      },
       value: bytes.get(header_name_end..header_end).unwrap_or_default(),
     }
   }
@@ -350,7 +354,7 @@ pub struct Header<'any, V> {
   /// The applicability and semantics depends on the HTTP version.
   pub is_trailer: bool,
   /// Header name
-  pub name: &'any [u8],
+  pub name: &'any str,
   /// Header value
   pub value: V,
 }
@@ -358,7 +362,7 @@ pub struct Header<'any, V> {
 impl<'any, V> Header<'any, V> {
   /// Sets `is_sensitive` and `is_trailer` to `false`.
   #[inline]
-  pub fn from_name_and_value(name: &'any [u8], value: V) -> Self {
+  pub fn from_name_and_value(name: &'any str, value: V) -> Self {
     Self { is_sensitive: false, is_trailer: false, name, value }
   }
 }
diff --git a/wtx/src/http/server_framework/methods.rs b/wtx/src/http/server_framework/methods.rs
index dbfcb1a3..63445f3f 100644
--- a/wtx/src/http/server_framework/methods.rs
+++ b/wtx/src/http/server_framework/methods.rs
@@ -10,7 +10,6 @@ fn check_method<E>(expected: Method, received: Method) -> Result<(), E>
 where
   E: From<crate::Error>,
 {
-  std::dbg!(received);
   if expected != received {
     return Err(E::from(crate::Error::from(HttpError::UnexpectedHttpMethod { expected })));
   }
diff --git a/wtx/src/http/server_framework/server_framework_builder.rs b/wtx/src/http/server_framework/server_framework_builder.rs
index 8bc2ce30..bac42e15 100644
--- a/wtx/src/http/server_framework/server_framework_builder.rs
+++ b/wtx/src/http/server_framework/server_framework_builder.rs
@@ -79,7 +79,7 @@ impl<CA, E, EN, M, S> ServerFrameworkBuilder<CA, E, EN, M, S, ()>
 where
   CA: ConnAux,
 {
-  /// Sets the initializing strut for `CAA` and sets the request auxiliary to `()`.
+  /// Sets the initializing strut for `CA` and sets the request auxiliary to `()`.
   #[inline]
   pub fn with_conn_aux<CAC>(
     self,
diff --git a/wtx/src/http/server_framework/tokio.rs b/wtx/src/http/server_framework/tokio.rs
index bad53771..5d021c7b 100644
--- a/wtx/src/http/server_framework/tokio.rs
+++ b/wtx/src/http/server_framework/tokio.rs
@@ -44,7 +44,7 @@ where
     host: &str,
     rng: RNG,
     err_cb: impl Clone + Fn(E) + Send + 'static,
-    operation_mode: impl Clone + Fn(Request<&mut ReqResBuffer>) -> Result<(), E> + Send + Sync + 'static,
+    headers_cb: impl Clone + Fn(Request<&mut ReqResBuffer>) -> Result<(), E> + Send + Sync + 'static,
   ) -> crate::Result<()>
   where
     RNG: Clone + Rng + Send + 'static,
@@ -58,7 +58,7 @@ where
       Self::tokio_manual,
       move |_, _, req, sa| {
         let rslt = Self::_route_params(req.rrd.uri.path(), &sa.1)?;
-        operation_mode(req)?;
+        headers_cb(req)?;
         Ok(rslt)
       },
       move || Ok(((_sa_cb.clone(), Arc::clone(&_router)), ReqResBuffer::empty())),
@@ -116,7 +116,7 @@ where
     host: &str,
     rng: RNG,
     err_cb: impl Clone + Fn(E) + Send + 'static,
-    operation_mode: impl Clone + Fn(Request<&mut ReqResBuffer>) -> Result<(), E> + Send + Sync + 'static,
+    headers_cb: impl Clone + Fn(Request<&mut ReqResBuffer>) -> Result<(), E> + Send + Sync + 'static,
   ) -> crate::Result<()>
   where
     RNG: Clone + Rng + Send + 'static,
@@ -130,7 +130,7 @@ where
       Self::tokio_rustls_manual,
       move |_, _, req, sa| {
         let rslt = Self::_route_params(req.rrd.uri.path(), &sa.1)?;
-        operation_mode(req)?;
+        headers_cb(req)?;
         Ok(rslt)
       },
       move || Ok(((_sa_cb.clone(), Arc::clone(&_router)), ReqResBuffer::empty())),
diff --git a/wtx/src/http/session.rs b/wtx/src/http/session.rs
index 5985c2be..cbe87593 100644
--- a/wtx/src/http/session.rs
+++ b/wtx/src/http/session.rs
@@ -1,49 +1,18 @@
-mod session_builder;
 mod session_decoder;
 mod session_enforcer;
 mod session_error;
 mod session_manager;
+mod session_manager_builder;
 mod session_state;
 mod session_store;
 
-use crate::http::server_framework::ConnAux;
-pub use session_builder::SessionBuilder;
 pub use session_decoder::SessionDecoder;
 pub use session_enforcer::SessionEnforcer;
 pub use session_error::SessionError;
-pub use session_manager::{SessionManager, SessionManagerInner};
+pub use session_manager::{SessionManager, SessionManagerInner, SessionManagerTokio};
+pub use session_manager_builder::SessionManagerBuilder;
 pub use session_state::SessionState;
 pub use session_store::SessionStore;
 
 type SessionId = [u8; 16];
 type SessionKey = [u8; 32];
-/// [`Session`] backed by `tokio`
-#[cfg(feature = "tokio")]
-pub type SessionTokio<CS, E, S> =
-  Session<crate::misc::Arc<tokio::sync::Mutex<SessionManagerInner<CS, E>>>, S>;
-
-/// Allows the management of state across requests within a connection.
-#[derive(Clone, Debug)]
-pub struct Session<I, S> {
-  /// Manager
-  pub manager: SessionManager<I>,
-  /// Store
-  pub store: S,
-}
-
-impl<I, S> Session<I, S> {
-  /// Allows the specification of custom parameters.
-  #[inline]
-  pub fn builder(store: S) -> SessionBuilder<S> {
-    SessionBuilder::new(store)
-  }
-}
-
-impl<I, S> ConnAux for Session<I, S> {
-  type Init = Self;
-
-  #[inline]
-  fn conn_aux(init: Self::Init) -> crate::Result<Self> {
-    Ok(init)
-  }
-}
diff --git a/wtx/src/http/session/session_decoder.rs b/wtx/src/http/session/session_decoder.rs
index 1d23f4b7..537a02a6 100644
--- a/wtx/src/http/session/session_decoder.rs
+++ b/wtx/src/http/session/session_decoder.rs
@@ -2,10 +2,10 @@ use crate::{
   http::{
     cookie::{decrypt, CookieBytes},
     server_framework::Middleware,
-    KnownHeaderName, ReqResBuffer, Request, Response, Session, SessionError, SessionManagerInner,
-    SessionState, SessionStore, StatusCode,
+    KnownHeaderName, ReqResBuffer, Request, Response, SessionError, SessionManager,
+    SessionManagerInner, SessionState, SessionStore, StatusCode,
   },
-  misc::{GenericTime, LeaseMut, Lock},
+  misc::{GenericTime, Lease, LeaseMut, Lock},
   pool::{Pool, ResourceManager},
 };
 use chrono::DateTime;
@@ -18,19 +18,21 @@ use serde::de::DeserializeOwned;
 /// is a NO-OP.
 #[derive(Debug)]
 pub struct SessionDecoder<I, S> {
-  session: Session<I, S>,
+  session_manager: SessionManager<I>,
+  session_store: S,
 }
 
 impl<I, S> SessionDecoder<I, S> {
   /// New instance
   #[inline]
-  pub fn new(session: Session<I, S>) -> Self {
-    Self { session }
+  pub fn new(session_manager: SessionManager<I>, session_store: S) -> Self {
+    Self { session_manager, session_store }
   }
 }
 
 impl<CA, CS, E, I, RM, S, SA> Middleware<CA, E, SA> for SessionDecoder<I, S>
 where
+  CA: LeaseMut<Option<SessionState<CS>>>,
   CS: DeserializeOwned + PartialEq,
   E: From<crate::Error>,
   I: Lock<Resource = SessionManagerInner<CS, E>>,
@@ -49,26 +51,26 @@ where
   #[inline]
   async fn req(
     &self,
-    _: &mut CA,
+    ca: &mut CA,
     _: &mut Self::Aux,
     req: &mut Request<ReqResBuffer>,
     _: &mut SA,
   ) -> Result<ControlFlow<StatusCode, ()>, E> {
-    let mut guard = self.session.manager.inner.lock().await;
-    let SessionManagerInner { cookie_def, key, state, .. } = &mut *guard;
-    if let Some(elem) = state {
+    let mut session_guard = self.session_manager.inner.lock().await;
+    let SessionManagerInner { cookie_def, key, .. } = &mut *session_guard;
+    if let Some(elem) = ca.lease() {
       if let Some(expire) = &elem.expire {
         let millis = i64::try_from(GenericTime::timestamp()?.as_millis()).unwrap_or_default();
         let date_time = DateTime::from_timestamp_millis(millis).unwrap_or_default();
         if expire >= &date_time {
-          let _rslt = self.session.store.get(&(), &()).await?.lease_mut().delete(&elem.id).await;
+          let _rslt = self.session_store.get(&(), &()).await?.lease_mut().delete(&elem.id).await;
           return Err(crate::Error::from(SessionError::ExpiredSession).into());
         }
       }
       return Ok(ControlFlow::Continue(()));
     }
     for header in req.rrd.headers.iter() {
-      if header.name != <&[u8]>::from(KnownHeaderName::Cookie) {
+      if header.name != <&str>::from(KnownHeaderName::Cookie) {
         continue;
       }
       let cookie = CookieBytes::parse(header.value, &mut cookie_def.value)?;
@@ -88,16 +90,19 @@ where
       let rslt_des = serde_json::from_slice(&cookie_def.value).map_err(Into::into);
       cookie_def.value.clear();
       let state_des: SessionState<CS> = rslt_des?;
-      let state_db_opt =
-        self.session.store.get(&(), &()).await?.lease_mut().read(&state_des.id).await?;
+      let state_db_opt = {
+        let mut guard = self.session_store.get(&(), &()).await?;
+        guard.lease_mut().read(&state_des.id).await?
+      };
       let Some(state_db) = state_db_opt else {
         return Err(crate::Error::from(SessionError::MissingStoredSession).into());
       };
       if state_db != state_des {
-        self.session.store.get(&(), &()).await?.lease_mut().delete(&state_des.id).await?;
+        self.session_store.get(&(), &()).await?.lease_mut().delete(&state_des.id).await?;
         return Err(crate::Error::from(SessionError::InvalidStoredSession).into());
       }
-      *state = Some(state_des);
+      let session_state: &mut Option<_> = ca.lease_mut();
+      *session_state = Some(state_des);
       break;
     }
     Ok(ControlFlow::Continue(()))
diff --git a/wtx/src/http/session/session_enforcer.rs b/wtx/src/http/session/session_enforcer.rs
index 660fe27e..9d6dd25f 100644
--- a/wtx/src/http/session/session_enforcer.rs
+++ b/wtx/src/http/session/session_enforcer.rs
@@ -1,33 +1,31 @@
 use crate::{
   http::{
-    server_framework::Middleware, ReqResBuffer, Request, Response, Session, SessionError,
-    SessionManagerInner, StatusCode,
+    server_framework::Middleware, ReqResBuffer, Request, Response, SessionError, SessionState,
+    StatusCode,
   },
-  misc::Lock,
+  misc::LeaseMut,
 };
-use core::ops::ControlFlow;
+use core::{marker::PhantomData, ops::ControlFlow};
 
 /// Enforces stored session in all requests.
-///
-///
 #[derive(Debug)]
-pub struct SessionEnforcer<I, S, const N: usize> {
+pub struct SessionEnforcer<CS, const N: usize> {
   denied: [&'static str; N],
-  session: Session<I, S>,
+  phantom: PhantomData<CS>,
 }
 
-impl<I, S, const N: usize> SessionEnforcer<I, S, N> {
+impl<CS, const N: usize> SessionEnforcer<CS, N> {
   /// Creates a new instance with paths that are not taken into consideration.
   #[inline]
-  pub fn new(denied: [&'static str; N], session: Session<I, S>) -> Self {
-    Self { denied, session }
+  pub fn new(denied: [&'static str; N]) -> Self {
+    Self { denied, phantom: PhantomData }
   }
 }
 
-impl<CA, CS, E, I, S, SA, const N: usize> Middleware<CA, E, SA> for SessionEnforcer<I, S, N>
+impl<CA, CS, E, SA, const N: usize> Middleware<CA, E, SA> for SessionEnforcer<CS, N>
 where
+  CA: LeaseMut<Option<SessionState<CS>>>,
   E: From<crate::Error>,
-  I: Lock<Resource = SessionManagerInner<CS, E>>,
 {
   type Aux = ();
 
@@ -39,7 +37,7 @@ where
   #[inline]
   async fn req(
     &self,
-    _: &mut CA,
+    ca: &mut CA,
     _: &mut Self::Aux,
     req: &mut Request<ReqResBuffer>,
     _: &mut SA,
@@ -48,7 +46,7 @@ where
     if self.denied.iter().all(|elem| *elem != path) {
       return Ok(ControlFlow::Continue(()));
     }
-    if self.session.manager.inner.lock().await.state().is_none() {
+    if ca.lease_mut().is_none() {
       return Err(crate::Error::from(SessionError::RequiredSessionInPath).into());
     }
     Ok(ControlFlow::Continue(()))
diff --git a/wtx/src/http/session/session_manager.rs b/wtx/src/http/session/session_manager.rs
index 398f2abe..990ce179 100644
--- a/wtx/src/http/session/session_manager.rs
+++ b/wtx/src/http/session/session_manager.rs
@@ -2,7 +2,8 @@ use crate::{
   http::{
     cookie::{encrypt, CookieGeneric},
     session::SessionKey,
-    Header, KnownHeaderName, ReqResBuffer, ReqResDataMut, SessionState, SessionStore,
+    Header, KnownHeaderName, ReqResBuffer, ReqResDataMut, SessionManagerBuilder, SessionState,
+    SessionStore,
   },
   misc::{GenericTime, Lease, LeaseMut, Lock, Rng, Vector},
 };
@@ -10,6 +11,11 @@ use chrono::DateTime;
 use core::marker::PhantomData;
 use serde::Serialize;
 
+/// [`Session`] backed by `tokio`
+#[cfg(feature = "tokio")]
+pub type SessionManagerTokio<CS, E> =
+  SessionManager<crate::misc::Arc<tokio::sync::Mutex<SessionManagerInner<CS, E>>>>;
+
 /// Manages sessions
 #[derive(Clone, Debug)]
 pub struct SessionManager<I> {
@@ -22,28 +28,37 @@ where
   E: From<crate::Error>,
   I: Lock<Resource = SessionManagerInner<CS, E>>,
 {
+  /// Allows the specification of custom parameters.
+  #[inline]
+  pub fn builder() -> SessionManagerBuilder {
+    SessionManagerBuilder::new()
+  }
+
   /// Removes the session from the store and also modifies headers.
   #[inline]
   pub async fn delete_session_cookie<RRD, S>(
     &mut self,
     rrd: &mut RRD,
+    state: &mut Option<SessionState<CS>>,
     store: &mut S,
   ) -> Result<(), E>
   where
     RRD: ReqResDataMut,
     S: SessionStore<CS, E>,
   {
-    let SessionManagerInner { cookie_def, phantom: _, key: _, state } =
-      &mut *self.inner.lock().await;
+    let SessionManagerInner { cookie_def, phantom: _, key: _ } = &mut *self.inner.lock().await;
     if let Some(elem) = state.take() {
       store.delete(&elem.id).await?;
     }
+    let prev_expire = cookie_def.expire;
     cookie_def.expire = Some(DateTime::from_timestamp_nanos(0));
     cookie_def.value.clear();
-    rrd.headers_mut().push_from_fmt(Header::from_name_and_value(
+    let rslt = rrd.headers_mut().push_from_fmt(Header::from_name_and_value(
       KnownHeaderName::SetCookie.into(),
       format_args!("{cookie_def}"),
-    ))?;
+    ));
+    cookie_def.expire = prev_expire;
+    rslt?;
     Ok(())
   }
 
@@ -64,7 +79,7 @@ where
     RRD: LeaseMut<ReqResBuffer>,
     S: SessionStore<CS, E>,
   {
-    let SessionManagerInner { cookie_def, phantom: _, key, state } = &mut *self.inner.lock().await;
+    let SessionManagerInner { cookie_def, phantom: _, key } = &mut *self.inner.lock().await;
     cookie_def.value.clear();
     let id = GenericTime::timestamp().map_err(Into::into)?.as_nanos().to_be_bytes();
     let local_state = if let Some(elem) = cookie_def.expire {
@@ -76,7 +91,6 @@ where
     };
     let idx = rrd.lease().body.len();
     serde_json::to_writer(&mut rrd.lease_mut().body, &local_state).map_err(Into::into)?;
-    *state = Some(local_state);
     let rslt = encrypt(
       &mut cookie_def.value,
       key,
@@ -98,14 +112,5 @@ where
 pub struct SessionManagerInner<CS, E> {
   pub(crate) cookie_def: CookieGeneric<&'static [u8], Vector<u8>>,
   pub(crate) key: SessionKey,
-  pub(crate) phantom: PhantomData<E>,
-  pub(crate) state: Option<SessionState<CS>>,
-}
-
-impl<CS, E> SessionManagerInner<CS, E> {
-  /// State saved in the store or in the current session.
-  #[inline]
-  pub fn state(&self) -> &Option<SessionState<CS>> {
-    &self.state
-  }
+  pub(crate) phantom: PhantomData<(CS, E)>,
 }
diff --git a/wtx/src/http/session/session_builder.rs b/wtx/src/http/session/session_manager_builder.rs
similarity index 85%
rename from wtx/src/http/session/session_builder.rs
rename to wtx/src/http/session/session_manager_builder.rs
index 95088506..bad46428 100644
--- a/wtx/src/http/session/session_builder.rs
+++ b/wtx/src/http/session/session_manager_builder.rs
@@ -2,7 +2,7 @@ use crate::{
   http::{
     cookie::{CookieGeneric, SameSite},
     session::{SessionKey, SessionManagerInner},
-    Session, SessionManager, SessionStore,
+    SessionManager, SessionStore,
   },
   misc::{sleep, Lock, Rng, Vector},
 };
@@ -11,15 +11,14 @@ use core::{future::Future, marker::PhantomData, time::Duration};
 
 /// Default and optional parameters for the construction of a [`Session`].
 #[derive(Debug)]
-pub struct SessionBuilder<SS> {
+pub struct SessionManagerBuilder {
   pub(crate) cookie_def: CookieGeneric<&'static [u8], Vector<u8>>,
   pub(crate) inspection_interval: Duration,
-  pub(crate) store: SS,
 }
 
-impl<SS> SessionBuilder<SS> {
+impl SessionManagerBuilder {
   #[inline]
-  pub(crate) const fn new(store: SS) -> Self {
+  pub(crate) const fn new() -> Self {
     Self {
       cookie_def: CookieGeneric {
         domain: &[],
@@ -33,7 +32,6 @@ impl<SS> SessionBuilder<SS> {
         value: Vector::new(),
       },
       inspection_interval: Duration::from_secs(60 * 30),
-      store,
     }
   }
 
@@ -46,10 +44,11 @@ impl<SS> SessionBuilder<SS> {
   /// If the backing store already has a system that automatically removes outdated sessions like
   /// SQL triggers, then the [`Future`] can be ignored.
   #[inline]
-  pub fn build_generating_key<CS, E, I, RNG>(
+  pub fn build_generating_key<CS, E, I, RNG, SS>(
     self,
     rng: &mut RNG,
-  ) -> (impl Future<Output = Result<(), E>>, Session<I, SS>)
+    session_store: &mut SS,
+  ) -> (impl Future<Output = Result<(), E>>, SessionManager<I>)
   where
     E: From<crate::Error>,
     I: Lock<Resource = SessionManagerInner<CS, E>>,
@@ -58,7 +57,7 @@ impl<SS> SessionBuilder<SS> {
   {
     let mut key = [0; 32];
     rng.fill_slice(&mut key);
-    Self::build_with_key(self, key)
+    Self::build_with_key(self, key, session_store)
   }
 
   /// Creates a new [`Session`] with the provided `key`.
@@ -69,17 +68,18 @@ impl<SS> SessionBuilder<SS> {
   /// If the backing store already has a system that automatically removes outdated sessions like
   /// SQL triggers, then the [`Future`] can be ignored.
   #[inline]
-  pub fn build_with_key<CS, E, I>(
+  pub fn build_with_key<CS, E, I, SS>(
     self,
     key: SessionKey,
-  ) -> (impl Future<Output = Result<(), E>>, Session<I, SS>)
+    session_store: &mut SS,
+  ) -> (impl Future<Output = Result<(), E>>, SessionManager<I>)
   where
     E: From<crate::Error>,
     I: Lock<Resource = SessionManagerInner<CS, E>>,
     SS: Clone + SessionStore<CS, E>,
   {
-    let Self { cookie_def, inspection_interval, store } = self;
-    let mut local_store = store.clone();
+    let Self { cookie_def, inspection_interval } = self;
+    let mut local_store = session_store.clone();
     (
       async move {
         loop {
@@ -87,11 +87,8 @@ impl<SS> SessionBuilder<SS> {
           sleep(inspection_interval).await.map_err(Into::into)?;
         }
       },
-      Session {
-        manager: SessionManager {
-          inner: I::new(SessionManagerInner { cookie_def, phantom: PhantomData, key, state: None }),
-        },
-        store,
+      SessionManager {
+        inner: I::new(SessionManagerInner { cookie_def, phantom: PhantomData, key }),
       },
     )
   }
diff --git a/wtx/src/http/session/session_state.rs b/wtx/src/http/session/session_state.rs
index 4e13d8e7..bd0f6ad3 100644
--- a/wtx/src/http/session/session_state.rs
+++ b/wtx/src/http/session/session_state.rs
@@ -2,7 +2,7 @@ use crate::http::session::SessionId;
 use chrono::{DateTime, Utc};
 
 /// Data that is saved in the corresponding store.
-#[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Copy, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
 pub struct SessionState<CS> {
   /// Custom state
   pub custom_state: CS,
diff --git a/wtx/src/http2/headers_frame.rs b/wtx/src/http2/headers_frame.rs
index e51c992d..378f023a 100644
--- a/wtx/src/http2/headers_frame.rs
+++ b/wtx/src/http2/headers_frame.rs
@@ -1,5 +1,5 @@
 use crate::{
-  http::{Header, HeaderName, KnownHeaderName, Method, ReqResBuffer},
+  http::{Header, KnownHeaderName, Method, ReqResBuffer},
   http2::{
     common_flags::CommonFlags,
     frame_init::{FrameInit, FrameInitTy},
@@ -100,11 +100,11 @@ impl<'uri> HeadersFrame<'uri> {
             &mut is_malformed,
             &mut is_over_size,
             max_headers_len,
-            name,
+            name.str(),
             value,
           );
         }
-        HpackHeaderBasic::Field => match KnownHeaderName::try_from(name) {
+        HpackHeaderBasic::Field => match KnownHeaderName::try_from(name.str().as_bytes()) {
           Ok(
             KnownHeaderName::Connection
             | KnownHeaderName::KeepAlive
@@ -118,24 +118,20 @@ impl<'uri> HeadersFrame<'uri> {
             is_malformed = true;
           }
           _ => {
-            let header_name = match HeaderName::http2p(name) {
-              Ok(header_name) => header_name,
-              Err(_err) => {
-                return Err(protocol_err(Http2Error::InvalidHeaderData));
-              }
-            };
             has_fields = true;
-            let len = decoded_header_size(name.len(), value.len());
+            let len = decoded_header_size(name.str().len(), value.len());
             expanded_headers_len = expanded_headers_len.wrapping_add(len);
             is_over_size = expanded_headers_len >= max_headers_len;
             if !is_over_size {
-              if let Ok(KnownHeaderName::ContentLength) = KnownHeaderName::try_from(header_name) {
+              if let Ok(KnownHeaderName::ContentLength) =
+                KnownHeaderName::try_from(name.str().as_bytes())
+              {
                 content_length = Some(usize::from_radix_10(value)?);
               }
               rrb_headers.push_from_iter(Header {
                 is_sensitive: false,
                 is_trailer: IS_TRAILER,
-                name,
+                name: name.str(),
                 value: [value],
               })?;
             }
@@ -149,7 +145,7 @@ impl<'uri> HeadersFrame<'uri> {
             &mut is_over_size,
             method.is_some(),
             max_headers_len,
-            name,
+            name.str(),
             value,
           ) {
             method = Some(local_method);
@@ -163,7 +159,7 @@ impl<'uri> HeadersFrame<'uri> {
             &mut is_malformed,
             &mut is_over_size,
             max_headers_len,
-            name,
+            name.str(),
             value,
           );
         }
@@ -175,7 +171,7 @@ impl<'uri> HeadersFrame<'uri> {
             &mut is_over_size,
             protocol.is_some(),
             max_headers_len,
-            name,
+            name.str(),
             value,
           ) {
             protocol = Some(local_protocol);
@@ -189,7 +185,7 @@ impl<'uri> HeadersFrame<'uri> {
             &mut is_malformed,
             &mut is_over_size,
             max_headers_len,
-            name,
+            name.str(),
             value,
           );
         }
@@ -201,7 +197,7 @@ impl<'uri> HeadersFrame<'uri> {
             &mut is_over_size,
             status.is_some(),
             max_headers_len,
-            name,
+            name.str(),
             value,
           ) {
             status = Some(local_status);
@@ -282,7 +278,7 @@ fn push_enum(
   is_over_size: &mut bool,
   is_some: bool,
   max_headers_len: usize,
-  name: &[u8],
+  name: &str,
   value: &[u8],
 ) -> bool {
   if *has_fields || is_some {
@@ -304,7 +300,7 @@ fn push_uri<const N: usize>(
   is_malformed: &mut bool,
   is_over_size: &mut bool,
   max_headers_len: usize,
-  name: &[u8],
+  name: &str,
   value: &[u8],
 ) {
   if *has_fields || !buffer.is_empty() {
diff --git a/wtx/src/http2/hpack_decoder.rs b/wtx/src/http2/hpack_decoder.rs
index ef9dfdb3..a22a05ac 100644
--- a/wtx/src/http2/hpack_decoder.rs
+++ b/wtx/src/http2/hpack_decoder.rs
@@ -1,5 +1,5 @@
 use crate::{
-  http::{KnownHeaderName, Method, StatusCode, _HeaderNameBuffer, _HeaderValueBuffer},
+  http::{HeaderName, KnownHeaderName, Method, StatusCode, _HeaderNameBuffer, _HeaderValueBuffer},
   http2::{
     hpack_header::{HpackHeaderBasic, HpackHeaderName},
     hpack_headers::HpackHeaders,
@@ -13,7 +13,8 @@ use alloc::boxed::Box;
 
 const DYN_IDX_OFFSET: usize = 62;
 
-type RawHeaderPair<'value> = (&'static [u8], &'value [u8]);
+type RawHeaderName<'value> = (HeaderName<&'static str>, HeaderName<&'value str>);
+type RawHeaderValue<'value> = (&'static [u8], &'value [u8]);
 
 #[derive(Debug)]
 pub(crate) struct HpackDecoder {
@@ -45,7 +46,7 @@ impl HpackDecoder {
   pub(crate) fn decode(
     &mut self,
     mut data: &[u8],
-    mut cb: impl FnMut((HpackHeaderBasic, &[u8], &[u8])) -> crate::Result<()>,
+    mut cb: impl FnMut((HpackHeaderBasic, HeaderName<&str>, &[u8])) -> crate::Result<()>,
   ) -> crate::Result<()> {
     if let Some(elem) = self.max_bytes.1.take() {
       self.dyn_headers.set_max_bytes(*Usize::from(elem), |_| {});
@@ -131,11 +132,11 @@ impl HpackDecoder {
     &mut self,
     data: &mut &[u8],
     mask: u8,
-    elem_cb: &mut impl FnMut((HpackHeaderBasic, &[u8], &[u8])) -> crate::Result<()>,
+    elem_cb: &mut impl FnMut((HpackHeaderBasic, HeaderName<&str>, &[u8])) -> crate::Result<()>,
   ) -> crate::Result<()> {
     let idx = Self::decode_integer(data, mask)?.1;
     let has_indexed_name = idx != 0;
-    let (hhb, name, value) = if has_indexed_name {
+    if has_indexed_name {
       let value = Self::decode_string_value(&mut self.header_buffers.1, data)?;
       let (hhb, (static_name, dyn_name), _) = Self::get(&self.dyn_headers, *Usize::from(idx))?;
       let new_hhb = match hhb {
@@ -147,25 +148,28 @@ impl HpackDecoder {
         HpackHeaderBasic::Scheme => HpackHeaderBasic::Scheme,
         HpackHeaderBasic::StatusCode(_) => HpackHeaderBasic::StatusCode(value.try_into()?),
       };
-      let name = if static_name.is_empty() {
+      let name = if static_name.str().is_empty() {
         elem_cb((new_hhb, dyn_name, value))?;
         self.header_buffers.0.clear();
-        self.header_buffers.0.extend_from_copyable_slice(dyn_name)?;
-        self.header_buffers.0.get_mut(..dyn_name.len()).unwrap_or_default()
+        self.header_buffers.0.extend_from_copyable_slice(dyn_name.str().as_bytes())?;
+        let bytes = self.header_buffers.0.get_mut(..dyn_name.str().len()).unwrap_or_default();
+        // SAFETY: Just a temporary copy of an already existing string
+        unsafe { core::str::from_utf8_unchecked(bytes) }
       } else {
         elem_cb((new_hhb, static_name, value))?;
-        static_name
+        static_name.str()
       };
-      (new_hhb, name, value)
+      if STORE {
+        self.dyn_headers.push_front(new_hhb, name, [value].into_iter(), false, |_| {})?;
+      }
     } else {
       let (hhn, name) = Self::decode_string_name(&mut self.header_buffers.0, data)?;
       let value = Self::decode_string_value(&mut self.header_buffers.1, data)?;
       let hhb = HpackHeaderBasic::try_from((hhn, value))?;
       elem_cb((hhb, name, value))?;
-      (hhb, name, value)
-    };
-    if STORE {
-      self.dyn_headers.push_front(hhb, name, [value].into_iter(), false, |_| {})?;
+      if STORE {
+        self.dyn_headers.push_front(hhb, name.str(), [value].into_iter(), false, |_| {})?;
+      }
     }
     Ok(())
   }
@@ -189,13 +193,13 @@ impl HpackDecoder {
   fn decode_string_name<'buffer, 'data, 'rslt>(
     buffer: &'buffer mut _HeaderNameBuffer,
     data: &mut &'data [u8],
-  ) -> crate::Result<(HpackHeaderName, &'rslt [u8])>
+  ) -> crate::Result<(HpackHeaderName, HeaderName<&'rslt str>)>
   where
     'buffer: 'rslt,
     'data: 'rslt,
   {
     let (before, after, is_encoded) = Self::decode_string_init(data)?;
-    let rslt = if is_encoded {
+    let (hhn, bytes) = if is_encoded {
       huffman_decode(before, buffer)?;
       (HpackHeaderName::new(buffer)?, &**buffer)
     } else {
@@ -207,7 +211,7 @@ impl HpackDecoder {
       }
     };
     *data = after;
-    Ok(rslt)
+    Ok((hhn, HeaderName::from_bytes(bytes)?))
   }
 
   #[inline]
@@ -235,111 +239,184 @@ impl HpackDecoder {
   fn get(
     dyn_headers: &HpackHeaders<HpackHeaderBasic>,
     idx: usize,
-  ) -> crate::Result<(HpackHeaderBasic, RawHeaderPair<'_>, RawHeaderPair<'_>)> {
-    Ok(match idx {
+  ) -> crate::Result<(HpackHeaderBasic, RawHeaderName<'_>, RawHeaderValue<'_>)> {
+    let (hhb, name, value) = match idx {
       0 => {
         return Err(crate::Error::Http2ErrorGoAway(
           Http2ErrorCode::CompressionError,
           Some(Http2Error::InvalidHpackIdx(Some(0))),
         ))
       }
-      1 => (HpackHeaderBasic::Authority, (b":authority", &[]), (&[], &[])),
-      2 => (HpackHeaderBasic::Method(Method::Get), (b":method", &[]), (b"GET", &[])),
-      3 => (HpackHeaderBasic::Method(Method::Post), (b":method", &[]), (b"POST", &[])),
-      4 => (HpackHeaderBasic::Path, (b":path", &[]), (b"/", &[])),
-      5 => (HpackHeaderBasic::Path, (b":path", &[]), (b"/index.html", &[])),
-      6 => (HpackHeaderBasic::Scheme, (b":scheme", &[]), (b"http", &[])),
-      7 => (HpackHeaderBasic::Scheme, (b":scheme", &[]), (b"https", &[])),
-      8 => (HpackHeaderBasic::StatusCode(StatusCode::Ok), (b":status", &[]), (b"200", &[])),
-      9 => (HpackHeaderBasic::StatusCode(StatusCode::NoContent), (b":status", &[]), (b"204", &[])),
-      10 => {
-        (HpackHeaderBasic::StatusCode(StatusCode::PartialContent), (b":status", &[]), (b"206", &[]))
-      }
-      11 => {
-        (HpackHeaderBasic::StatusCode(StatusCode::NotModified), (b":status", &[]), (b"304", &[]))
-      }
-      12 => {
-        (HpackHeaderBasic::StatusCode(StatusCode::BadRequest), (b":status", &[]), (b"400", &[]))
+      1 => (HpackHeaderBasic::Authority, (":authority", ""), (&[][..], &[][..])),
+      2 => (HpackHeaderBasic::Method(Method::Get), (":method", ""), ("GET".as_bytes(), &[][..])),
+      3 => (HpackHeaderBasic::Method(Method::Post), (":method", ""), ("POST".as_bytes(), &[][..])),
+      4 => (HpackHeaderBasic::Path, (":path", ""), ("/".as_bytes(), &[][..])),
+      5 => (HpackHeaderBasic::Path, (":path", ""), ("/index.html".as_bytes(), &[][..])),
+      6 => (HpackHeaderBasic::Scheme, (":scheme", ""), ("http".as_bytes(), &[][..])),
+      7 => (HpackHeaderBasic::Scheme, (":scheme", ""), ("https".as_bytes(), &[][..])),
+      8 => {
+        (HpackHeaderBasic::StatusCode(StatusCode::Ok), (":status", ""), ("200".as_bytes(), &[][..]))
       }
-      13 => (HpackHeaderBasic::StatusCode(StatusCode::NotFound), (b":status", &[]), (b"404", &[])),
+      9 => (
+        HpackHeaderBasic::StatusCode(StatusCode::NoContent),
+        (":status", ""),
+        ("204".as_bytes(), &[][..]),
+      ),
+      10 => (
+        HpackHeaderBasic::StatusCode(StatusCode::PartialContent),
+        (":status", ""),
+        ("206".as_bytes(), &[][..]),
+      ),
+      11 => (
+        HpackHeaderBasic::StatusCode(StatusCode::NotModified),
+        (":status", ""),
+        ("304".as_bytes(), &[][..]),
+      ),
+      12 => (
+        HpackHeaderBasic::StatusCode(StatusCode::BadRequest),
+        (":status", ""),
+        ("400".as_bytes(), &[][..]),
+      ),
+      13 => (
+        HpackHeaderBasic::StatusCode(StatusCode::NotFound),
+        (":status", ""),
+        ("404".as_bytes(), &[][..]),
+      ),
       14 => (
         HpackHeaderBasic::StatusCode(StatusCode::InternalServerError),
-        (b":status", &[]),
-        (b"500", &[]),
+        (":status", ""),
+        ("500".as_bytes(), &[][..]),
       ),
-      15 => (HpackHeaderBasic::Field, (KnownHeaderName::AcceptCharset.into(), &[]), (&[], &[])),
+      15 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::AcceptCharset.into(), ""), (&[][..], &[][..]))
+      }
       16 => (
         HpackHeaderBasic::Field,
-        (KnownHeaderName::AcceptEncoding.into(), &[]),
-        (b"gzip, deflate", &[]),
+        (KnownHeaderName::AcceptEncoding.into(), ""),
+        ("gzip, deflate".as_bytes(), &[][..]),
       ),
-      17 => (HpackHeaderBasic::Field, (KnownHeaderName::AcceptLanguage.into(), &[]), (&[], &[])),
-      18 => (HpackHeaderBasic::Field, (KnownHeaderName::AcceptRanges.into(), &[]), (&[], &[])),
-      19 => (HpackHeaderBasic::Field, (KnownHeaderName::Accept.into(), &[]), (&[], &[])),
+      17 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::AcceptLanguage.into(), ""), (&[][..], &[][..]))
+      }
+      18 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::AcceptRanges.into(), ""), (&[][..], &[][..]))
+      }
+      19 => (HpackHeaderBasic::Field, (KnownHeaderName::Accept.into(), ""), (&[][..], &[][..])),
       20 => (
         HpackHeaderBasic::Field,
-        (KnownHeaderName::AccessControlAllowOrigin.into(), &[]),
-        (&[], &[]),
+        (KnownHeaderName::AccessControlAllowOrigin.into(), ""),
+        (&[][..], &[][..]),
+      ),
+      21 => (HpackHeaderBasic::Field, (KnownHeaderName::Age.into(), ""), (&[][..], &[][..])),
+      22 => (HpackHeaderBasic::Field, (KnownHeaderName::Allow.into(), ""), (&[][..], &[][..])),
+      23 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::Authorization.into(), ""), (&[][..], &[][..]))
+      }
+      24 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::CacheControl.into(), ""), (&[][..], &[][..]))
+      }
+      25 => (
+        HpackHeaderBasic::Field,
+        (KnownHeaderName::ContentDisposition.into(), ""),
+        (&[][..], &[][..]),
       ),
-      21 => (HpackHeaderBasic::Field, (KnownHeaderName::Age.into(), &[]), (&[], &[])),
-      22 => (HpackHeaderBasic::Field, (KnownHeaderName::Allow.into(), &[]), (&[], &[])),
-      23 => (HpackHeaderBasic::Field, (KnownHeaderName::Authorization.into(), &[]), (&[], &[])),
-      24 => (HpackHeaderBasic::Field, (KnownHeaderName::CacheControl.into(), &[]), (&[], &[])),
-      25 => {
-        (HpackHeaderBasic::Field, (KnownHeaderName::ContentDisposition.into(), &[]), (&[], &[]))
+      26 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::ContentEncoding.into(), ""), (&[][..], &[][..]))
+      }
+      27 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::ContentLanguage.into(), ""), (&[][..], &[][..]))
+      }
+      28 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::ContentLength.into(), ""), (&[][..], &[][..]))
+      }
+      29 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::ContentLocation.into(), ""), (&[][..], &[][..]))
+      }
+      30 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::ContentRange.into(), ""), (&[][..], &[][..]))
+      }
+      31 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::ContentType.into(), ""), (&[][..], &[][..]))
+      }
+      32 => (HpackHeaderBasic::Field, (KnownHeaderName::Cookie.into(), ""), (&[][..], &[][..])),
+      33 => (HpackHeaderBasic::Field, (KnownHeaderName::Date.into(), ""), (&[][..], &[][..])),
+      34 => (HpackHeaderBasic::Field, (KnownHeaderName::Etag.into(), ""), (&[][..], &[][..])),
+      35 => (HpackHeaderBasic::Field, (KnownHeaderName::Expect.into(), ""), (&[][..], &[][..])),
+      36 => (HpackHeaderBasic::Field, (KnownHeaderName::Expires.into(), ""), (&[][..], &[][..])),
+      37 => (HpackHeaderBasic::Field, (KnownHeaderName::From.into(), ""), (&[][..], &[][..])),
+      38 => (HpackHeaderBasic::Field, (KnownHeaderName::Host.into(), ""), (&[][..], &[][..])),
+      39 => (HpackHeaderBasic::Field, (KnownHeaderName::IfMatch.into(), ""), (&[][..], &[][..])),
+      40 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::IfModifiedSince.into(), ""), (&[][..], &[][..]))
       }
-      26 => (HpackHeaderBasic::Field, (KnownHeaderName::ContentEncoding.into(), &[]), (&[], &[])),
-      27 => (HpackHeaderBasic::Field, (KnownHeaderName::ContentLanguage.into(), &[]), (&[], &[])),
-      28 => (HpackHeaderBasic::Field, (KnownHeaderName::ContentLength.into(), &[]), (&[], &[])),
-      29 => (HpackHeaderBasic::Field, (KnownHeaderName::ContentLocation.into(), &[]), (&[], &[])),
-      30 => (HpackHeaderBasic::Field, (KnownHeaderName::ContentRange.into(), &[]), (&[], &[])),
-      31 => (HpackHeaderBasic::Field, (KnownHeaderName::ContentType.into(), &[]), (&[], &[])),
-      32 => (HpackHeaderBasic::Field, (KnownHeaderName::Cookie.into(), &[]), (&[], &[])),
-      33 => (HpackHeaderBasic::Field, (KnownHeaderName::Date.into(), &[]), (&[], &[])),
-      34 => (HpackHeaderBasic::Field, (KnownHeaderName::Etag.into(), &[]), (&[], &[])),
-      35 => (HpackHeaderBasic::Field, (KnownHeaderName::Expect.into(), &[]), (&[], &[])),
-      36 => (HpackHeaderBasic::Field, (KnownHeaderName::Expires.into(), &[]), (&[], &[])),
-      37 => (HpackHeaderBasic::Field, (KnownHeaderName::From.into(), &[]), (&[], &[])),
-      38 => (HpackHeaderBasic::Field, (KnownHeaderName::Host.into(), &[]), (&[], &[])),
-      39 => (HpackHeaderBasic::Field, (KnownHeaderName::IfMatch.into(), &[]), (&[], &[])),
-      40 => (HpackHeaderBasic::Field, (KnownHeaderName::IfModifiedSince.into(), &[]), (&[], &[])),
-      41 => (HpackHeaderBasic::Field, (KnownHeaderName::IfNoneMatch.into(), &[]), (&[], &[])),
-      42 => (HpackHeaderBasic::Field, (KnownHeaderName::IfRange.into(), &[]), (&[], &[])),
-      43 => (HpackHeaderBasic::Field, (KnownHeaderName::IfUnmodifiedSince.into(), &[]), (&[], &[])),
-      44 => (HpackHeaderBasic::Field, (KnownHeaderName::LastModified.into(), &[]), (&[], &[])),
-      45 => (HpackHeaderBasic::Field, (KnownHeaderName::Link.into(), &[]), (&[], &[])),
-      46 => (HpackHeaderBasic::Field, (KnownHeaderName::Location.into(), &[]), (&[], &[])),
-      47 => (HpackHeaderBasic::Field, (KnownHeaderName::MaxForwards.into(), &[]), (&[], &[])),
-      48 => (HpackHeaderBasic::Field, (KnownHeaderName::ProxyAuthenticate.into(), &[]), (&[], &[])),
-      49 => {
-        (HpackHeaderBasic::Field, (KnownHeaderName::ProxyAuthorization.into(), &[]), (&[], &[]))
+      41 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::IfNoneMatch.into(), ""), (&[][..], &[][..]))
       }
-      50 => (HpackHeaderBasic::Field, (KnownHeaderName::Range.into(), &[]), (&[], &[])),
-      51 => (HpackHeaderBasic::Field, (KnownHeaderName::Referer.into(), &[]), (&[], &[])),
-      52 => (HpackHeaderBasic::Field, (KnownHeaderName::Refresh.into(), &[]), (&[], &[])),
-      53 => (HpackHeaderBasic::Field, (KnownHeaderName::RetryAfter.into(), &[]), (&[], &[])),
-      54 => (HpackHeaderBasic::Field, (KnownHeaderName::Server.into(), &[]), (&[], &[])),
-      55 => (HpackHeaderBasic::Field, (KnownHeaderName::SetCookie.into(), &[]), (&[], &[])),
+      42 => (HpackHeaderBasic::Field, (KnownHeaderName::IfRange.into(), ""), (&[][..], &[][..])),
+      43 => (
+        HpackHeaderBasic::Field,
+        (KnownHeaderName::IfUnmodifiedSince.into(), ""),
+        (&[][..], &[][..]),
+      ),
+      44 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::LastModified.into(), ""), (&[][..], &[][..]))
+      }
+      45 => (HpackHeaderBasic::Field, (KnownHeaderName::Link.into(), ""), (&[][..], &[][..])),
+      46 => (HpackHeaderBasic::Field, (KnownHeaderName::Location.into(), ""), (&[][..], &[][..])),
+      47 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::MaxForwards.into(), ""), (&[][..], &[][..]))
+      }
+      48 => (
+        HpackHeaderBasic::Field,
+        (KnownHeaderName::ProxyAuthenticate.into(), ""),
+        (&[][..], &[][..]),
+      ),
+      49 => (
+        HpackHeaderBasic::Field,
+        (KnownHeaderName::ProxyAuthorization.into(), ""),
+        (&[][..], &[][..]),
+      ),
+      50 => (HpackHeaderBasic::Field, (KnownHeaderName::Range.into(), ""), (&[][..], &[][..])),
+      51 => (HpackHeaderBasic::Field, (KnownHeaderName::Referer.into(), ""), (&[][..], &[][..])),
+      52 => (HpackHeaderBasic::Field, (KnownHeaderName::Refresh.into(), ""), (&[][..], &[][..])),
+      53 => (HpackHeaderBasic::Field, (KnownHeaderName::RetryAfter.into(), ""), (&[][..], &[][..])),
+      54 => (HpackHeaderBasic::Field, (KnownHeaderName::Server.into(), ""), (&[][..], &[][..])),
+      55 => (HpackHeaderBasic::Field, (KnownHeaderName::SetCookie.into(), ""), (&[][..], &[][..])),
       56 => (
         HpackHeaderBasic::Field,
-        (KnownHeaderName::StrictTransportSecurity.into(), &[]),
-        (&[], &[]),
+        (KnownHeaderName::StrictTransportSecurity.into(), ""),
+        (&[][..], &[][..]),
       ),
-      57 => (HpackHeaderBasic::Field, (KnownHeaderName::TransferEncoding.into(), &[]), (&[], &[])),
-      58 => (HpackHeaderBasic::Field, (KnownHeaderName::UserAgent.into(), &[]), (&[], &[])),
-      59 => (HpackHeaderBasic::Field, (KnownHeaderName::Vary.into(), &[]), (&[], &[])),
-      60 => (HpackHeaderBasic::Field, (KnownHeaderName::Via.into(), &[]), (&[], &[])),
-      61 => (HpackHeaderBasic::Field, (KnownHeaderName::WwwAuthenticate.into(), &[]), (&[], &[])),
-      dyn_idx_with_offset => dyn_headers
-        .get_by_idx(dyn_idx_with_offset.wrapping_sub(DYN_IDX_OFFSET))
-        .ok_or_else(|| {
-          crate::Error::Http2ErrorGoAway(
-            Http2ErrorCode::CompressionError,
-            Some(Http2Error::InvalidHpackIdx(dyn_idx_with_offset.try_into().ok())),
-          )
-        })
-        .map(|el| (*el.misc, (&[][..], el.name_bytes), (&[][..], el.value_bytes)))?,
-    })
+      57 => (
+        HpackHeaderBasic::Field,
+        (KnownHeaderName::TransferEncoding.into(), ""),
+        (&[][..], &[][..]),
+      ),
+      58 => (HpackHeaderBasic::Field, (KnownHeaderName::UserAgent.into(), ""), (&[][..], &[][..])),
+      59 => (HpackHeaderBasic::Field, (KnownHeaderName::Vary.into(), ""), (&[][..], &[][..])),
+      60 => (HpackHeaderBasic::Field, (KnownHeaderName::Via.into(), ""), (&[][..], &[][..])),
+      61 => {
+        (HpackHeaderBasic::Field, (KnownHeaderName::WwwAuthenticate.into(), ""), (&[][..], &[][..]))
+      }
+      dyn_idx_with_offset => {
+        return dyn_headers
+          .get_by_idx(dyn_idx_with_offset.wrapping_sub(DYN_IDX_OFFSET))
+          .map(|el| {
+            (
+              *el.misc,
+              (HeaderName::new_unchecked(""), HeaderName::new_unchecked(el.name_bytes)),
+              (&[][..], el.value_bytes),
+            )
+          })
+          .ok_or_else(|| {
+            crate::Error::Http2ErrorGoAway(
+              Http2ErrorCode::CompressionError,
+              Some(Http2Error::InvalidHpackIdx(dyn_idx_with_offset.try_into().ok())),
+            )
+          })
+      }
+    };
+    Ok((hhb, (HeaderName::new_unchecked(name.0), HeaderName::new_unchecked(name.1)), value))
   }
 
   #[inline]
@@ -347,7 +424,7 @@ impl HpackDecoder {
     &mut self,
     byte: u8,
     data: &mut &[u8],
-    elem_cb: &mut impl FnMut((HpackHeaderBasic, &[u8], &[u8])) -> crate::Result<()>,
+    elem_cb: &mut impl FnMut((HpackHeaderBasic, HeaderName<&str>, &[u8])) -> crate::Result<()>,
     mut size_update_cb: impl FnMut() -> crate::Result<()>,
   ) -> crate::Result<()> {
     match DecodeIdx::try_from(byte)? {
@@ -356,7 +433,7 @@ impl HpackDecoder {
         elem_cb(Self::get(&self.dyn_headers, *Usize::from(idx)).map(|(hhb, name, value)| {
           (
             hhb,
-            if name.0.is_empty() { name.1 } else { name.0 },
+            if name.0.str().is_empty() { name.1 } else { name.0 },
             if value.0.is_empty() { value.1 } else { value.0 },
           )
         })?)?;
@@ -414,37 +491,3 @@ impl TryFrom<u8> for DecodeIdx {
     })
   }
 }
-
-#[cfg(all(feature = "_bench", test))]
-mod bench {
-  use crate::{
-    http::Header,
-    http2::{hpack_decoder::HpackDecoder, hpack_encoder::HpackEncoder},
-    misc::{simple_seed, Usize, Vector, Xorshift64},
-  };
-
-  #[bench]
-  fn decode(b: &mut test::Bencher) {
-    const N: u32 = 1024 * 1024;
-    let data = {
-      let mut rslt = crate::bench::_data(*Usize::from(N));
-      rslt.iter_mut().filter(|el| **el == b':').for_each(|el| {
-        *el = 0;
-      });
-      rslt
-    };
-    let mut buffer = Vector::with_capacity(*Usize::from(N)).unwrap();
-    let mut he = HpackEncoder::new(Xorshift64::from(simple_seed()));
-    he.set_max_dyn_super_bytes(N);
-    he.encode(&mut buffer, [].into_iter(), {
-      data.chunks_exact(128).map(|el| Header::from_name_and_value(&el[..64], &el[64..]))
-    })
-    .unwrap();
-    let mut hd = HpackDecoder::new();
-    hd.set_max_bytes(N);
-    b.iter(|| {
-      hd.decode(&buffer, |_| Ok(())).unwrap();
-      hd.clear();
-    });
-  }
-}
diff --git a/wtx/src/http2/hpack_encoder.rs b/wtx/src/http2/hpack_encoder.rs
index b9a510b0..0e2b9967 100644
--- a/wtx/src/http2/hpack_encoder.rs
+++ b/wtx/src/http2/hpack_encoder.rs
@@ -82,8 +82,8 @@ impl HpackEncoder {
     buffer.reserve(reserve)?;
     self.manage_size_update(buffer)?;
     for (hhb, value) in pseudo_headers_iter {
-      let idx = self.encode_idx((&[], value, false), hhb, Self::shi_pseudo((hhb, value)))?;
-      Self::manage_encode(buffer, (&[], value), idx)?;
+      let idx = self.encode_idx(("", value, false), hhb, Self::shi_pseudo((hhb, value)))?;
+      Self::manage_encode(buffer, ("", value), idx)?;
     }
     for Header { is_sensitive, name, value, .. } in user_headers_iter {
       let idx = self.encode_idx(
@@ -147,13 +147,13 @@ impl HpackEncoder {
   #[inline]
   fn dyn_idx(
     &mut self,
-    header: (&[u8], &[u8], bool),
+    header: (&str, &[u8], bool),
     should_not_index: bool,
   ) -> crate::Result<EncodeIdx> {
     let (name, value, is_sensitive) = header;
 
     let mut name_hasher = self.rs.build_hasher();
-    name_hasher.write(name);
+    name_hasher.write(name.as_bytes());
 
     let mut pair_hasher = name_hasher.clone();
     pair_hasher.write(value);
@@ -191,7 +191,7 @@ impl HpackEncoder {
   #[inline]
   fn dyn_idx_with_static_name(
     &mut self,
-    header: (&[u8], &[u8], bool),
+    header: (&str, &[u8], bool),
     name_idx: u32,
   ) -> crate::Result<EncodeIdx> {
     let (name, value, is_sensitive) = header;
@@ -205,7 +205,7 @@ impl HpackEncoder {
   #[inline]
   fn encode_idx(
     &mut self,
-    header: (&[u8], &[u8], bool),
+    header: (&str, &[u8], bool),
     hhb: HpackHeaderBasic,
     static_header: Option<StaticHeader>,
   ) -> crate::Result<EncodeIdx> {
@@ -330,10 +330,10 @@ impl HpackEncoder {
   // Regardless of the "sensitive" flag set by users, these headers may carry sensitive content
   // that shouldn't be indexed.
   #[inline]
-  fn header_is_naturally_sensitive(hhb: HpackHeaderBasic, name: &[u8]) -> bool {
+  fn header_is_naturally_sensitive(hhb: HpackHeaderBasic, name: &str) -> bool {
     match hhb {
       HpackHeaderBasic::Field => matches!(
-        KnownHeaderName::try_from(name),
+        KnownHeaderName::try_from(name.as_bytes()),
         Ok(
           KnownHeaderName::Age
             | KnownHeaderName::Authorization
@@ -353,7 +353,7 @@ impl HpackEncoder {
 
   // Very large headers are not good candidates for indexing.
   #[inline]
-  fn header_is_very_large(&self, hhb: HpackHeaderBasic, name: &[u8], value: &[u8]) -> bool {
+  fn header_is_very_large(&self, hhb: HpackHeaderBasic, name: &str, value: &[u8]) -> bool {
     hhb.len(name, value) >= (self.dyn_headers.max_bytes() / 4).wrapping_mul(3)
   }
 
@@ -365,7 +365,7 @@ impl HpackEncoder {
   #[inline]
   fn manage_encode(
     buffer: &mut Vector<u8>,
-    header: (&[u8], &[u8]),
+    header: (&str, &[u8]),
     idx: EncodeIdx,
   ) -> crate::Result<()> {
     let (name, value) = header;
@@ -383,12 +383,12 @@ impl HpackEncoder {
       }
       EncodeIdx::SavedNameSavedValue => {
         buffer.push(0b0100_0000)?;
-        Self::encode_str(buffer, name)?;
+        Self::encode_str(buffer, name.as_bytes())?;
         Self::encode_str(buffer, value)?;
       }
       EncodeIdx::UnsavedNameUnsavedValue => {
         buffer.push(0b0001_0000)?;
-        Self::encode_str(buffer, name)?;
+        Self::encode_str(buffer, name.as_bytes())?;
         Self::encode_str(buffer, value)?;
       }
     }
@@ -428,7 +428,7 @@ impl HpackEncoder {
   #[inline]
   fn push_dyn_headers(
     &mut self,
-    (name, value, is_sensitive): (&[u8], &[u8], bool),
+    (name, value, is_sensitive): (&str, &[u8], bool),
     (name_hash, pair_hash): (Option<u64>, u64),
   ) -> crate::Result<()> {
     self.idx = self.idx.wrapping_add(1);
@@ -446,10 +446,10 @@ impl HpackEncoder {
 
   #[inline]
   fn shi_pseudo((hhb, value): (HpackHeaderBasic, &[u8])) -> Option<StaticHeader> {
-    let (has_value, idx, name): (_, _, &[u8]) = match hhb {
-      HpackHeaderBasic::Authority => (false, 1, b":authority"),
+    let (has_value, idx, name): (_, _, &str) = match hhb {
+      HpackHeaderBasic::Authority => (false, 1, ":authority"),
       HpackHeaderBasic::Method(method) => {
-        let name = b":method";
+        let name = ":method";
         let (has_value, idx) = match method {
           Method::Get => (true, 2),
           Method::Post => (true, 3),
@@ -458,7 +458,7 @@ impl HpackEncoder {
         (has_value, idx, name)
       }
       HpackHeaderBasic::Path => {
-        let name = b":path";
+        let name = ":path";
         let (has_value, idx) = match value {
           b"/" => (true, 4),
           b"/index.html" => (true, 5),
@@ -467,7 +467,7 @@ impl HpackEncoder {
         (has_value, idx, name)
       }
       HpackHeaderBasic::Scheme => {
-        let name = b":path";
+        let name = ":path";
         let (has_value, idx) = match value {
           b"http" => (true, 6),
           b"https" => (true, 7),
@@ -476,7 +476,7 @@ impl HpackEncoder {
         (has_value, idx, name)
       }
       HpackHeaderBasic::StatusCode(status) => {
-        let name = b":status";
+        let name = ":status";
         let (has_value, idx) = match status {
           StatusCode::Ok => (true, 8),
           StatusCode::NoContent => (true, 9),
@@ -495,8 +495,8 @@ impl HpackEncoder {
   }
 
   #[inline]
-  fn shi_user((name, value): (&[u8], &[u8])) -> Option<StaticHeader> {
-    let (has_value, idx, local_name) = match KnownHeaderName::try_from(name) {
+  fn shi_user((name, value): (&str, &[u8])) -> Option<StaticHeader> {
+    let (has_value, idx, local_name) = match KnownHeaderName::try_from(name.as_bytes()) {
       Ok(KnownHeaderName::AcceptCharset) => (false, 15, KnownHeaderName::AcceptCharset.into()),
       Ok(KnownHeaderName::AcceptEncoding) => {
         if value == b"gzip, deflate" {
@@ -572,7 +572,7 @@ impl HpackEncoder {
   #[inline]
   fn should_not_index(
     &self,
-    (name, value, is_sensitive): (&[u8], &[u8], bool),
+    (name, value, is_sensitive): (&str, &[u8], bool),
     hhb: HpackHeaderBasic,
   ) -> bool {
     is_sensitive
@@ -591,7 +591,7 @@ impl HpackEncoder {
   #[inline]
   fn store_header_with_ref_name<const HAS_STATIC_NAME: bool>(
     &mut self,
-    (name, value, is_sensitive): (&[u8], &[u8], bool),
+    (name, value, is_sensitive): (&str, &[u8], bool),
     name_idx: u32,
     pair_hash: u64,
   ) -> crate::Result<EncodeIdx> {
@@ -647,31 +647,5 @@ struct Metadata {
 struct StaticHeader {
   has_value: bool,
   idx: u32,
-  name: &'static [u8],
-}
-
-#[cfg(all(feature = "_bench", test))]
-mod bench {
-  use crate::{
-    http::Header,
-    http2::hpack_encoder::HpackEncoder,
-    misc::{simple_seed, Usize, Vector, Xorshift64},
-  };
-
-  #[bench]
-  fn encode(b: &mut test::Bencher) {
-    const N: u32 = 1024 * 1024 * 4;
-    let data = crate::bench::_data(*Usize::from(N));
-    let mut he = HpackEncoder::new(Xorshift64::from(simple_seed()));
-    he.set_max_dyn_super_bytes(N);
-    let mut buffer = Vector::new();
-    b.iter(|| {
-      he.encode(
-        &mut buffer,
-        [].into_iter(),
-        data.chunks_exact(128).map(|el| Header::from_name_and_value(&el[..64], &el[64..])),
-      )
-      .unwrap();
-    });
-  }
+  name: &'static str,
 }
diff --git a/wtx/src/http2/hpack_header.rs b/wtx/src/http2/hpack_header.rs
index bce4ee35..e1ccc168 100644
--- a/wtx/src/http2/hpack_header.rs
+++ b/wtx/src/http2/hpack_header.rs
@@ -15,7 +15,7 @@ pub(crate) enum HpackHeaderBasic {
 }
 
 impl HpackHeaderBasic {
-  pub(crate) const fn len(self, name: &[u8], value: &[u8]) -> usize {
+  pub(crate) const fn len(self, name: &str, value: &[u8]) -> usize {
     match self {
       HpackHeaderBasic::Authority => 10usize.wrapping_add(value.len()).wrapping_add(32),
       HpackHeaderBasic::Field => name.len().wrapping_add(value.len()).wrapping_add(32),
diff --git a/wtx/src/http2/hpack_headers.rs b/wtx/src/http2/hpack_headers.rs
index c4897df2..1d7d2638 100644
--- a/wtx/src/http2/hpack_headers.rs
+++ b/wtx/src/http2/hpack_headers.rs
@@ -1,4 +1,5 @@
 use crate::misc::{Block, BlocksDeque};
+use core::str;
 
 #[derive(Debug)]
 pub(crate) struct HpackHeaders<M> {
@@ -44,7 +45,7 @@ where
   pub(crate) fn push_front<'bytes, I>(
     &mut self,
     misc: M,
-    name: &'bytes [u8],
+    name: &'bytes str,
     values: I,
     is_sensitive: bool,
     cb: impl FnMut(M),
@@ -64,7 +65,7 @@ where
     }
     self.remove_until_max_bytes(local_len, cb);
     self.bq.push_front_from_coyable_data(
-      [name].into_iter().chain(iter),
+      [name.as_bytes()].into_iter().chain(iter),
       Metadata { is_sensitive, misc, name_len: name.len() },
     )?;
     Ok(())
@@ -87,7 +88,11 @@ where
     AbstractHeader {
       is_sensitive: block.misc.is_sensitive,
       misc: &block.misc.misc,
-      name_bytes: block.data.get(..block.misc.name_len).unwrap_or_default(),
+      name_bytes: {
+        let str = block.data.get(..block.misc.name_len).unwrap_or_default();
+        // SAFETY: Input methods only accept UTF-8 data
+        unsafe { str::from_utf8_unchecked(str) }
+      },
       value_bytes: block.data.get(block.misc.name_len..).unwrap_or_default(),
     }
   }
@@ -111,7 +116,7 @@ where
 pub(crate) struct AbstractHeader<'ah, M> {
   pub(crate) is_sensitive: bool,
   pub(crate) misc: &'ah M,
-  pub(crate) name_bytes: &'ah [u8],
+  pub(crate) name_bytes: &'ah str,
   pub(crate) value_bytes: &'ah [u8],
 }
 
diff --git a/wtx/src/misc/rng/rand_chacha.rs b/wtx/src/misc/rng/rand_chacha.rs
index c18c4a49..51268b5e 100644
--- a/wtx/src/misc/rng/rand_chacha.rs
+++ b/wtx/src/misc/rng/rand_chacha.rs
@@ -2,16 +2,6 @@ use rand_core::RngCore;
 
 macro_rules! implement {
   ($struct:ty) => {
-    #[cfg(feature = "http-server-framework")]
-    impl crate::http::server_framework::ConnAux for $struct {
-      type Init = Self;
-
-      #[inline]
-      fn conn_aux(init: Self::Init) -> crate::Result<Self> {
-        Ok(init)
-      }
-    }
-
     impl crate::misc::rng::Rng for $struct {
       #[inline]
       fn u8(&mut self) -> u8 {
diff --git a/wtx/src/misc/rng/xorshift.rs b/wtx/src/misc/rng/xorshift.rs
index e0d0d3ab..137ffc91 100644
--- a/wtx/src/misc/rng/xorshift.rs
+++ b/wtx/src/misc/rng/xorshift.rs
@@ -7,16 +7,6 @@ pub struct Xorshift64 {
   value: u64,
 }
 
-#[cfg(feature = "http-server-framework")]
-impl crate::http::server_framework::ConnAux for Xorshift64 {
-  type Init = Self;
-
-  #[inline]
-  fn conn_aux(init: Self::Init) -> crate::Result<Self> {
-    Ok(init)
-  }
-}
-
 impl Rng for Xorshift64 {
   #[inline]
   fn u8(&mut self) -> u8 {
diff --git a/wtx/src/misc/stream.rs b/wtx/src/misc/stream.rs
index 62ec0d54..7e475817 100644
--- a/wtx/src/misc/stream.rs
+++ b/wtx/src/misc/stream.rs
@@ -1,3 +1,15 @@
+macro_rules! _local_write_all {
+  ($bytes:expr, $write:expr) => {{
+    while !$bytes.is_empty() {
+      match $write {
+        Err(e) => return Err(e.into()),
+        Ok(0) => return { Err(crate::Error::UnexpectedStreamWriteEOF) },
+        Ok(n) => $bytes = $bytes.get(n..).unwrap_or_default(),
+      }
+    }
+  }};
+}
+
 macro_rules! _local_write_all_vectored {
   ($bytes:expr, $this:ident, |$io_slices:ident| $write_many:expr) => {
     if let [single] = $bytes {
@@ -17,6 +29,8 @@ macro_rules! _local_write_all_vectored {
 }
 
 mod bytes_stream;
+#[cfg(feature = "embassy-net")]
+mod embassy_net;
 #[cfg(feature = "embedded-tls")]
 mod embedded_tls;
 #[cfg(feature = "std")]
diff --git a/wtx/src/misc/stream/embassy_net.rs b/wtx/src/misc/stream/embassy_net.rs
new file mode 100644
index 00000000..bd1a93c2
--- /dev/null
+++ b/wtx/src/misc/stream/embassy_net.rs
@@ -0,0 +1,25 @@
+use crate::misc::{StreamReader, StreamWriter};
+use embassy_net::tcp::TcpSocket;
+
+impl StreamReader for TcpSocket<'_> {
+  #[inline]
+  async fn read(&mut self, bytes: &mut [u8]) -> crate::Result<usize> {
+    Ok((*self).read(bytes).await?)
+  }
+}
+
+impl StreamWriter for TcpSocket<'_> {
+  #[inline]
+  async fn write_all(&mut self, mut bytes: &[u8]) -> crate::Result<()> {
+    _local_write_all!(bytes, Self::write(self, bytes).await);
+    Ok(())
+  }
+
+  #[inline]
+  async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> {
+    for elem in bytes {
+      self.write_all(elem).await?;
+    }
+    Ok(())
+  }
+}
diff --git a/wtx/src/misc/stream/tokio_rustls.rs b/wtx/src/misc/stream/tokio_rustls.rs
index ff6f8eaf..8d8042be 100644
--- a/wtx/src/misc/stream/tokio_rustls.rs
+++ b/wtx/src/misc/stream/tokio_rustls.rs
@@ -1,5 +1,6 @@
 use crate::misc::{StreamReader, StreamWithTls, StreamWriter};
 use ring::digest::{self, Digest};
+use rustls_pki_types::CertificateDer;
 use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
 
 impl<T> StreamReader for tokio_rustls::client::TlsStream<T>
@@ -21,35 +22,7 @@ where
   #[inline]
   fn tls_server_end_point(&self) -> crate::Result<Option<Self::TlsServerEndPoint>> {
     let (_, conn) = self.get_ref();
-    Ok(match conn.peer_certificates() {
-      Some([cert, ..]) => {
-        #[cfg(feature = "x509-certificate")]
-        let algorithm = {
-          use x509_certificate::{DigestAlgorithm, SignatureAlgorithm};
-          let x509_cer = x509_certificate::X509Certificate::from_der(cert)?;
-          let Some(sa) = x509_cer.signature_algorithm() else {
-            return Ok(None);
-          };
-          match sa {
-            SignatureAlgorithm::EcdsaSha256
-            | SignatureAlgorithm::RsaSha1
-            | SignatureAlgorithm::RsaSha256 => &digest::SHA256,
-            SignatureAlgorithm::EcdsaSha384 | SignatureAlgorithm::RsaSha384 => &digest::SHA384,
-            SignatureAlgorithm::Ed25519 => &digest::SHA512,
-            SignatureAlgorithm::NoSignature(da) => match da {
-              DigestAlgorithm::Sha1 | DigestAlgorithm::Sha256 => &digest::SHA256,
-              DigestAlgorithm::Sha384 => &digest::SHA384,
-              DigestAlgorithm::Sha512 => &digest::SHA512,
-            },
-            SignatureAlgorithm::RsaSha512 => &digest::SHA512,
-          }
-        };
-        #[cfg(not(feature = "x509-certificate"))]
-        let algorithm = &digest::SHA256;
-        Some(digest::digest(algorithm, cert.as_ref()))
-      }
-      _ => None,
-    })
+    tls_server_end_point(conn.peer_certificates())
   }
 }
 
@@ -89,10 +62,7 @@ where
   #[inline]
   fn tls_server_end_point(&self) -> crate::Result<Option<Self::TlsServerEndPoint>> {
     let (_, conn) = self.get_ref();
-    Ok(match conn.peer_certificates() {
-      Some([cert, ..]) => Some(digest::digest(&digest::SHA256, cert)),
-      _ => None,
-    })
+    tls_server_end_point(conn.peer_certificates())
   }
 }
 
@@ -112,3 +82,38 @@ where
     Ok(())
   }
 }
+
+#[inline]
+fn tls_server_end_point(
+  certs: Option<&[CertificateDer<'static>]>,
+) -> crate::Result<Option<Digest>> {
+  Ok(match certs {
+    Some([cert, ..]) => {
+      #[cfg(feature = "x509-certificate")]
+      let algorithm = {
+        use x509_certificate::{DigestAlgorithm, SignatureAlgorithm};
+        let x509_cer = x509_certificate::X509Certificate::from_der(cert)?;
+        let Some(sa) = x509_cer.signature_algorithm() else {
+          return Ok(None);
+        };
+        match sa {
+          SignatureAlgorithm::EcdsaSha256
+          | SignatureAlgorithm::RsaSha1
+          | SignatureAlgorithm::RsaSha256 => &digest::SHA256,
+          SignatureAlgorithm::EcdsaSha384 | SignatureAlgorithm::RsaSha384 => &digest::SHA384,
+          SignatureAlgorithm::Ed25519 => &digest::SHA512,
+          SignatureAlgorithm::NoSignature(da) => match da {
+            DigestAlgorithm::Sha1 | DigestAlgorithm::Sha256 => &digest::SHA256,
+            DigestAlgorithm::Sha384 => &digest::SHA384,
+            DigestAlgorithm::Sha512 => &digest::SHA512,
+          },
+          SignatureAlgorithm::RsaSha512 => &digest::SHA512,
+        }
+      };
+      #[cfg(not(feature = "x509-certificate"))]
+      let algorithm = &digest::SHA256;
+      Some(digest::digest(algorithm, cert.as_ref()))
+    }
+    _ => None,
+  })
+}
diff --git a/wtx/src/pool/resource_manager.rs b/wtx/src/pool/resource_manager.rs
index fd239068..1330ae12 100644
--- a/wtx/src/pool/resource_manager.rs
+++ b/wtx/src/pool/resource_manager.rs
@@ -238,8 +238,8 @@ pub(crate) mod database {
           Executor::connect_encrypted(
             &config,
             ExecutorBuffer::new(self.max_stmts, &mut &self.rng),
-            TcpStream::connect(uri.hostname_with_implied_port()).await.map_err(Into::into)?,
             &mut &self.rng,
+            TcpStream::connect(uri.hostname_with_implied_port()).await.map_err(Into::into)?,
             |stream| async {
               let mut rslt = TokioRustlsConnector::from_auto()?;
               if let Some(elem) = self._certs {
@@ -268,8 +268,8 @@ pub(crate) mod database {
           Executor::connect_encrypted(
             &config,
             buffer,
-            TcpStream::connect(uri.hostname_with_implied_port()).await.map_err(Into::into)?,
             &mut &self.rng,
+            TcpStream::connect(uri.hostname_with_implied_port()).await.map_err(Into::into)?,
             |stream| async {
               let mut rslt = TokioRustlsConnector::from_auto()?;
               if let Some(elem) = self._certs {


Test patch:
diff --git a/wtx/src/database/client/postgres/integration_tests.rs b/wtx/src/database/client/postgres/integration_tests.rs
index bbba3e08..f2459f47 100644
--- a/wtx/src/database/client/postgres/integration_tests.rs
+++ b/wtx/src/database/client/postgres/integration_tests.rs
@@ -21,8 +21,8 @@ async fn conn_scram_tls() {
   let _executor = Executor::<crate::Error, _, _>::connect_encrypted(
     &Config::from_uri(&uri).unwrap(),
     ExecutorBuffer::new(usize::MAX, &mut rng),
-    TcpStream::connect(uri.hostname_with_implied_port()).await.unwrap(),
     &mut rng,
+    TcpStream::connect(uri.hostname_with_implied_port()).await.unwrap(),
     |stream| async {
       Ok(
         crate::misc::TokioRustlsConnector::from_auto()
diff --git a/wtx/src/http2/tests/connections.rs b/wtx/src/http2/tests/connections.rs
index 15657c36..b596ae97 100644
--- a/wtx/src/http2/tests/connections.rs
+++ b/wtx/src/http2/tests/connections.rs
@@ -34,7 +34,7 @@ async fn client(uri: &UriString) {
   _0(rrb.body(), rrb.headers());
 
   rrb.clear();
-  rrb.headers.push_from_iter(Header::from_name_and_value(b"123", ["456".as_bytes()])).unwrap();
+  rrb.headers.push_from_iter(Header::from_name_and_value("123", ["456".as_bytes()])).unwrap();
   rrb = stream_client(&mut http2, rrb, &uri_ref).await;
   _1(rrb.body(), rrb.headers());
 
@@ -45,7 +45,7 @@ async fn client(uri: &UriString) {
 
   rrb.clear();
   rrb.body.extend_from_copyable_slice(b"123").unwrap();
-  rrb.headers.push_from_iter(Header::from_name_and_value(b"123", ["456".as_bytes()])).unwrap();
+  rrb.headers.push_from_iter(Header::from_name_and_value("123", ["456".as_bytes()])).unwrap();
   rrb = stream_client(&mut http2, rrb, &uri_ref).await;
   _3(rrb.body(), rrb.headers());
 
diff --git a/wtx/src/http2/tests/hpack.rs b/wtx/src/http2/tests/hpack.rs
index ab914055..44f0b252 100644
--- a/wtx/src/http2/tests/hpack.rs
+++ b/wtx/src/http2/tests/hpack.rs
@@ -111,15 +111,15 @@ fn fetch_project() {
     .unwrap();
 }
 
-pub(crate) const fn hhb_name<'name>(hhb: HpackHeaderBasic, name: &'name [u8]) -> &'name [u8] {
+pub(crate) const fn hhb_name<'name>(hhb: HpackHeaderBasic, name: &'name str) -> &'name str {
   match hhb {
-    HpackHeaderBasic::Authority => b":authority",
+    HpackHeaderBasic::Authority => ":authority",
     HpackHeaderBasic::Field => name,
-    HpackHeaderBasic::Method(_) => b":method",
-    HpackHeaderBasic::Path => b":path",
-    HpackHeaderBasic::Protocol(_) => b":protocol",
-    HpackHeaderBasic::Scheme => b":scheme",
-    HpackHeaderBasic::StatusCode(_) => b":status",
+    HpackHeaderBasic::Method(_) => ":method",
+    HpackHeaderBasic::Path => ":path",
+    HpackHeaderBasic::Protocol(_) => ":protocol",
+    HpackHeaderBasic::Scheme => ":scheme",
+    HpackHeaderBasic::StatusCode(_) => ":status",
   }
 }
 
@@ -142,12 +142,12 @@ fn parse_hex(hex: &[u8]) -> Vector<u8> {
 
 fn strs<'key, 'value>(
   hhb: HpackHeaderBasic,
-  name: &'key [u8],
+  name: &'key str,
   value: &'value [u8],
 ) -> (&'key str, &'value str) {
   match hhb {
     HpackHeaderBasic::Authority => (":authority", from_utf8_basic(value).unwrap()),
-    HpackHeaderBasic::Field => (from_utf8_basic(name).unwrap(), from_utf8_basic(value).unwrap()),
+    HpackHeaderBasic::Field => (name, from_utf8_basic(value).unwrap()),
     HpackHeaderBasic::Method(elem) => (":method", elem.strings().custom[0]),
     HpackHeaderBasic::Path => (":path", from_utf8_basic(value).unwrap()),
     HpackHeaderBasic::Protocol(elem) => (":protocol", elem.strings().custom[0]),
@@ -220,7 +220,7 @@ fn test_story_encoding_and_decoding(
       if header.name.starts_with(":") {
         None
       } else {
-        Some((HpackHeaderBasic::Field, header.name.as_bytes(), header.value.as_bytes()))
+        Some((HpackHeaderBasic::Field, header.name.as_str(), header.value.as_bytes()))
       }
     }))
     .unwrap();
@@ -236,7 +236,7 @@ fn test_story_encoding_and_decoding(
     decoder
       .decode(&buffer, |(hhb, name, value)| {
         if pseudo_headers.is_empty() {
-          assert_eq!((hhb, hhb_name(hhb, name), value), user_headers.remove(0).unwrap());
+          assert_eq!((hhb, hhb_name(hhb, name.str()), value), user_headers.remove(0).unwrap());
         } else {
           assert_eq!((hhb, value), pseudo_headers.remove(0).unwrap());
         }
@@ -263,7 +263,7 @@ fn test_story_wired_decoding(cases: &mut Vector<Case>, decoder: &mut HpackDecode
     decoder
       .decode(&parse_hex(wire.as_bytes()), |(hhb, name, value)| {
         let case_header = case.headers.remove(0).unwrap();
-        let (name, value) = strs(hhb, name, value);
+        let (name, value) = strs(hhb, name.str(), value);
         assert_eq!(case_header.name, name);
         assert_eq!(case_header.value, value);
         Ok(())
diff --git a/wtx/src/web_socket/handshake/tests.rs b/wtx/src/web_socket/handshake/tests.rs
index 184d8d0c..9ffcb03d 100644
--- a/wtx/src/web_socket/handshake/tests.rs
+++ b/wtx/src/web_socket/handshake/tests.rs
@@ -15,7 +15,6 @@ use crate::{
     WebSocketClient, WebSocketClientOwned, WebSocketServer, WebSocketServerOwned,
   },
 };
-use alloc::vec;
 use core::{
   sync::atomic::{AtomicBool, Ordering},
   time::Duration,
@@ -177,7 +176,7 @@ where
   NC: NegotiatedCompression,
 {
   async fn client(ws: &mut WebSocketClientOwned<NC, TcpStream>) {
-    let bytes = || vec![b'1'; 256 * 1024];
+    let bytes = || _vector![b'1'; 256 * 1024];
     ws.write_frame(&mut Frame::new_unfin(OpCode::Text, &mut bytes())).await.unwrap();
     ws.write_frame(&mut Frame::new_unfin(OpCode::Continuation, &mut bytes())).await.unwrap();
     ws.write_frame(&mut Frame::new_unfin(OpCode::Continuation, &mut bytes())).await.unwrap();
@@ -193,7 +192,7 @@ where
   async fn server(ws: &mut WebSocketServerOwned<NC, TcpStream>) {
     let text = ws.read_frame().await.unwrap();
     assert_eq!(OpCode::Text, text.op_code());
-    assert_eq!(&vec![b'1'; 10 * 256 * 1024], text.payload());
+    assert_eq!(_vector![b'1'; 10 * 256 * 1024].as_slice(), *text.payload());
   }
 }