Merge autoland to mozilla-central a=merge
authorCoroiu Cristina <ccoroiu@mozilla.com>
Sun, 17 Nov 2019 23:33:53 +0200
changeset 502499 d6844fe546ad129a6b2c93dd2e70a75d40e7ffca
parent 502498 20eeab9d1782c253e1d01fe5ffb978e2db47ef01 (current diff)
parent 502343 16aae9e3e3ea4e6770189908388ded4cb6836de3 (diff)
child 502500 f78494c785f1b3264b1a17376d01520e1072ba7b
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone72.0a1
first release with
nightly linux32
d6844fe546ad / 72.0a1 / 20191117213438 / files
nightly linux64
d6844fe546ad / 72.0a1 / 20191117213438 / files
nightly mac
d6844fe546ad / 72.0a1 / 20191117213438 / files
nightly win32
d6844fe546ad / 72.0a1 / 20191117213438 / files
nightly win64
d6844fe546ad / 72.0a1 / 20191117213438 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central a=merge
third_party/rust/neqo-http3/src/connection_server.rs
--- a/.cargo/config.in
+++ b/.cargo/config.in
@@ -10,17 +10,17 @@ replace-with = "vendored-sources"
 [source."https://github.com/mozilla/rkv"]
 git = "https://github.com/mozilla/rkv"
 replace-with = "vendored-sources"
 rev = "6a866fdad2ca880df9b87fcbc9921abac1e91914"
 
 [source."https://github.com/mozilla/neqo"]
 git = "https://github.com/mozilla/neqo"
 replace-with = "vendored-sources"
-rev = "a17c1e83"
+tag = "v0.1.6"
 
 [source."https://github.com/kvark/spirv_cross"]
 branch = "wgpu"
 git = "https://github.com/kvark/spirv_cross"
 replace-with = "vendored-sources"
 
 [source."https://github.com/kvark/rust-objc-exception"]
 branch = "cc"
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2296,86 +2296,86 @@ dependencies = [
 
 [[package]]
 name = "murmurhash3"
 version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "neqo-common"
-version = "0.1.4"
-source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
+version = "0.1.6"
+source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
 dependencies = [
  "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "neqo-crypto"
-version = "0.1.4"
-source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
+version = "0.1.6"
+source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
 dependencies = [
  "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
+ "neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "neqo-http3"
-version = "0.1.4"
-source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
+version = "0.1.6"
+source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
 dependencies = [
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-qpack 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
+ "neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-qpack 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "neqo-qpack"
-version = "0.1.4"
-source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
+version = "0.1.6"
+source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
 dependencies = [
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
+ "neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
 ]
 
 [[package]]
 name = "neqo-transport"
-version = "0.1.4"
-source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
+version = "0.1.6"
+source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
 dependencies = [
  "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
+ "neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "slice-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "neqo_glue"
 version = "0.1.0"
 dependencies = [
- "neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-http3 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
- "neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
+ "neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-http3 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
+ "neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
  "nserror 0.1.0",
  "nsstring 0.1.0",
  "thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "xpcom 0.1.0",
 ]
 
 [[package]]
 name = "net2"
@@ -3165,17 +3165,17 @@ name = "rust_cascade"
 version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bit_reverse 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rustc-demangle"
 version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -4670,21 +4670,21 @@ dependencies = [
 "checksum mio-named-pipes 0.1.6 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>"
 "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
 "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
 "checksum moz_cbor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20c82a57087fd5990d7122dbff1607c3b20c3d2958e9d9ad9765aab415e2c91c"
 "checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
 "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
 "checksum murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
-"checksum neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
-"checksum neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
-"checksum neqo-http3 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
-"checksum neqo-qpack 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
-"checksum neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
+"checksum neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
+"checksum neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
+"checksum neqo-http3 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
+"checksum neqo-qpack 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
+"checksum neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
 "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
 "checksum nix 0.13.1 (git+https://github.com/shravanrn/nix/?branch=r0.13.1)" = "<none>"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
 "checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
 "checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
 "checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
--- a/browser/components/preferences/in-content/syncChooseWhatToSync.js
+++ b/browser/components/preferences/in-content/syncChooseWhatToSync.js
@@ -36,22 +36,25 @@ let gSyncChooseWhatToSync = {
     }
   },
 
   // make whatever tweaks we need based on preferences.
   _adjustForPrefs() {
     // These 2 engines are unique in that there are prefs that make the
     // entire engine unavailable (which is distinct from "disabled").
     let enginePrefs = [
-      ["services.sync.engine.addresses.available", ".sync-engine-addresses"],
-      [
-        "services.sync.engine.creditcards.available",
-        ".sync-engine-creditcards",
-      ],
+      ["services.sync.engine.addresses", ".sync-engine-addresses"],
+      ["services.sync.engine.creditcards", ".sync-engine-creditcards"],
     ];
-    for (let [availablePref, className] of enginePrefs) {
+    for (let [enabledPref, className] of enginePrefs) {
+      let availablePref = enabledPref + ".available";
+      // If the engine is enabled we force it to be available, otherwise we see
+      // spooky things happen (like it magically re-appear later)
+      if (Services.prefs.getBoolPref(enabledPref, false)) {
+        Services.prefs.setBoolPref(availablePref, true);
+      }
       if (!Services.prefs.getBoolPref(availablePref)) {
         let elt = document.querySelector(className);
         elt.hidden = true;
       }
     }
   },
 };
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3973,16 +3973,19 @@ gfxFontGroup* CanvasRenderingContext2D::
           FontFamilyList(StyleGenericFontFamily::SansSerif), &style, tp,
           nullptr, devToCssSize);
       if (CurrentState().fontGroup) {
         CurrentState().font = kDefaultFontStyle;
       } else {
         NS_ERROR("Default canvas font is invalid");
       }
     }
+  } else {
+    // The fontgroup needs to check if its cached families/faces are valid.
+    CurrentState().fontGroup->CheckForUpdatedPlatformList();
   }
 
   return CurrentState().fontGroup;
 }
 
 //
 // line caps/joins
 //
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1345,27 +1345,17 @@ void ContentChild::InitXPCOM(
     MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
     return;
   }
 
   LSObject::Initialize();
 
   ClientManager::Startup();
 
-  // Respecting COOP and COEP requires processing headers in the parent process
-  // in order to choose an appropriate content process, but the workers'
-  // ScriptLoader processes headers in content processes. An intermediary step
-  // that provides security guarantees is to simply never allow SharedWorkers
-  // and ServiceWorkers to exist in a COOP+COEP process. The ultimate goal
-  // is to allow these worker types to be put in such processes based on their
-  // script response headers.
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=1595206
-  if (!IsWebCoopCoepRemoteType(GetRemoteType())) {
-    RemoteWorkerService::Initialize();
-  }
+  RemoteWorkerService::Initialize();
 
   nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!svc) {
     NS_WARNING("Couldn't acquire console service");
     return;
   }
 
   mConsoleListener = new ConsoleListener(this);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -723,21 +723,16 @@ const nsDependentSubstring RemoteTypePre
   return StringHead(aContentProcessType, equalIdx);
 }
 
 bool IsWebRemoteType(const nsAString& aContentProcessType) {
   return StringBeginsWith(aContentProcessType,
                           NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
 }
 
-bool IsWebCoopCoepRemoteType(const nsAString& aContentProcessType) {
-  return StringBeginsWith(aContentProcessType,
-                          NS_LITERAL_STRING(WITH_COOP_COEP_REMOTE_TYPE_PREFIX));
-}
-
 /*static*/
 uint32_t ContentParent::GetMaxProcessCount(
     const nsAString& aContentProcessType) {
   // Max process count is based only on the prefix.
   const nsDependentSubstring processTypePrefix =
       RemoteTypePrefix(aContentProcessType);
 
   // Check for the default remote type of "web", as it uses different prefs.
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1393,18 +1393,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(ContentPar
 
 // This is the C++ version of remoteTypePrefix in E10SUtils.jsm.
 const nsDependentSubstring RemoteTypePrefix(
     const nsAString& aContentProcessType);
 
 // This is based on isWebRemoteType in E10SUtils.jsm.
 bool IsWebRemoteType(const nsAString& aContentProcessType);
 
-bool IsWebCoopCoepRemoteType(const nsAString& aContentProcessType);
-
 }  // namespace dom
 }  // namespace mozilla
 
 class ParentIdleListener : public nsIObserver {
   friend class mozilla::dom::ContentParent;
 
  public:
   NS_DECL_ISUPPORTS
--- a/dom/workers/remoteworkers/RemoteWorkerManager.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerManager.cpp
@@ -234,22 +234,17 @@ RemoteWorkerManager::SelectTargetActorFo
     MOZ_ASSERT(bgParent);
 
     RefPtr<ContentParent> contentParent =
         BackgroundParent::GetContentParent(bgParent);
 
     auto scopeExit = MakeScopeExit(
         [&] { contentParents.AppendElement(std::move(contentParent)); });
 
-    const nsAString& remoteType = contentParent->GetRemoteType();
-    MOZ_DIAGNOSTIC_ASSERT(
-        !IsWebCoopCoepRemoteType(remoteType),
-        "COOP+COEP processes don't support remote workers right now");
-
-    if (IsWebRemoteType(remoteType)) {
+    if (IsWebRemoteType(contentParent->GetRemoteType())) {
       auto lock = contentParent->mRemoteWorkerActorData.Lock();
 
       if (lock->mCount || !lock->mShutdownStarted) {
         ++lock->mCount;
 
         // This won't cause any race conditions because the content process
         // should wait for the permissions to be received before executing the
         // Service Worker.
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -2314,10 +2314,14 @@ void gfxPlatformFontList::InitOtherFamil
     return;
   }
   if (list->GetGeneration() != aGeneration) {
     return;
   }
   InitOtherFamilyNames(aDefer);
 }
 
+uint32_t gfxPlatformFontList::GetGeneration() const {
+  return SharedFontList() ? SharedFontList()->GetGeneration() : 0;
+}
+
 #undef LOG
 #undef LOG_ENABLED
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -439,16 +439,24 @@ class gfxPlatformFontList : public gfxFo
 
   static const char* GetGenericName(
       mozilla::StyleGenericFontFamily aGenericType);
 
   bool SkipFontFallbackForChar(uint32_t aCh) const {
     return mCodepointsWithNoFonts.test(aCh);
   }
 
+  // If using the shared font list, returns a generation count that is
+  // incremented if/when the platform list is reinitialized (e.g. because
+  // fonts are installed/removed while the browser is running), such that
+  // existing references to shared font family or face objects and character
+  // maps will no longer be valid.
+  // (The legacy (non-shared) list just returns 0 here.)
+  uint32_t GetGeneration() const;
+
  protected:
   friend class mozilla::fontlist::FontList;
   friend class InitOtherFamilyNamesForStylo;
 
   class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable {
    public:
     InitOtherFamilyNamesRunnable()
         : CancelableRunnable(
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1729,16 +1729,18 @@ void gfxFontGroup::BuildFontList() {
   // build the fontlist from the specified families
   for (const auto& f : fonts) {
     if (f.mFamily.mIsShared) {
       AddFamilyToFontList(f.mFamily.mShared, f.mGeneric);
     } else {
       AddFamilyToFontList(f.mFamily.mUnshared, f.mGeneric);
     }
   }
+
+  mFontListGeneration = pfl->GetGeneration();
 }
 
 void gfxFontGroup::AddPlatformFont(const nsACString& aName, bool aQuotedName,
                                    nsTArray<FamilyAndGeneric>& aFamilyList) {
   // First, look up in the user font set...
   // If the fontSet matches the family, we must not look for a platform
   // font of the same name, even if we fail to actually get a fontEntry
   // here; we'll fall back to the next name in the CSS font-family list.
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -1044,16 +1044,27 @@ class gfxFontGroup final : public gfxTex
   // It is only guaranteed to exist until the next call to GetEllipsisTextRun
   // (which might use a different appUnitsPerDev value or flags) for the font
   // group, or until UpdateUserFonts is called, or the fontgroup is destroyed.
   // Get it/use it/forget it :) - don't keep a reference that might go stale.
   gfxTextRun* GetEllipsisTextRun(
       int32_t aAppUnitsPerDevPixel, mozilla::gfx::ShapedTextFlags aFlags,
       LazyReferenceDrawTargetGetter& aRefDrawTargetGetter);
 
+  void CheckForUpdatedPlatformList() {
+    auto* pfl = gfxPlatformFontList::PlatformFontList();
+    if (mFontListGeneration != pfl->GetGeneration()) {
+      // Forget cached fonts that may no longer be valid.
+      mLastPrefFamily = FontFamily();
+      mLastPrefFont = nullptr;
+      mFonts.Clear();
+      BuildFontList();
+    }
+  }
+
  protected:
   friend class mozilla::PostTraversalTask;
 
   struct TextRange {
     TextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont,
               FontMatchType aMatchType,
               mozilla::gfx::ShapedTextFlags aOrientation)
         : start(aStart),
@@ -1352,16 +1363,19 @@ class gfxFontGroup final : public gfxTex
   eFontPrefLang mPageLang;
   bool mLastPrefFirstFont;  // is this the first font in the list of pref fonts
                             // for this lang group?
 
   bool mSkipDrawing;  // hide text while waiting for a font
                       // download to complete (or fallback
                       // timer to fire)
 
+  uint32_t mFontListGeneration = 0;  // platform font list generation for this
+                                     // fontgroup
+
   /**
    * Textrun creation short-cuts for special cases where we don't need to
    * call a font shaper to generate glyphs.
    */
   already_AddRefed<gfxTextRun> MakeEmptyTextRun(
       const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags,
       nsTextFrameUtils::Flags aFlags2);
 
--- a/netwerk/protocol/http/Http3Session.cpp
+++ b/netwerk/protocol/http/Http3Session.cpp
@@ -323,16 +323,19 @@ nsresult Http3Session::ProcessEvents(uin
         LOG(("Http3Session::ProcessEvents - ConnectionClosing"));
         if (NS_SUCCEEDED(mError) && !IsClosing()) {
           mError = NS_ERROR_NET_HTTP3_PROTOCOL_ERROR;
         }
         CloseInternal(false);
         break;
       case Http3Event::Tag::ConnectionClosed:
         LOG(("Http3Session::ProcessEvents - ConnectionClosed"));
+        if (NS_SUCCEEDED(mError) && !IsClosing()) {
+          mError = NS_ERROR_NET_HTTP3_PROTOCOL_ERROR;
+        }
         CloseInternal(false);
         mState = CLOSED;
         break;
       default:
         break;
     }
     event = mHttp3Connection->GetEvent();
   }
--- a/netwerk/socket/neqo_glue/Cargo.toml
+++ b/netwerk/socket/neqo_glue/Cargo.toml
@@ -3,21 +3,21 @@ name = "neqo_glue"
 version = "0.1.0"
 authors = ["Dragana Damjanovic <dd.mozilla@gmail.com>"]
 edition = "2018"
 
 [lib]
 name = "neqo_glue"
 
 [dependencies]
-neqo-http3 = { rev = "a17c1e83", git = "https://github.com/mozilla/neqo" }
-neqo-transport = { rev = "a17c1e83", git = "https://github.com/mozilla/neqo" }
-neqo-common = { rev = "a17c1e83", git = "https://github.com/mozilla/neqo" }
+neqo-http3 = { tag = "v0.1.6", git = "https://github.com/mozilla/neqo" }
+neqo-transport = { tag = "v0.1.6", git = "https://github.com/mozilla/neqo" }
+neqo-common = { tag = "v0.1.6", git = "https://github.com/mozilla/neqo" }
 nserror = { path = "../../../xpcom/rust/nserror" }
 nsstring = { path = "../../../xpcom/rust/nsstring" }
 xpcom = { path = "../../../xpcom/rust/xpcom" }
 thin-vec = { version = "0.1.0", features = ["gecko-ffi"] }
 
 [dependencies.neqo-crypto]
-rev = "a17c1e83"
+tag = "v0.1.6"
 git = "https://github.com/mozilla/neqo"
 default-features = false
 features = ["gecko"]
--- a/third_party/rust/neqo-common/.cargo-checksum.json
+++ b/third_party/rust/neqo-common/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6791b2f6143d31a8b2511e995a1ca902e0827f8cefdd966a477ad11068602e80","src/codec.rs":"6c619c42d1293297fd1e1763213033a82723bfa97938f5dd9fde6745f965940e","src/datagram.rs":"47d69797b66108cec997375818cb43ba9575b89f8730277047c6889de09b12aa","src/incrdecoder.rs":"4d55c9d992a4c409e4b4e37a8c04d3741d2ba260f46d5385cb3eff5121db03de","src/lib.rs":"7204f3eb32908563ffd50e615534326509be781cb5afd111f3bccdd6cf04249c","src/log.rs":"68a0a30344edcfad6c222eed62f5810fb9aa896fea7ec782b6ca2b2fc9a0bd4b","src/once.rs":"ad0d1ac0233dda75e294b5ccab65caceaec66d277659e22b1236aceea0c53ede","src/timer.rs":"13fb2ad4ef435d57895c61c291aca82a261c93c0f2cae2634929fb6ca5fdac85","tests/log.rs":"79e01eeef039d1abb17aadb2212256ad064c53e6d72bbebe254230119a623510"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"0132063e21304df128d64381c01694c31d7775c1f3d72f169ea9d4547d7024cf","src/codec.rs":"6c619c42d1293297fd1e1763213033a82723bfa97938f5dd9fde6745f965940e","src/datagram.rs":"47d69797b66108cec997375818cb43ba9575b89f8730277047c6889de09b12aa","src/incrdecoder.rs":"4d55c9d992a4c409e4b4e37a8c04d3741d2ba260f46d5385cb3eff5121db03de","src/lib.rs":"7204f3eb32908563ffd50e615534326509be781cb5afd111f3bccdd6cf04249c","src/log.rs":"943e4e332400d94805d60f965d1d0ae7aad180f6d5b50936d0bd9e085bbc1502","src/once.rs":"ad0d1ac0233dda75e294b5ccab65caceaec66d277659e22b1236aceea0c53ede","src/timer.rs":"13fb2ad4ef435d57895c61c291aca82a261c93c0f2cae2634929fb6ca5fdac85","tests/log.rs":"1c7ae6cb43047877fff27f3d01abc8ac456ea0907e88473d0179215342391d5d"},"package":null}
\ No newline at end of file
--- a/third_party/rust/neqo-common/Cargo.toml
+++ b/third_party/rust/neqo-common/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "neqo-common"
-version = "0.1.4"
+version = "0.1.6"
 authors = ["Bobby Holley <bobbyholley@gmail.com>"]
 edition = "2018"
 license = "MIT/Apache-2.0"
 
 [dependencies]
 num-traits = "0.2"
 log = "0.4.0"
 env_logger = "0.6.1"
--- a/third_party/rust/neqo-common/src/log.rs
+++ b/third_party/rust/neqo-common/src/log.rs
@@ -42,35 +42,30 @@ macro_rules! qlog {
     ($lvl:expr, $ctx:expr, $($arg:tt)*) => ( {
         ::neqo_common::log::init();
         ::log::log!($lvl, "[{}] {}", $ctx, format!($($arg)*));
     } )
 }
 #[macro_export]
 macro_rules! qerror {
     ([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Error, $ctx, $($arg)*););
-    ([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Error, $ctx, $($arg)*););
     ($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Error, $($arg)*); } );
 }
 #[macro_export]
 macro_rules! qwarn {
     ([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Warn, $ctx, $($arg)*););
-    ([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Warn, $ctx, $($arg)*););
     ($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Warn, $($arg)*); } );
 }
 #[macro_export]
 macro_rules! qinfo {
     ([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Info, $ctx, $($arg)*););
-    ([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Info, $ctx, $($arg)*););
     ($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Info, $($arg)*); } );
 }
 #[macro_export]
 macro_rules! qdebug {
     ([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Debug, $ctx, $($arg)*););
-    ([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Debug, $ctx, $($arg)*););
     ($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Debug, $($arg)*); } );
 }
 #[macro_export]
 macro_rules! qtrace {
     ([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Trace, $ctx, $($arg)*););
-    ([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Trace, $ctx, $($arg)*););
     ($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Trace, $($arg)*); } );
 }
--- a/third_party/rust/neqo-common/tests/log.rs
+++ b/third_party/rust/neqo-common/tests/log.rs
@@ -26,21 +26,21 @@ fn args() {
     qinfo!("info {} {:?}", num, obj);
     qdebug!("debug {} {:?}", num, obj);
     qtrace!("trace {} {:?}", num, obj);
 }
 
 #[test]
 fn context() {
     let context = "context";
-    qerror!([context] "error");
-    qwarn!([context] "warn");
-    qinfo!([context] "info");
-    qdebug!([context] "debug");
-    qtrace!([context] "trace");
+    qerror!([context], "error");
+    qwarn!([context], "warn");
+    qinfo!([context], "info");
+    qdebug!([context], "debug");
+    qtrace!([context], "trace");
 }
 
 #[test]
 fn context_comma() {
     let obj = vec![1, 2, 3];
     let context = "context";
     qerror!([context], "error {:?}", obj);
     qwarn!([context], "warn {:?}", obj);
--- a/third_party/rust/neqo-crypto/.cargo-checksum.json
+++ b/third_party/rust/neqo-crypto/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"d7afc57115b1915c379e45550e58e5b09245db87affd7a55b8b733a852a542a0","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"0f305bda9513e7fb4b521df79912ad5ba21784377b84f4b531895619e561f356","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"ebb685e47de005413d8e24370ba22576b45b0273aaf0a5116af96dcdc48d32c0","src/aead.rs":"bfbd4b72354fb7103ff31a2a600dd457e10fdc14ad670a5de1f5bb0f9b6e1504","src/agent.rs":"b8f59b2f1d3432db0b810383c2ae6d17a79b89819b90da50eecc3370cae77398","src/agentio.rs":"615a805e0f27970755daa5bfe864b2e9b3b09309dfa4178b85f38a13ae6f7131","src/auth.rs":"846a4954186f0bcabc4084214ae216819215f3bccc33cc08d93abb9c5fefb7f2","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"75dec8e3c74326f492a115a0e7a487daba32eba30bcbd64d2223333b3caa4008","src/err.rs":"81d5c9b75457d4367607d0a456c276fa037c0f66a1c8df40af58ff42426c9890","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"f3cc5bfdd96d46affff43653258d91eb447251f83da19b37dd415129052413e3","src/hkdf.rs":"6d44f63493f0c558a23339f88fe766f8afdb0bda3dc11a79e8a99d3c8d0b6acb","src/hp.rs":"854ce7b9d44892fbb01ac4078b84266771a9254cebfea5b94e7f4b4a7fb1b946","src/lib.rs":"6c3540b4e54510f6a298f04093f44f6d957f30f475214fd3ec9e39fa4d98e386","src/p11.rs":"89df482ae683646add0f46333991f31fe996fdce67859a1ff37c090a4166ce6e","src/prio.rs":"0e213056f6bf0c797c2cfe13c6d14dbb64a64b1218fff21cbf36fb3309b852f9","src/replay.rs":"01eae2accfefbc26719fcccd4bcb8c1ea6400ab96fbb696ecdb8f32164f931a2","src/result.rs":"d76c7bc5e99c80a5a124909ab586cdb91d894856e52f5146430da43584a6d6c1","src/secrets.rs":"e929b69927d93b4bde3bd490c0ed9a4e1e4c5a047492259ab1dae7fbad885c22","src/selfencrypt.rs":"9bffad6af2f186f606bd7305a8528d76e66471a71f7103c7498b90507fb031e1","src/ssl.rs":"4c7c850777a1b4b7b66ad765e24a25780e64f24da08175b5cc722a840d35f693","src/time.rs":"4dffa6f4ac9cfc8db240c370fb04a7d7241c80793ecf6acda2d41d0bc94b0236","tests/aead.rs":"bedf985ba0b95a9c6db6a84f870d15062d821f3b24cb3cb9dfa89445be795d50","tests/agent.rs":"8b9ca3c182cf065b7668fd9c7e5885b1cde8bb1d0ea3afbb5fb7a3186d7a9d2e","tests/ext.rs":"b1d2f9d68d18e24df5f246e4ad6f80a0a0d98f824094a9fa447a580b02486d90","tests/handshake.rs":"2752bd6c575e7d28db2bce8484aa08ba08846f30aa0bb9aa07153d1763dab830","tests/hkdf.rs":"83300020a18d5485a1adcd3b806aed64fd008072589875112145f401340f3602","tests/hp.rs":"83f453a792ef17eb51a20b2764407c28a60620f5d3b917c8e237a121b32988df","tests/init.rs":"abb08d3d5d9610d62dc94535230ed4f52743d90b7059224b152caa8cf7cf43d7","tests/selfencrypt.rs":"365bc96be63d2e970bab7cf0134a59526513e1c1c3b854c34fa44fc8ed8c10d3"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"f238c080977551a9301b25aa52362b19dae1ad1fdeda2b3f47d21752e13e37bf","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"0f305bda9513e7fb4b521df79912ad5ba21784377b84f4b531895619e561f356","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"0a4eaffefed2e190286a0de3eb69cd860ed4aea215d58a7135331b1850a5f82d","src/aead.rs":"bfbd4b72354fb7103ff31a2a600dd457e10fdc14ad670a5de1f5bb0f9b6e1504","src/agent.rs":"2539f4d1c471457208af0597c61a30e7abb1295d1442e6ed8fbbd83811c3dff6","src/agentio.rs":"25b87af28366d32671770900bed3bf093b141cc92c5193be71e4f748eea2a313","src/auth.rs":"846a4954186f0bcabc4084214ae216819215f3bccc33cc08d93abb9c5fefb7f2","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"75dec8e3c74326f492a115a0e7a487daba32eba30bcbd64d2223333b3caa4008","src/err.rs":"d2ee7e2e024acb8894fe0a9e028e6627dad19368808df1d52d321f1b8a159dca","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"f3cc5bfdd96d46affff43653258d91eb447251f83da19b37dd415129052413e3","src/hkdf.rs":"6d44f63493f0c558a23339f88fe766f8afdb0bda3dc11a79e8a99d3c8d0b6acb","src/hp.rs":"854ce7b9d44892fbb01ac4078b84266771a9254cebfea5b94e7f4b4a7fb1b946","src/lib.rs":"6c3540b4e54510f6a298f04093f44f6d957f30f475214fd3ec9e39fa4d98e386","src/p11.rs":"89df482ae683646add0f46333991f31fe996fdce67859a1ff37c090a4166ce6e","src/prio.rs":"0e213056f6bf0c797c2cfe13c6d14dbb64a64b1218fff21cbf36fb3309b852f9","src/replay.rs":"01eae2accfefbc26719fcccd4bcb8c1ea6400ab96fbb696ecdb8f32164f931a2","src/result.rs":"d76c7bc5e99c80a5a124909ab586cdb91d894856e52f5146430da43584a6d6c1","src/secrets.rs":"e929b69927d93b4bde3bd490c0ed9a4e1e4c5a047492259ab1dae7fbad885c22","src/selfencrypt.rs":"9bffad6af2f186f606bd7305a8528d76e66471a71f7103c7498b90507fb031e1","src/ssl.rs":"4c7c850777a1b4b7b66ad765e24a25780e64f24da08175b5cc722a840d35f693","src/time.rs":"4dffa6f4ac9cfc8db240c370fb04a7d7241c80793ecf6acda2d41d0bc94b0236","tests/aead.rs":"bedf985ba0b95a9c6db6a84f870d15062d821f3b24cb3cb9dfa89445be795d50","tests/agent.rs":"8b9ca3c182cf065b7668fd9c7e5885b1cde8bb1d0ea3afbb5fb7a3186d7a9d2e","tests/ext.rs":"b1d2f9d68d18e24df5f246e4ad6f80a0a0d98f824094a9fa447a580b02486d90","tests/handshake.rs":"2752bd6c575e7d28db2bce8484aa08ba08846f30aa0bb9aa07153d1763dab830","tests/hkdf.rs":"83300020a18d5485a1adcd3b806aed64fd008072589875112145f401340f3602","tests/hp.rs":"83f453a792ef17eb51a20b2764407c28a60620f5d3b917c8e237a121b32988df","tests/init.rs":"abb08d3d5d9610d62dc94535230ed4f52743d90b7059224b152caa8cf7cf43d7","tests/selfencrypt.rs":"365bc96be63d2e970bab7cf0134a59526513e1c1c3b854c34fa44fc8ed8c10d3"},"package":null}
\ No newline at end of file
--- a/third_party/rust/neqo-crypto/Cargo.toml
+++ b/third_party/rust/neqo-crypto/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "neqo-crypto"
-version = "0.1.4"
+version = "0.1.6"
 authors = ["Martin Thomson <mt@lowentropy.net>"]
 edition = "2018"
 build = "build.rs"
 license = "MIT/Apache-2.0"
 
 [dependencies]
 neqo-common = { path = "../neqo-common" }
 log = "0.4.0"
--- a/third_party/rust/neqo-crypto/build.rs
+++ b/third_party/rust/neqo-crypto/build.rs
@@ -226,17 +226,19 @@ fn get_includes(nsstarget: &Path, nssdis
 fn build_bindings(base: &str, bindings: &Bindings, flags: &[String], gecko: bool) {
     let suffix = if bindings.cplusplus { ".hpp" } else { ".h" };
     let header_path = PathBuf::from(BINDINGS_DIR).join(String::from(base) + suffix);
     let header = header_path.to_str().unwrap();
     let out = PathBuf::from(env::var("OUT_DIR").unwrap()).join(String::from(base) + ".rs");
 
     println!("cargo:rerun-if-changed={}", header);
 
-    let mut builder = Builder::default().header(header).generate_comments(false);
+    let mut builder = Builder::default().header(header);
+    builder = builder.generate_comments(false);
+    builder = builder.derive_debug(false); // https://github.com/rust-lang/rust-bindgen/issues/372
 
     builder = builder.clang_arg("-v");
 
     if !gecko {
         builder = builder.clang_arg("-DNO_NSPR_10_SUPPORT");
         if env::consts::OS == "windows" {
             builder = builder.clang_arg("-DWIN");
         } else if env::consts::OS == "macos" {
--- a/third_party/rust/neqo-crypto/src/agent.rs
+++ b/third_party/rust/neqo-crypto/src/agent.rs
@@ -70,17 +70,17 @@ fn get_alpn(fd: *mut ssl::PRFileDesc, pr
             chosen.truncate(chosen_len as usize);
             Some(match String::from_utf8(chosen) {
                 Ok(a) => a,
                 _ => return Err(Error::InternalError),
             })
         }
         _ => None,
     };
-    qinfo!([format!("{:p}", fd)] "got ALPN {:?}", alpn);
+    qinfo!([format!("{:p}", fd)], "got ALPN {:?}", alpn);
     Ok(alpn)
 }
 
 pub struct SecretAgentPreInfo {
     info: ssl::SSLPreliminaryChannelInfo,
     alpn: Option<String>,
 }
 
@@ -285,17 +285,21 @@ impl SecretAgent {
         let alert = alert.as_ref().unwrap();
         if alert.level == 2 {
             // Fatal alerts demand attention.
             let p = arg as *mut Option<Alert>;
             let st = p.as_mut().unwrap();
             if st.is_none() {
                 *st = Some(alert.description);
             } else {
-                qwarn!([format!("{:p}", fd)] "duplicate alert {}", alert.description);
+                qwarn!(
+                    [format!("{:p}", fd)],
+                    "duplicate alert {}",
+                    alert.description
+                );
             }
         }
     }
 
     // TODO(mt) move to time.rs.
     unsafe extern "C" fn time_func(arg: *mut c_void) -> PRTime {
         let p = arg as *mut PRTime as *const PRTime;
         *p.as_ref().unwrap()
@@ -505,17 +509,17 @@ impl SecretAgent {
     pub fn authenticated(&mut self, status: AuthenticationStatus) {
         assert_eq!(self.state, HandshakeState::AuthenticationPending);
         *self.auth_required = false;
         self.state = HandshakeState::Authenticated(status.into());
     }
 
     fn capture_error<T>(&mut self, res: Res<T>) -> Res<T> {
         if let Err(e) = &res {
-            qwarn!([self] "error: {:?}", e);
+            qwarn!([self], "error: {:?}", e);
             self.state = HandshakeState::Failed(e.clone());
         }
         res
     }
 
     fn update_state(&mut self, res: Res<()>) -> Res<()> {
         self.state = if is_blocked(&res) {
             if *self.auth_required {
@@ -523,17 +527,17 @@ impl SecretAgent {
             } else {
                 HandshakeState::InProgress
             }
         } else {
             self.capture_error(res)?;
             let info = self.capture_error(SecretAgentInfo::new(self.fd))?;
             HandshakeState::Complete(info)
         };
-        qinfo!([self] "state -> {:?}", self.state);
+        qinfo!([self], "state -> {:?}", self.state);
         Ok(())
     }
 
     // Drive the TLS handshake, taking bytes from @input and putting
     // any bytes necessary into @output.
     // This takes the current time as @now.
     // On success a tuple of a HandshakeState and usize indicate whether the handshake
     // is complete and how many bytes were written to @output, respectively.
@@ -577,19 +581,19 @@ impl SecretAgent {
         if self.no_eoed {
             let mut read_epoch: u16 = 0;
             unsafe { ssl::SSL_GetCurrentEpoch(self.fd, &mut read_epoch, null_mut()) }?;
             if read_epoch == 1 {
                 // It's waiting for EndOfEarlyData, so feed one in.
                 // Note that this is the test that ensures that we only do this for the server.
                 let eoed = Record::new(1, 22, END_OF_EARLY_DATA);
                 self.capture_error(eoed.write(self.fd))?;
+                self.no_eoed = false;
             }
         }
-        self.no_eoed = false;
         Ok(())
     }
 
     // Drive the TLS handshake, but get the raw content of records, not
     // protected records as bytes. This function is incompatible with
     // handshake(); use either this or handshake() exclusively.
     //
     // Ideally, this only includes records from the current epoch.
@@ -597,17 +601,17 @@ impl SecretAgent {
     pub fn handshake_raw(&mut self, now: Instant, input: Option<Record>) -> Res<RecordList> {
         *self.now = Time::from(now).try_into()?;
         let mut records = self.setup_raw()?;
 
         // Fire off any authentication we might need to complete.
         if let HandshakeState::Authenticated(ref err) = self.state {
             let result =
                 secstatus_to_res(unsafe { ssl::SSL_AuthCertificateComplete(self.fd, *err) });
-            qdebug!([self] "SSL_AuthCertificateComplete: {:?}", result);
+            qdebug!([self], "SSL_AuthCertificateComplete: {:?}", result);
             // This should return SECSuccess, so don't use update_state().
             self.capture_error(result)?;
         }
 
         // Feed in any records.
         if let Some(rec) = input {
             if rec.epoch == 2 {
                 self.inject_eoed()?;
@@ -674,17 +678,17 @@ impl Client {
         token: *const u8,
         len: c_uint,
         arg: *mut c_void,
     ) -> ssl::SECStatus {
         let resumption_ptr = arg as *mut Option<Vec<u8>>;
         let resumption = resumption_ptr.as_mut().unwrap();
         let mut v = Vec::with_capacity(len as usize);
         v.extend_from_slice(std::slice::from_raw_parts(token, len as usize));
-        qdebug!([format!("{:p}", fd)] "Got resumption token");
+        qdebug!([format!("{:p}", fd)], "Got resumption token");
         *resumption = Some(v);
         ssl::SECSuccess
     }
 
     fn ready(&mut self) -> Res<()> {
         unsafe {
             ssl::SSL_SetResumptionTokenCallback(
                 self.fd,
--- a/third_party/rust/neqo-crypto/src/agentio.rs
+++ b/third_party/rust/neqo-crypto/src/agentio.rs
@@ -172,26 +172,26 @@ impl AgentIoInput {
     fn read_input(&mut self, buf: *mut u8, count: usize) -> Res<usize> {
         let amount = min(self.available, count);
         if amount == 0 {
             unsafe { PR_SetError(nspr::PR_WOULD_BLOCK_ERROR, 0) };
             return Err(Error::NoDataAvailable);
         }
 
         let src = unsafe { std::slice::from_raw_parts(self.input, amount) };
-        qtrace!([self] "read {}", hex(src));
+        qtrace!([self], "read {}", hex(src));
         let dst = unsafe { std::slice::from_raw_parts_mut(buf, amount) };
         dst.copy_from_slice(&src);
         self.input = self.input.wrapping_add(amount);
         self.available -= amount;
         Ok(amount)
     }
 
     fn reset(&mut self) {
-        qtrace!([self] "reset");
+        qtrace!([self], "reset");
         self.input = null();
         self.available = 0;
     }
 }
 
 impl ::std::fmt::Display for AgentIoInput {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "AgentIoInput {:p}", self.input)
@@ -227,22 +227,22 @@ impl AgentIo {
     pub fn wrap<'a: 'c, 'b: 'c, 'c>(&'a mut self, input: &'b [u8]) -> AgentIoInputContext<'c> {
         assert_eq!(self.output.len(), 0);
         self.input.wrap(input)
     }
 
     // Stage output from TLS into the output buffer.
     fn save_output(&mut self, buf: *const u8, count: usize) {
         let slice = unsafe { std::slice::from_raw_parts(buf, count) };
-        qtrace!([self] "save output {}", hex(slice));
+        qtrace!([self], "save output {}", hex(slice));
         self.output.extend_from_slice(slice);
     }
 
     pub fn take_output(&mut self) -> Vec<u8> {
-        qtrace!([self] "take output");
+        qtrace!([self], "take output");
         mem::replace(&mut self.output, Vec::new())
     }
 }
 
 impl ::std::fmt::Display for AgentIo {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "AgentIo")
     }
--- a/third_party/rust/neqo-crypto/src/err.rs
+++ b/third_party/rust/neqo-crypto/src/err.rs
@@ -183,10 +183,9 @@ mod tests {
             Error::NssError { name, code, desc } => {
                 assert_eq!(name, "PR_WOULD_BLOCK_ERROR");
                 assert_eq!(code, -5998);
                 assert_eq!(desc, "The operation would have blocked");
             }
             _ => panic!("bad error type"),
         }
     }
-
 }
--- a/third_party/rust/neqo-http3/.cargo-checksum.json
+++ b/third_party/rust/neqo-http3/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"bde1a1af255191ae9785b8f438fe72addc291496e4fa7d140437de5828aa6d8c","src/client_events.rs":"c7022955c4c7c1257204948a0a2a88ccd895dfdb64b62ff76e56bc989d066277","src/connection.rs":"5a3003fad10db9c92ae5c4728e6944e3fc3433555cd210300908f4bf55eabe4f","src/connection_client.rs":"96395301b0b82aa09f3684b6f8571cab9261a1590565ad67209b71b40f610d81","src/connection_server.rs":"ec6c6182f4522b2c8bddbd441790bc8f07f122c35292dc227779c7a7574d8a43","src/control_stream_local.rs":"8b685d5236ea59914ca91f6bd9613586ede581ca400e54e8f429f9e51580774b","src/control_stream_remote.rs":"94ba2cdeeb1e76e7bab7ed19ef02b9516fb4c13f496a4c8066f92230c62cf083","src/hframe.rs":"15dce78028666c12dbc99e252f3db8e87659da9260fc7bf0d2d182cb9e6d3081","src/lib.rs":"8b5607f7dee014e11771ea05b4ed52fcd1eafe146ee8ebee75da742921867b57","src/server_events.rs":"374b40c645443eae19a0a039f74e3f5353b1a6373c7a3089e9f270db9609596e","src/stream_type_reader.rs":"e96f55f9e1df4e894d4d93250a79a4a46db1669d8c17353b94525db0a75c774e","src/transaction_client.rs":"d2664b0eb6505c6de9ec86d5c422d30576c42896e6bbbf5c907a9fd7e01caecd","src/transaction_server.rs":"9c1eb5a7cc81269a063fa891aeae0fc93bf773f23ead8a177452ea2dc425ff09","tests/httpconn.rs":"7a78d258bb940c88b3b935e4e3c76c103fb4d400ddfad14107b17a15759eb3e9"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"2c3a091954d90040b9d2bc7df2e2e2e2457da21186d69d4fe30fcf4cf3888a66","src/client_events.rs":"c7022955c4c7c1257204948a0a2a88ccd895dfdb64b62ff76e56bc989d066277","src/connection.rs":"30a79c660e6945fd193ab0eb27bf22014c4d246a5ee361aad5a5586e3c03b39f","src/connection_client.rs":"362f4774003c5c3b51eda02e9975943de15d3f244178c208407c62115942e867","src/control_stream_local.rs":"319f8277fc4765b31a4a094bfd663e681d71831532925b0043bae5da96202e64","src/control_stream_remote.rs":"1b96316d6eecc582436382517fcffdb2bb4f9d73194301bc3e2e253d3322e95e","src/hframe.rs":"6e65670cfe5944e88a0631e39d077c8e9d225fde650c978405816f1b2028c9a1","src/lib.rs":"908cb880d6b68c35085b768b67e866d1db0d3212d3bd0e6a76daf0d670b79d1c","src/server.rs":"4819dcfe998f036501b4900ce489c03cc3e24c45ca8825354daff826f7157316","src/server_connection_events.rs":"6ae07ca2c54a8b733a2e4cdd5594838f530224e7bb8233ecd9d7ad0838842bf2","src/server_events.rs":"e0a19bfc88b91d0584c1ec08da3005aae192471cbc37809a977dd6098f4e7dcc","src/stream_type_reader.rs":"be1ea1f553292b5447f0d6d89bdfa73732189db236ce34b4067cda0276229540","src/transaction_client.rs":"2e4a2ca83bdc6583697ab5b6e8c2767b4fd46fd4215f4fe9cf79891ad5523bd6","src/transaction_server.rs":"98ba7522fb20936e056cce2bbd1098ee94e748a58e7b4609772c87c349b12d85","tests/httpconn.rs":"7955f6ac4406b5d770e0fb10258aff529a1c01020374dfc5f85d8608abb68f6f"},"package":null}
\ No newline at end of file
--- a/third_party/rust/neqo-http3/Cargo.toml
+++ b/third_party/rust/neqo-http3/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "neqo-http3"
-version = "0.1.4"
+version = "0.1.6"
 authors = ["draganadamjanovic"]
 edition = "2018"
 license = "MIT/Apache-2.0"
 
 [dependencies]
 neqo-common = { path = "./../neqo-common" }
 neqo-crypto = { path = "./../neqo-crypto" }
 neqo-transport = { path = "./../neqo-transport" }
--- a/third_party/rust/neqo-http3/src/connection.rs
+++ b/third_party/rust/neqo-http3/src/connection.rs
@@ -3,34 +3,27 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 use crate::client_events::Http3ClientEvents;
 use crate::control_stream_local::{ControlStreamLocal, HTTP3_UNI_STREAM_TYPE_CONTROL};
 use crate::control_stream_remote::ControlStreamRemote;
 use crate::hframe::{HFrame, HSettingType};
-use crate::server_events::Http3ServerEvents;
+use crate::server_connection_events::Http3ServerConnEvents;
 use crate::stream_type_reader::NewStreamTypeReader;
 use crate::transaction_client::TransactionClient;
 use crate::transaction_server::TransactionServer;
-use neqo_common::{matches, qdebug, qerror, qinfo, qtrace, qwarn, Datagram};
-use neqo_crypto::AntiReplay;
+use neqo_common::{matches, qdebug, qerror, qinfo, qtrace, qwarn};
 use neqo_qpack::decoder::{QPackDecoder, QPACK_UNI_STREAM_TYPE_DECODER};
 use neqo_qpack::encoder::{QPackEncoder, QPACK_UNI_STREAM_TYPE_ENCODER};
-use neqo_transport::{
-    AppError, CloseError, Connection, ConnectionEvent, ConnectionIdManager, Output, Role, State,
-    StreamType,
-};
-use std::cell::RefCell;
+use neqo_transport::{AppError, CloseError, Connection, ConnectionEvent, State, StreamType};
 use std::collections::{BTreeSet, HashMap};
 use std::fmt::Debug;
 use std::mem;
-use std::net::SocketAddr;
-use std::rc::Rc;
 use std::time::Instant;
 
 use crate::{Error, Res};
 
 const HTTP3_UNI_STREAM_TYPE_PUSH: u64 = 0x1;
 
 const MAX_HEADER_LIST_SIZE_DEFAULT: u64 = u64::max_value();
 
@@ -90,19 +83,19 @@ pub trait Http3Handler<E: Http3Events, T
 pub enum Http3State {
     Initializing,
     Connected,
     GoingAway,
     Closing(CloseError),
     Closed(CloseError),
 }
 
+#[derive(Debug)]
 pub struct Http3Connection<E: Http3Events, T: Http3Transaction, H: Http3Handler<E, T>> {
     pub state: Http3State,
-    pub conn: Connection,
     max_header_list_size: u64,
     control_stream_local: ControlStreamLocal,
     control_stream_remote: ControlStreamRemote,
     new_streams: HashMap<u64, NewStreamTypeReader>,
     pub qpack_encoder: QPackEncoder,
     pub qpack_decoder: QPackDecoder,
     settings_received: bool,
     streams_have_data_to_send: BTreeSet<u64>,
@@ -110,263 +103,185 @@ pub struct Http3Connection<E: Http3Event
     pub transactions: HashMap<u64, T>,
     handler: H,
 }
 
 impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>> ::std::fmt::Display
     for Http3Connection<E, T, H>
 {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
-        write!(f, "Http3 connection {:?}", self.role())
+        write!(f, "Http3 connection")
     }
 }
 
 impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
     Http3Connection<E, T, H>
 {
-    pub fn new_client(
-        server_name: &str,
-        protocols: &[impl AsRef<str>],
-        cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
-        local_addr: SocketAddr,
-        remote_addr: SocketAddr,
-        max_table_size: u32,
-        max_blocked_streams: u16,
-    ) -> Res<Self> {
+    pub fn new(max_table_size: u32, max_blocked_streams: u16) -> Self {
         if max_table_size > (1 << 30) - 1 {
             panic!("Wrong max_table_size");
         }
-        let conn =
-            Connection::new_client(server_name, protocols, cid_manager, local_addr, remote_addr)?;
-        Http3Connection::new_client_with_conn(conn, max_table_size, max_blocked_streams)
-    }
-
-    pub fn new_client_with_conn(
-        c: Connection,
-        max_table_size: u32,
-        max_blocked_streams: u16,
-    ) -> Res<Self> {
-        if max_table_size > (1 << 30) - 1 {
-            panic!("Wrong max_table_size");
-        }
-        Ok(Http3Connection {
+        Http3Connection {
             state: Http3State::Initializing,
-            conn: c,
             max_header_list_size: MAX_HEADER_LIST_SIZE_DEFAULT,
             control_stream_local: ControlStreamLocal::default(),
             control_stream_remote: ControlStreamRemote::new(),
             new_streams: HashMap::new(),
             qpack_encoder: QPackEncoder::new(true),
             qpack_decoder: QPackDecoder::new(max_table_size, max_blocked_streams),
             settings_received: false,
             streams_have_data_to_send: BTreeSet::new(),
             events: E::default(),
             transactions: HashMap::new(),
             handler: H::new(),
-        })
+        }
     }
 
-    pub fn new_server(
-        certs: &[impl AsRef<str>],
-        protocols: &[impl AsRef<str>],
-        anti_replay: &AntiReplay,
-        cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
-        max_table_size: u32,
-        max_blocked_streams: u16,
-    ) -> Res<Self> {
-        if max_table_size > (1 << 30) - 1 {
-            panic!("Wrong max_table_size");
-        }
-        Ok(Http3Connection {
-            state: Http3State::Initializing,
-            conn: Connection::new_server(certs, protocols, anti_replay, cid_manager)?,
-            max_header_list_size: MAX_HEADER_LIST_SIZE_DEFAULT,
-            control_stream_local: ControlStreamLocal::default(),
-            control_stream_remote: ControlStreamRemote::new(),
-            new_streams: HashMap::new(),
-            qpack_encoder: QPackEncoder::new(true),
-            qpack_decoder: QPackDecoder::new(max_table_size, max_blocked_streams),
-            settings_received: false,
-            streams_have_data_to_send: BTreeSet::new(),
-            events: E::default(),
-            transactions: HashMap::new(),
-            handler: H::new(),
-        })
-    }
+    fn initialize_http3_connection(&mut self, conn: &mut Connection) -> Res<()> {
+        qinfo!([self], "Initialize the http3 connection.");
+        self.control_stream_local.create(conn)?;
 
-    fn initialize_http3_connection(&mut self) -> Res<()> {
-        qinfo!([self] "Initialize the http3 connection.");
-        self.control_stream_local.create(&mut self.conn)?;
         self.send_settings();
-        self.create_qpack_streams()?;
+        self.create_qpack_streams(conn)?;
         Ok(())
     }
 
     fn send_settings(&mut self) {
-        qdebug!([self] "Send settings.");
+        qdebug!([self], "Send settings.");
         self.control_stream_local.queue_frame(HFrame::Settings {
             settings: vec![
                 (
                     HSettingType::MaxTableSize,
                     self.qpack_decoder.get_max_table_size().into(),
                 ),
                 (
                     HSettingType::BlockedStreams,
                     self.qpack_decoder.get_blocked_streams().into(),
                 ),
             ],
         });
     }
 
-    fn create_qpack_streams(&mut self) -> Res<()> {
-        qdebug!([self] "create_qpack_streams.");
+    fn create_qpack_streams(&mut self, conn: &mut Connection) -> Res<()> {
+        qdebug!([self], "create_qpack_streams.");
         self.qpack_encoder
-            .add_send_stream(self.conn.stream_create(StreamType::UniDi)?);
+            .add_send_stream(conn.stream_create(StreamType::UniDi)?);
         self.qpack_decoder
-            .add_send_stream(self.conn.stream_create(StreamType::UniDi)?);
+            .add_send_stream(conn.stream_create(StreamType::UniDi)?);
         Ok(())
     }
 
     // This function takes the provided result and check for an error.
     // An error results in closing the connection.
-    fn check_result<ERR>(&mut self, now: Instant, res: Res<ERR>) -> bool {
+    fn check_result<ERR>(&mut self, conn: &mut Connection, now: Instant, res: Res<ERR>) -> bool {
         match &res {
             Err(e) => {
-                qinfo!([self] "Connection error: {}.", e);
-                self.close(now, e.code(), &format!("{}", e));
+                qinfo!([self], "Connection error: {}.", e);
+                self.close(conn, now, e.code(), &format!("{}", e));
+                self.events
+                    .connection_state_change(Http3State::Closing(CloseError::Application(
+                        e.code(),
+                    )));
                 true
             }
             _ => false,
         }
     }
 
-    pub fn role(&self) -> Role {
-        self.conn.role()
-    }
-
-    pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
-        qtrace!([self] "Process.");
-        if let Some(d) = dgram {
-            self.process_input(d, now);
-        }
-        self.process_http3(now);
-        self.process_output(now)
-    }
-
-    pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
-        qtrace!([self] "Process input.");
-        self.conn.process_input(dgram, now);
-    }
-
-    pub fn process_timer(&mut self, now: Instant) {
-        qtrace!([self] "Process timer.");
-        self.conn.process_timer(now);
-    }
-
-    pub fn conn(&mut self) -> &mut Connection {
-        &mut self.conn
-    }
-
-    pub fn process_http3(&mut self, now: Instant) {
-        qtrace!([self] "Process http3 internal.");
+    pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) {
+        qtrace!([self], "Process http3 internal.");
         match self.state {
             Http3State::Connected | Http3State::GoingAway => {
-                let res = self.check_connection_events();
-                if self.check_result(now, res) {
+                let res = self.check_connection_events(conn);
+                if self.check_result(conn, now, res) {
                     return;
                 }
-                let res = self.process_sending();
-                self.check_result(now, res);
+                let res = self.process_sending(conn);
+                self.check_result(conn, now, res);
             }
             Http3State::Closed { .. } => {}
             _ => {
-                let res = self.check_connection_events();
-                let _ = self.check_result(now, res);
+                let res = self.check_connection_events(conn);
+                let _ = self.check_result(conn, now, res);
             }
         }
     }
 
-    pub fn process_output(&mut self, now: Instant) -> Output {
-        qtrace!([self] "Process output.");
-        self.conn.process_output(now)
-    }
-
-    pub fn stream_stop_sending(&mut self, stream_id: u64, app_error: AppError) -> Res<()> {
-        self.conn.stream_stop_sending(stream_id, app_error)?;
-        Ok(())
-    }
-
     pub fn insert_streams_have_data_to_send(&mut self, stream_id: u64) {
         self.streams_have_data_to_send.insert(stream_id);
     }
 
-    fn process_sending(&mut self) -> Res<()> {
+    pub fn has_data_to_send(&self) -> bool {
+        !self.streams_have_data_to_send.is_empty()
+    }
+
+    fn process_sending(&mut self, conn: &mut Connection) -> Res<()> {
         // check if control stream has data to send.
-        self.control_stream_local.send(&mut self.conn)?;
+        self.control_stream_local.send(conn)?;
 
         let to_send = mem::replace(&mut self.streams_have_data_to_send, BTreeSet::new());
         for stream_id in to_send {
             if let Some(t) = &mut self.transactions.get_mut(&stream_id) {
-                t.send(&mut self.conn, &mut self.qpack_encoder)?;
+                t.send(conn, &mut self.qpack_encoder)?;
                 if t.has_data_to_send() {
                     self.streams_have_data_to_send.insert(stream_id);
                 }
             }
         }
-        self.qpack_decoder.send(&mut self.conn)?;
-        self.qpack_encoder.send(&mut self.conn)?;
+        self.qpack_decoder.send(conn)?;
+        self.qpack_encoder.send(conn)?;
         Ok(())
     }
 
     // If this return an error the connection must be closed.
-    fn check_connection_events(&mut self) -> Res<()> {
-        qtrace!([self] "Check connection events.");
-        while let Some(e) = self.conn.next_event() {
-            qdebug!([self] "check_connection_events - event {:?}.", e);
+    fn check_connection_events(&mut self, conn: &mut Connection) -> Res<()> {
+        qtrace!([self], "Check connection events.");
+        while let Some(e) = conn.next_event() {
+            qdebug!([self], "check_connection_events - event {:?}.", e);
             match e {
                 ConnectionEvent::NewStream {
                     stream_id,
                     stream_type,
-                } => self.handle_new_stream(stream_id, stream_type)?,
+                } => self.handle_new_stream(conn, stream_id, stream_type)?,
                 ConnectionEvent::SendStreamWritable { stream_id } => {
                     self.handler.handle_send_stream_writable(
                         &mut self.transactions,
                         &mut self.events,
                         stream_id,
                     )?
                 }
                 ConnectionEvent::RecvStreamReadable { stream_id } => {
-                    self.handle_stream_readable(stream_id)?
+                    self.handle_stream_readable(conn, stream_id)?
                 }
                 ConnectionEvent::RecvStreamReset {
                     stream_id,
                     app_error,
-                } => self.handle_stream_reset(stream_id, app_error)?,
+                } => self.handle_stream_reset(conn, stream_id, app_error)?,
                 ConnectionEvent::SendStreamStopSending {
                     stream_id,
                     app_error,
                 } => self.handler.handle_stream_stop_sending(
                     &mut self.transactions,
                     &mut self.events,
-                    &mut self.conn,
+                    conn,
                     stream_id,
                     app_error,
                 )?,
                 ConnectionEvent::SendStreamComplete { stream_id } => {
                     self.handle_stream_complete(stream_id)?
                 }
                 ConnectionEvent::SendStreamCreatable { stream_type } => self
                     .handler
                     .handle_stream_creatable(&mut self.events, stream_type)?,
                 ConnectionEvent::AuthenticationNeeded => self
                     .handler
                     .handle_authentication_needed(&mut self.events)?,
                 ConnectionEvent::StateChange(state) => {
                     match state {
-                        State::Connected => self.handle_connection_connected()?,
+                        State::Connected => self.handle_connection_connected(conn)?,
                         State::Closing { error, .. } => {
                             self.handle_connection_closing(error.clone().into())?
                         }
                         State::Closed(error) => {
                             self.handle_connection_closed(error.clone().into())?
                         }
                         _ => {}
                     };
@@ -375,153 +290,165 @@ impl<E: Http3Events + Default, T: Http3T
                     // TODO(mt) work out what to do here.
                     // Everything will have to be redone: SETTINGS, qpack streams, and requests.
                 }
             }
         }
         Ok(())
     }
 
-    fn handle_new_stream(&mut self, stream_id: u64, stream_type: StreamType) -> Res<()> {
-        qinfo!([self] "A new stream: {:?} {}.", stream_type, stream_id);
+    fn handle_new_stream(
+        &mut self,
+        conn: &mut Connection,
+        stream_id: u64,
+        stream_type: StreamType,
+    ) -> Res<()> {
+        qinfo!([self], "A new stream: {:?} {}.", stream_type, stream_id);
         assert!(self.state_active());
         match stream_type {
             StreamType::BiDi => self.handler.handle_new_bidi_stream(
                 &mut self.transactions,
                 &mut self.events,
                 stream_id,
             ),
             StreamType::UniDi => {
                 let stream_type;
                 let fin;
                 {
                     let ns = &mut self
                         .new_streams
                         .entry(stream_id)
                         .or_insert_with(NewStreamTypeReader::new);
-                    stream_type = ns.get_type(&mut self.conn, stream_id);
+                    stream_type = ns.get_type(conn, stream_id);
                     fin = ns.fin();
                 }
 
                 if fin {
                     self.new_streams.remove(&stream_id);
                     Ok(())
                 } else if let Some(t) = stream_type {
-                    self.decode_new_stream(t, stream_id)?;
+                    self.decode_new_stream(conn, t, stream_id)?;
                     self.new_streams.remove(&stream_id);
                     Ok(())
                 } else {
                     Ok(())
                 }
             }
         }
     }
 
-    fn handle_stream_readable(&mut self, stream_id: u64) -> Res<()> {
-        qtrace!([self] "Readable stream {}.", stream_id);
+    fn handle_stream_readable(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
+        qtrace!([self], "Readable stream {}.", stream_id);
 
         assert!(self.state_active());
 
         let label = if ::log::log_enabled!(::log::Level::Debug) {
             format!("{}", self)
         } else {
             String::new()
         };
         let mut unblocked_streams: Vec<u64> = Vec::new();
 
-        if self.handle_read_stream(stream_id)? {
-            qdebug!([label] "Request/response stream {} read.", stream_id);
+        if self.handle_read_stream(conn, stream_id)? {
+            qdebug!([label], "Request/response stream {} read.", stream_id);
         } else if self
             .control_stream_remote
-            .receive_if_this_stream(&mut self.conn, stream_id)?
+            .receive_if_this_stream(conn, stream_id)?
         {
             qdebug!(
-                [self]
+                [self],
                 "The remote control stream ({}) is readable.",
                 stream_id
             );
             while self.control_stream_remote.frame_reader_done()
                 || self.control_stream_remote.recvd_fin()
             {
                 self.handle_control_frame()?;
                 self.control_stream_remote
-                    .receive_if_this_stream(&mut self.conn, stream_id)?;
+                    .receive_if_this_stream(conn, stream_id)?;
             }
-        } else if self
-            .qpack_encoder
-            .recv_if_encoder_stream(&mut self.conn, stream_id)?
-        {
+        } else if self.qpack_encoder.recv_if_encoder_stream(conn, stream_id)? {
             qdebug!(
-                [self]
+                [self],
                 "The qpack encoder stream ({}) is readable.",
                 stream_id
             );
         } else if self.qpack_decoder.is_recv_stream(stream_id) {
             qdebug!(
-                [self]
+                [self],
                 "The qpack decoder stream ({}) is readable.",
                 stream_id
             );
-            unblocked_streams = self.qpack_decoder.receive(&mut self.conn, stream_id)?;
+            unblocked_streams = self.qpack_decoder.receive(conn, stream_id)?;
         } else if let Some(ns) = self.new_streams.get_mut(&stream_id) {
-            let stream_type = ns.get_type(&mut self.conn, stream_id);
+            let stream_type = ns.get_type(conn, stream_id);
             let fin = ns.fin();
             if fin {
                 self.new_streams.remove(&stream_id);
             }
             if let Some(t) = stream_type {
-                self.decode_new_stream(t, stream_id)?;
+                self.decode_new_stream(conn, t, stream_id)?;
                 self.new_streams.remove(&stream_id);
             }
         } else {
             // For a new stream we receive NewStream event and a
             // RecvStreamReadable event.
             // In most cases we decode a new stream already on the NewStream
             // event and remove it from self.new_streams.
             // Therefore, while processing RecvStreamReadable there will be no
             // entry for the stream in self.new_streams.
             qdebug!("Unknown stream.");
         }
 
         for stream_id in unblocked_streams {
-            qinfo!([self] "Stream {} is unblocked", stream_id);
-            self.handle_read_stream(stream_id)?;
+            qinfo!([self], "Stream {} is unblocked", stream_id);
+            self.handle_read_stream(conn, stream_id)?;
         }
         Ok(())
     }
 
-    fn handle_stream_reset(&mut self, stream_id: u64, app_err: AppError) -> Res<()> {
-        qinfo!([self] "Handle a stream reset stream_id={} app_err={}", stream_id, app_err);
+    fn handle_stream_reset(
+        &mut self,
+        conn: &mut Connection,
+        stream_id: u64,
+        app_err: AppError,
+    ) -> Res<()> {
+        qinfo!(
+            [self],
+            "Handle a stream reset stream_id={} app_err={}",
+            stream_id,
+            app_err
+        );
 
         assert!(self.state_active());
 
         if let Some(t) = self.transactions.get_mut(&stream_id) {
             // Post the reset event.
             self.events.reset(stream_id, app_err);
             // Close both sides of the transaction_client.
             t.reset_receiving_side();
             t.stop_sending();
             // close sending side of the transport stream as well. The server may have done
             // it se well, but just to be sure.
-            let _ = self.conn.stream_reset_send(stream_id, app_err);
+            let _ = conn.stream_reset_send(stream_id, app_err);
             // remove the stream
             self.transactions.remove(&stream_id);
         }
         Ok(())
     }
 
     fn handle_stream_complete(&mut self, _stream_id: u64) -> Res<()> {
         Ok(())
     }
 
-    fn handle_connection_connected(&mut self) -> Res<()> {
+    fn handle_connection_connected(&mut self, conn: &mut Connection) -> Res<()> {
         assert_eq!(self.state, Http3State::Initializing);
         self.events.connection_state_change(Http3State::Connected);
         self.state = Http3State::Connected;
-        self.initialize_http3_connection()
+        self.initialize_http3_connection(conn)
     }
 
     fn handle_connection_closing(&mut self, error_code: CloseError) -> Res<()> {
         assert!(self.state_active() || self.state_closing());
         self.events
             .connection_state_change(Http3State::Closing(error_code));
         self.state = Http3State::Closing(error_code);
         Ok(())
@@ -529,133 +456,147 @@ impl<E: Http3Events + Default, T: Http3T
 
     fn handle_connection_closed(&mut self, error_code: CloseError) -> Res<()> {
         self.events
             .connection_state_change(Http3State::Closed(error_code));
         self.state = Http3State::Closed(error_code);
         Ok(())
     }
 
-    fn handle_read_stream(&mut self, stream_id: u64) -> Res<bool> {
+    fn handle_read_stream(&mut self, conn: &mut Connection, stream_id: u64) -> Res<bool> {
         let label = if ::log::log_enabled!(::log::Level::Debug) {
             format!("{}", self)
         } else {
             String::new()
         };
 
         assert!(self.state_active());
 
         if let Some(transaction) = &mut self.transactions.get_mut(&stream_id) {
-            qinfo!([label] "Request/response stream {} is readable.", stream_id);
-            match transaction.receive(&mut self.conn, &mut self.qpack_decoder) {
+            qinfo!(
+                [label],
+                "Request/response stream {} is readable.",
+                stream_id
+            );
+            match transaction.receive(conn, &mut self.qpack_decoder) {
                 Err(e) => {
-                    qerror!([label] "Error {} ocurred", e);
+                    qerror!([label], "Error {} ocurred", e);
                     return Err(e);
                 }
                 Ok(()) => {
                     if transaction.done() {
                         self.transactions.remove(&stream_id);
                     }
                 }
             }
             Ok(true)
         } else {
             Ok(false)
         }
     }
 
-    fn decode_new_stream(&mut self, stream_type: u64, stream_id: u64) -> Res<()> {
+    fn decode_new_stream(
+        &mut self,
+        conn: &mut Connection,
+        stream_type: u64,
+        stream_id: u64,
+    ) -> Res<()> {
         match stream_type {
             HTTP3_UNI_STREAM_TYPE_CONTROL => {
                 self.control_stream_remote.add_remote_stream(stream_id)?;
                 Ok(())
             }
 
             HTTP3_UNI_STREAM_TYPE_PUSH => {
-                qinfo!([self] "A new push stream {}.", stream_id);
+                qinfo!([self], "A new push stream {}.", stream_id);
                 self.handler.handle_new_push_stream()
             }
             QPACK_UNI_STREAM_TYPE_ENCODER => {
-                qinfo!([self] "A new remote qpack encoder stream {}", stream_id);
+                qinfo!([self], "A new remote qpack encoder stream {}", stream_id);
                 self.qpack_decoder
                     .add_recv_stream(stream_id)
                     .map_err(|_| Error::HttpStreamCreationError)
             }
             QPACK_UNI_STREAM_TYPE_DECODER => {
-                qinfo!([self] "A new remote qpack decoder stream {}", stream_id);
+                qinfo!([self], "A new remote qpack decoder stream {}", stream_id);
                 self.qpack_encoder
                     .add_recv_stream(stream_id)
                     .map_err(|_| Error::HttpStreamCreationError)
             }
             // TODO reserved stream types
             _ => {
-                self.conn
-                    .stream_stop_sending(stream_id, Error::HttpStreamCreationError.code())?;
+                conn.stream_stop_sending(stream_id, Error::HttpStreamCreationError.code())?;
                 Ok(())
             }
         }
     }
 
-    pub fn close(&mut self, now: Instant, error: AppError, msg: &str) {
-        qinfo!([self] "Close connection error {:?} msg={}.", error, msg);
-        assert!(self.state_active());
-        self.state = Http3State::Closing(CloseError::Application(error));
-        if !self.transactions.is_empty() && (error == 0) {
-            qwarn!("close() called when streams still active");
+    pub fn close(&mut self, conn: &mut Connection, now: Instant, error: AppError, msg: &str) {
+        qinfo!([self], "Close connection error {:?} msg={}.", error, msg);
+        if !matches!(self.state, Http3State::Closing(_) | Http3State::Closed(_)) {
+            self.state = Http3State::Closing(CloseError::Application(error));
+            if !self.transactions.is_empty() && (error == 0) {
+                qwarn!("close() called when streams still active");
+            }
+            self.transactions.clear();
+            conn.close(now, error, msg);
         }
-        self.transactions.clear();
-        self.conn.close(now, error, msg);
     }
 
-    pub fn stream_reset(&mut self, stream_id: u64, error: AppError) -> Res<()> {
-        qinfo!([self] "Reset stream {} error={}.", stream_id, error);
+    pub fn stream_reset(
+        &mut self,
+        conn: &mut Connection,
+        stream_id: u64,
+        error: AppError,
+    ) -> Res<()> {
+        qinfo!([self], "Reset stream {} error={}.", stream_id, error);
         assert!(self.state_active());
         let mut transaction = self
             .transactions
             .remove(&stream_id)
             .ok_or(Error::InvalidStreamId)?;
         transaction.stop_sending();
         // Stream maybe already be closed and we may get an error here, but we do not care.
-        let _ = self.conn.stream_reset_send(stream_id, error);
+        let _ = conn.stream_reset_send(stream_id, error);
         transaction.reset_receiving_side();
         // Stream maybe already be closed and we may get an error here, but we do not care.
-        self.conn.stream_stop_sending(stream_id, error)?;
+        conn.stream_stop_sending(stream_id, error)?;
         self.events.remove_events_for_stream_id(stream_id);
         Ok(())
     }
 
-    pub fn stream_close_send(&mut self, stream_id: u64) -> Res<()> {
-        qinfo!([self] "Close sending side for stream {}.", stream_id);
+    pub fn stream_close_send(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
+        qinfo!([self], "Close sending side for stream {}.", stream_id);
         assert!(self.state_active());
         let transaction = self
             .transactions
             .get_mut(&stream_id)
             .ok_or(Error::InvalidStreamId)?;
-        transaction.close_send(&mut self.conn)?;
+        transaction.close_send(conn)?;
         if transaction.done() {
             self.transactions.remove(&stream_id);
         }
         Ok(())
     }
 
     fn handle_control_frame(&mut self) -> Res<()> {
         if self.control_stream_remote.recvd_fin() {
             return Err(Error::HttpClosedCriticalStream);
         }
         if self.control_stream_remote.frame_reader_done() {
             let f = self.control_stream_remote.get_frame()?;
-            qinfo!([self] "Handle a control frame {:?}", f);
+            qinfo!([self], "Handle a control frame {:?}", f);
             if let HFrame::Settings { .. } = f {
                 if self.settings_received {
-                    qerror!([self] "SETTINGS frame already received");
+                    qerror!([self], "SETTINGS frame already received");
                     return Err(Error::HttpFrameUnexpected);
                 }
                 self.settings_received = true;
             } else if !self.settings_received {
-                qerror!([self] "SETTINGS frame not received");
+                qerror!([self], "SETTINGS frame not received");
                 return Err(Error::HttpMissingSettings);
             }
             return match f {
                 HFrame::Settings { settings } => {
                     self.handle_settings(&settings)?;
                     Ok(())
                 }
                 HFrame::CancelPush { .. } => Err(Error::HttpFrameUnexpected),
@@ -668,37 +609,34 @@ impl<E: Http3Events + Default, T: Http3T
                 HFrame::MaxPushId { push_id } => self.handler.handle_max_push_id(push_id),
                 _ => Err(Error::HttpFrameUnexpected),
             };
         }
         Ok(())
     }
 
     fn handle_settings(&mut self, s: &[(HSettingType, u64)]) -> Res<()> {
-        qinfo!([self] "Handle SETTINGS frame.");
+        qinfo!([self], "Handle SETTINGS frame.");
         for (t, v) in s {
-            qinfo!([self] " {:?} = {:?}", t, v);
+            qinfo!([self], " {:?} = {:?}", t, v);
             match t {
                 HSettingType::MaxHeaderListSize => {
                     self.max_header_list_size = *v;
                 }
                 HSettingType::MaxTableSize => self.qpack_encoder.set_max_capacity(*v)?,
                 HSettingType::BlockedStreams => self.qpack_encoder.set_max_blocked_streams(*v)?,
 
                 _ => {}
             }
         }
         Ok(())
     }
 
     fn state_active(&self) -> bool {
-        match self.state {
-            Http3State::Connected | Http3State::GoingAway => true,
-            _ => false,
-        }
+        matches!(self.state, Http3State::Connected | Http3State::GoingAway)
     }
 
     fn state_closing(&self) -> bool {
         matches!(self.state, Http3State::Closing(_))
     }
 
     pub fn state(&self) -> Http3State {
         self.state.clone()
@@ -726,17 +664,17 @@ impl Http3Handler<Http3ClientEvents, Tra
         stream_type: StreamType,
     ) -> Res<()> {
         events.new_requests_creatable(stream_type);
         Ok(())
     }
 
     fn handle_new_push_stream(&mut self) -> Res<()> {
         // TODO implement PUSH
-        qerror!([self] "PUSH is not implemented!");
+        qerror!([self], "PUSH is not implemented!");
         Err(Error::HttpIdError)
     }
 
     fn handle_new_bidi_stream(
         &mut self,
         _transactions: &mut HashMap<u64, TransactionClient>,
         _events: &mut Http3ClientEvents,
         _stream_id: u64,
@@ -746,17 +684,17 @@ impl Http3Handler<Http3ClientEvents, Tra
     }
 
     fn handle_send_stream_writable(
         &mut self,
         transactions: &mut HashMap<u64, TransactionClient>,
         events: &mut Http3ClientEvents,
         stream_id: u64,
     ) -> Res<()> {
-        qtrace!([self] "Writable stream {}.", stream_id);
+        qtrace!([self], "Writable stream {}.", stream_id);
 
         if let Some(t) = transactions.get_mut(&stream_id) {
             if t.is_state_sending_data() {
                 events.data_writable(stream_id);
             }
         }
         Ok(())
     }
@@ -764,17 +702,22 @@ impl Http3Handler<Http3ClientEvents, Tra
     fn handle_stream_stop_sending(
         &mut self,
         transactions: &mut HashMap<u64, TransactionClient>,
         events: &mut Http3ClientEvents,
         conn: &mut Connection,
         stop_stream_id: u64,
         app_err: AppError,
     ) -> Res<()> {
-        qinfo!([self] "Handle stream_stop_sending stream_id={} app_err={}", stop_stream_id, app_err);
+        qinfo!(
+            [self],
+            "Handle stream_stop_sending stream_id={} app_err={}",
+            stop_stream_id,
+            app_err
+        );
 
         if let Some(t) = transactions.get_mut(&stop_stream_id) {
             // close sending side.
             t.stop_sending();
 
             // If error is Error::EarlyResponse we will post StopSending event,
             // otherwise post reset.
             if app_err == Error::HttpEarlyResponse.code() && !t.is_sending_closed() {
@@ -797,17 +740,17 @@ impl Http3Handler<Http3ClientEvents, Tra
 
     fn handle_goaway(
         &mut self,
         transactions: &mut HashMap<u64, TransactionClient>,
         events: &mut Http3ClientEvents,
         state: &mut Http3State,
         goaway_stream_id: u64,
     ) -> Res<()> {
-        qinfo!([self] "handle_goaway");
+        qinfo!([self], "handle_goaway");
         // Issue reset events for streams >= goaway stream id
         for id in transactions
             .iter()
             .filter(|(id, _)| **id >= goaway_stream_id)
             .map(|(id, _)| *id)
         {
             events.reset(id, Error::HttpRequestRejected.code())
         }
@@ -818,101 +761,101 @@ impl Http3Handler<Http3ClientEvents, Tra
 
         if *state == Http3State::Connected {
             *state = Http3State::GoingAway;
         }
         Ok(())
     }
 
     fn handle_max_push_id(&mut self, stream_id: u64) -> Res<()> {
-        qerror!([self] "handle_max_push_id={}.", stream_id);
+        qerror!([self], "handle_max_push_id={}.", stream_id);
         Err(Error::HttpFrameUnexpected)
     }
 
     fn handle_authentication_needed(&self, events: &mut Http3ClientEvents) -> Res<()> {
         events.authentication_needed();
         Ok(())
     }
 }
 
 impl ::std::fmt::Display for Http3ClientHandler {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "Http3 connection client")
     }
 }
 
-#[derive(Default)]
+#[derive(Default, Debug)]
 pub struct Http3ServerHandler {}
 
-impl Http3Handler<Http3ServerEvents, TransactionServer> for Http3ServerHandler {
+impl Http3Handler<Http3ServerConnEvents, TransactionServer> for Http3ServerHandler {
     fn new() -> Self {
         Http3ServerHandler::default()
     }
 
     fn handle_stream_creatable(
         &mut self,
-        _events: &mut Http3ServerEvents,
+        _events: &mut Http3ServerConnEvents,
         _stream_type: StreamType,
     ) -> Res<()> {
         Ok(())
     }
 
     fn handle_new_push_stream(&mut self) -> Res<()> {
-        qerror!([self] "Error: server receives a push stream!");
+        qerror!([self], "Error: server receives a push stream!");
         Err(Error::HttpStreamCreationError)
     }
 
     fn handle_new_bidi_stream(
         &mut self,
         transactions: &mut HashMap<u64, TransactionServer>,
-        events: &mut Http3ServerEvents,
+        events: &mut Http3ServerConnEvents,
         stream_id: u64,
     ) -> Res<()> {
         transactions.insert(stream_id, TransactionServer::new(stream_id, events.clone()));
         Ok(())
     }
 
     fn handle_send_stream_writable(
         &mut self,
         _transactions: &mut HashMap<u64, TransactionServer>,
-        _events: &mut Http3ServerEvents,
+        _events: &mut Http3ServerConnEvents,
         _stream_id: u64,
     ) -> Res<()> {
         Ok(())
     }
 
     fn handle_goaway(
         &mut self,
         _transactions: &mut HashMap<u64, TransactionServer>,
-        _events: &mut Http3ServerEvents,
+        _events: &mut Http3ServerConnEvents,
         _state: &mut Http3State,
         _goaway_stream_id: u64,
     ) -> Res<()> {
-        qerror!([self] "handle_goaway");
+        qerror!([self], "handle_goaway");
         Err(Error::HttpFrameUnexpected)
     }
 
     fn handle_stream_stop_sending(
         &mut self,
         _transactions: &mut HashMap<u64, TransactionServer>,
-        _events: &mut Http3ServerEvents,
+        _events: &mut Http3ServerConnEvents,
         _conn: &mut Connection,
         _stop_stream_id: u64,
         _app_err: AppError,
     ) -> Res<()> {
         Ok(())
     }
 
     fn handle_max_push_id(&mut self, stream_id: u64) -> Res<()> {
-        qinfo!([self] "handle_max_push_id={}.", stream_id);
+        qinfo!([self], "handle_max_push_id={}.", stream_id);
         // TODO
         Ok(())
     }
 
-    fn handle_authentication_needed(&self, _events: &mut Http3ServerEvents) -> Res<()> {
+    fn handle_authentication_needed(&self, _events: &mut Http3ServerConnEvents) -> Res<()> {
         Err(Error::HttpInternalError)
     }
 }
 
 impl ::std::fmt::Display for Http3ServerHandler {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "Http3 connection server")
     }
--- a/third_party/rust/neqo-http3/src/connection_client.rs
+++ b/third_party/rust/neqo-http3/src/connection_client.rs
@@ -15,141 +15,145 @@ use neqo_transport::{AppError, Connectio
 use std::cell::RefCell;
 use std::net::SocketAddr;
 use std::rc::Rc;
 use std::time::Instant;
 
 use crate::{Error, Res};
 
 pub struct Http3Client {
+    conn: Connection,
     base_handler: Http3Connection<Http3ClientEvents, TransactionClient, Http3ClientHandler>,
 }
 
 impl ::std::fmt::Display for Http3Client {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
-        write!(f, "Http3 connection {:?}", self.role())
+        write!(f, "Http3 client")
     }
 }
 
 impl Http3Client {
     pub fn new(
         server_name: &str,
         protocols: &[impl AsRef<str>],
         cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
         local_addr: SocketAddr,
         remote_addr: SocketAddr,
         max_table_size: u32,
         max_blocked_streams: u16,
     ) -> Res<Http3Client> {
         Ok(Http3Client {
-            base_handler: Http3Connection::new_client(
+            conn: Connection::new_client(
                 server_name,
                 protocols,
                 cid_manager,
                 local_addr,
                 remote_addr,
-                max_table_size,
-                max_blocked_streams,
             )?,
+            base_handler: Http3Connection::new(max_table_size, max_blocked_streams),
         })
     }
 
     pub fn new_with_conn(
         c: Connection,
         max_table_size: u32,
         max_blocked_streams: u16,
     ) -> Res<Http3Client> {
         Ok(Http3Client {
-            base_handler: Http3Connection::new_client_with_conn(
-                c,
-                max_table_size,
-                max_blocked_streams,
-            )?,
+            conn: c,
+            base_handler: Http3Connection::new(max_table_size, max_blocked_streams),
         })
     }
 
     pub fn role(&self) -> Role {
-        self.base_handler.role()
+        self.conn.role()
     }
 
     pub fn state(&self) -> Http3State {
         self.base_handler.state()
     }
 
     pub fn tls_info(&self) -> Option<&SecretAgentInfo> {
-        self.base_handler.conn.tls_info()
+        self.conn.tls_info()
     }
 
     /// Get the peer's certificate.
     pub fn peer_certificate(&self) -> Option<CertificateInfo> {
-        self.base_handler.conn.peer_certificate()
+        self.conn.peer_certificate()
     }
 
     pub fn authenticated(&mut self, status: AuthenticationStatus, now: Instant) {
-        self.base_handler.conn.authenticated(status, now);
+        self.conn.authenticated(status, now);
     }
 
     pub fn close(&mut self, now: Instant, error: AppError, msg: &str) {
-        qinfo!([self] "Close the connection error={} msg={}.", error, msg);
-        self.base_handler.close(now, error, msg);
+        qinfo!([self], "Close the connection error={} msg={}.", error, msg);
+        self.base_handler.close(&mut self.conn, now, error, msg);
     }
 
     pub fn fetch(
         &mut self,
         method: &str,
         scheme: &str,
         host: &str,
         path: &str,
         headers: &[Header],
     ) -> Res<u64> {
         qinfo!(
-            [self]
+            [self],
             "Fetch method={}, scheme={}, host={}, path={}",
             method,
             scheme,
             host,
             path
         );
-        let id = self.base_handler.conn().stream_create(StreamType::BiDi)?;
+        let id = self.conn.stream_create(StreamType::BiDi)?;
         self.base_handler.add_transaction(
             id,
             TransactionClient::new(
                 id,
                 method,
                 scheme,
                 host,
                 path,
                 headers,
                 self.base_handler.events.clone(),
             ),
         );
         Ok(id)
     }
 
     pub fn stream_reset(&mut self, stream_id: u64, error: AppError) -> Res<()> {
-        qinfo!([self] "reset_stream {} error={}.", stream_id, error);
-        self.base_handler.stream_reset(stream_id, error)
+        qinfo!([self], "reset_stream {} error={}.", stream_id, error);
+        self.base_handler
+            .stream_reset(&mut self.conn, stream_id, error)
     }
 
     pub fn stream_close_send(&mut self, stream_id: u64) -> Res<()> {
-        qinfo!([self] "Close senidng side stream={}.", stream_id);
-        self.base_handler.stream_close_send(stream_id)
+        qinfo!([self], "Close senidng side stream={}.", stream_id);
+        self.base_handler
+            .stream_close_send(&mut self.conn, stream_id)
     }
 
     pub fn send_request_body(&mut self, stream_id: u64, buf: &[u8]) -> Res<usize> {
-        qinfo!([self] "send_request_body from stream {} sending {} bytes.", stream_id, buf.len());
+        qinfo!(
+            [self],
+            "send_request_body from stream {} sending {} bytes.",
+            stream_id,
+            buf.len()
+        );
         self.base_handler
             .transactions
             .get_mut(&stream_id)
             .ok_or(Error::InvalidStreamId)?
-            .send_request_body(&mut self.base_handler.conn, buf)
+            .send_request_body(&mut self.conn, buf)
     }
 
     pub fn read_response_headers(&mut self, stream_id: u64) -> Res<(Vec<Header>, bool)> {
-        qinfo!([self] "read_response_headers from stream {}.", stream_id);
+        qinfo!([self], "read_response_headers from stream {}.", stream_id);
         let transaction = self
             .base_handler
             .transactions
             .get_mut(&stream_id)
             .ok_or(Error::InvalidStreamId)?;
         match transaction.read_response_headers() {
             Ok((headers, fin)) => {
                 if transaction.done() {
@@ -162,37 +166,34 @@ impl Http3Client {
     }
 
     pub fn read_response_data(
         &mut self,
         now: Instant,
         stream_id: u64,
         buf: &mut [u8],
     ) -> Res<(usize, bool)> {
-        qinfo!([self] "read_data from stream {}.", stream_id);
+        qinfo!([self], "read_data from stream {}.", stream_id);
         let transaction = self
             .base_handler
             .transactions
             .get_mut(&stream_id)
             .ok_or(Error::InvalidStreamId)?;
 
-        match transaction.read_response_data(&mut self.base_handler.conn, buf) {
+        match transaction.read_response_data(&mut self.conn, buf) {
             Ok((amount, fin)) => {
                 if fin {
                     self.base_handler.transactions.remove(&stream_id);
                 } else if amount > 0 {
                     // Directly call receive instead of adding to
                     // streams_are_readable here. This allows the app to
                     // pick up subsequent already-received data frames in
                     // the stream even if no new packets arrive to cause
                     // process_http3() to run.
-                    transaction.receive(
-                        &mut self.base_handler.conn,
-                        &mut self.base_handler.qpack_decoder,
-                    )?;
+                    transaction.receive(&mut self.conn, &mut self.base_handler.qpack_decoder)?;
                 }
                 Ok((amount, fin))
             }
             Err(e) => {
                 if e == Error::HttpFrameError {
                     self.close(now, e.code(), "");
                 }
                 Err(e)
@@ -214,43 +215,47 @@ impl Http3Client {
     /// Get events that indicate state changes on the connection. This method
     /// correctly handles cases where handling one event can obsolete
     /// previously-queued events, or cause new events to be generated.
     pub fn next_event(&mut self) -> Option<Http3ClientEvent> {
         self.base_handler.events.next_event()
     }
 
     pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
-        qtrace!([self] "Process.");
-        self.base_handler.process(dgram, now)
+        qtrace!([self], "Process.");
+        if let Some(d) = dgram {
+            self.process_input(d, now);
+        }
+        self.process_http3(now);
+        self.process_output(now)
     }
 
     pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
-        qtrace!([self] "Process input.");
-        self.base_handler.process_input(dgram, now);
+        qtrace!([self], "Process input.");
+        self.conn.process_input(dgram, now);
     }
 
     pub fn process_timer(&mut self, now: Instant) {
-        qtrace!([self] "Process timer.");
-        self.base_handler.process_timer(now);
+        qtrace!([self], "Process timer.");
+        self.conn.process_timer(now);
     }
 
     pub fn conn(&mut self) -> &mut Connection {
-        &mut self.base_handler.conn
+        &mut self.conn
     }
 
     pub fn process_http3(&mut self, now: Instant) {
-        qtrace!([self] "Process http3 internal.");
+        qtrace!([self], "Process http3 internal.");
 
-        self.base_handler.process_http3(now);
+        self.base_handler.process_http3(&mut self.conn, now);
     }
 
     pub fn process_output(&mut self, now: Instant) -> Output {
-        qtrace!([self] "Process output.");
-        self.base_handler.process_output(now)
+        qtrace!([self], "Process output.");
+        self.conn.process_output(now)
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use crate::hframe::HFrame;
     use neqo_common::{matches, Encoder};
deleted file mode 100644
--- a/third_party/rust/neqo-http3/src/connection_server.rs
+++ /dev/null
@@ -1,737 +0,0 @@
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use crate::connection::{Http3Connection, Http3ServerHandler, Http3State};
-use crate::server_events::{Http3ServerEvent, Http3ServerEvents};
-use crate::transaction_server::TransactionServer;
-use crate::{Error, Header, Res};
-use neqo_common::{qdebug, qinfo, qtrace, Datagram};
-use neqo_crypto::AntiReplay;
-use neqo_transport::{AppError, Connection, ConnectionIdManager, Output, Role};
-use std::cell::RefCell;
-use std::rc::Rc;
-use std::time::Instant;
-
-pub struct Http3Server {
-    base_handler: Http3Connection<Http3ServerEvents, TransactionServer, Http3ServerHandler>,
-}
-
-impl ::std::fmt::Display for Http3Server {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
-        write!(f, "Http3 connection {:?}", self.role())
-    }
-}
-
-impl Http3Server {
-    pub fn new(
-        certs: &[impl AsRef<str>],
-        protocols: &[impl AsRef<str>],
-        anti_replay: &AntiReplay,
-        cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
-        max_table_size: u32,
-        max_blocked_streams: u16,
-    ) -> Res<Http3Server> {
-        Ok(Http3Server {
-            base_handler: Http3Connection::new_server(
-                certs,
-                protocols,
-                anti_replay,
-                cid_manager,
-                max_table_size,
-                max_blocked_streams,
-            )?,
-        })
-    }
-
-    fn role(&self) -> Role {
-        self.base_handler.role()
-    }
-
-    pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
-        qtrace!([self] "Process.");
-        self.base_handler.process(dgram, now)
-    }
-
-    pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
-        qtrace!([self] "Process input.");
-        self.base_handler.process_input(dgram, now);
-    }
-
-    pub fn process_timer(&mut self, now: Instant) {
-        qtrace!([self] "Process timer.");
-        self.base_handler.process_timer(now);
-    }
-
-    pub fn conn(&mut self) -> &mut Connection {
-        &mut self.base_handler.conn
-    }
-
-    pub fn process_http3(&mut self, now: Instant) {
-        qtrace!([self] "Process http3 internal.");
-        self.base_handler.process_http3(now);
-    }
-
-    pub fn process_output(&mut self, now: Instant) -> Output {
-        qtrace!([self] "Process output.");
-        self.base_handler.process_output(now)
-    }
-
-    pub fn close(&mut self, now: Instant, error: AppError, msg: &str) {
-        qinfo!([self] "Close connection.");
-        self.base_handler.close(now, error, msg);
-    }
-
-    pub fn state(&self) -> Http3State {
-        self.base_handler.state.clone()
-    }
-
-    /// Get all current events. Best used just in debug/testing code, use
-    /// next_event() instead.
-    pub fn events(&mut self) -> impl Iterator<Item = Http3ServerEvent> {
-        self.base_handler.events.events()
-    }
-
-    /// Return true if there are outstanding events.
-    pub fn has_events(&self) -> bool {
-        self.base_handler.events.has_events()
-    }
-
-    /// Get events that indicate state changes on the connection. This method
-    /// correctly handles cases where handling one event can obsolete
-    /// previously-queued events, or cause new events to be generated.
-    pub fn next_event(&mut self) -> Option<Http3ServerEvent> {
-        self.base_handler.events.next_event()
-    }
-
-    pub fn set_response(&mut self, stream_id: u64, headers: &[Header], data: Vec<u8>) -> Res<()> {
-        qinfo!([self] "Set new respons for stream {}.", stream_id);
-        self.base_handler
-            .transactions
-            .get_mut(&stream_id)
-            .ok_or(Error::InvalidStreamId)?
-            .set_response(headers, data, &mut self.base_handler.qpack_encoder);
-        self.base_handler
-            .insert_streams_have_data_to_send(stream_id);
-        Ok(())
-    }
-
-    pub fn stream_stop_sending(&mut self, stream_id: u64, app_error: AppError) -> Res<()> {
-        qdebug!([self] "stop sending stream_id:{} error:{}.", stream_id, app_error);
-        self.base_handler.stream_stop_sending(stream_id, app_error)
-    }
-
-    pub fn stream_reset(&mut self, stream_id: u64, app_error: AppError) -> Res<()> {
-        qdebug!([self] "reset stream_id:{} error:{}.", stream_id, app_error);
-        self.base_handler.stream_reset(stream_id, app_error)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use neqo_common::matches;
-    use neqo_crypto::AuthenticationStatus;
-    use neqo_qpack::encoder::QPackEncoder;
-    use neqo_transport::{
-        CloseError, ConnectionEvent, FixedConnectionIdManager, State, StreamType,
-    };
-    use test_fixture::*;
-
-    /// Create a http3 server with default configuration.
-    pub fn default_http3_server() -> Http3Server {
-        fixture_init();
-        Http3Server::new(
-            DEFAULT_KEYS,
-            DEFAULT_ALPN,
-            &anti_replay(),
-            Rc::new(RefCell::new(FixedConnectionIdManager::new(5))),
-            100,
-            100,
-        )
-        .expect("create a default server")
-    }
-
-    fn assert_closed(hconn: &Http3Server, expected: Error) {
-        match hconn.state() {
-            Http3State::Closing(err) | Http3State::Closed(err) => {
-                assert_eq!(err, CloseError::Application(expected.code()))
-            }
-            _ => panic!("Wrong state {:?}", hconn.state()),
-        };
-    }
-
-    // Start a client/server and check setting frame.
-    #[allow(clippy::cognitive_complexity)]
-    fn connect_and_receive_settings() -> (Http3Server, Connection) {
-        // Create a server and connect it to a client.
-        // We will have a http3 server on one side and a neqo_transport
-        // connection on the other side so that we can check what the http3
-        // side sends and also to simulate an incorrectly behaving http3
-        // client.
-
-        fixture_init();
-        let mut hconn = default_http3_server();
-        let mut neqo_trans_conn = default_client();
-
-        assert_eq!(hconn.state(), Http3State::Initializing);
-        let out = neqo_trans_conn.process(None, now());
-        let out = hconn.process(out.dgram(), now());
-        let out = neqo_trans_conn.process(out.dgram(), now());
-        let _ = hconn.process(out.dgram(), now());
-        let authentication_needed = |e| matches!(e, ConnectionEvent::AuthenticationNeeded);
-        assert!(neqo_trans_conn.events().any(authentication_needed));
-        neqo_trans_conn.authenticated(AuthenticationStatus::Ok, now());
-        let out = neqo_trans_conn.process(None, now());
-        let out = hconn.process(out.dgram(), now());
-        assert_eq!(hconn.state(), Http3State::Connected);
-        neqo_trans_conn.process(out.dgram(), now());
-
-        let mut connected = false;
-        while let Some(e) = neqo_trans_conn.next_event() {
-            match e {
-                ConnectionEvent::NewStream {
-                    stream_id,
-                    stream_type,
-                } => {
-                    assert!((stream_id == 3) || (stream_id == 7) || (stream_id == 11));
-                    assert_eq!(stream_type, StreamType::UniDi);
-                }
-                ConnectionEvent::RecvStreamReadable { stream_id } => {
-                    if stream_id == 2 || stream_id == 3 {
-                        // the control stream
-                        let mut buf = [0u8; 100];
-                        let (amount, fin) =
-                            neqo_trans_conn.stream_recv(stream_id, &mut buf).unwrap();
-                        assert_eq!(fin, false);
-                        const CONTROL_STREAM_DATA: &[u8] =
-                            &[0x0, 0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64];
-                        assert_eq!(amount, CONTROL_STREAM_DATA.len());
-                        assert_eq!(&buf[..9], CONTROL_STREAM_DATA);
-                    } else if stream_id == 6 || stream_id == 7 {
-                        let mut buf = [0u8; 100];
-                        let (amount, fin) =
-                            neqo_trans_conn.stream_recv(stream_id, &mut buf).unwrap();
-                        assert_eq!(fin, false);
-                        assert_eq!(amount, 1);
-                        assert_eq!(buf[..1], [0x2]);
-                    } else if stream_id == 10 || stream_id == 11 {
-                        let mut buf = [0u8; 100];
-                        let (amount, fin) =
-                            neqo_trans_conn.stream_recv(stream_id, &mut buf).unwrap();
-                        assert_eq!(fin, false);
-                        assert_eq!(amount, 1);
-                        assert_eq!(buf[..1], [0x3]);
-                    } else {
-                        panic!("unexpected event");
-                    }
-                }
-                ConnectionEvent::SendStreamWritable { stream_id } => {
-                    assert!((stream_id == 2) || (stream_id == 6) || (stream_id == 10));
-                }
-                ConnectionEvent::StateChange(State::Connected) => connected = true,
-                ConnectionEvent::StateChange(_) => (),
-                _ => panic!("unexpected event"),
-            }
-        }
-        assert!(connected);
-        (hconn, neqo_trans_conn)
-    }
-
-    // Test http3 connection inintialization.
-    // The server will open the control and qpack streams and send SETTINGS frame.
-    #[test]
-    fn test_server_connect() {
-        let _ = connect_and_receive_settings();
-    }
-
-    struct PeerConnection {
-        conn: Connection,
-        control_stream_id: u64,
-    }
-
-    // Connect transport, send and receive settings.
-    fn connect() -> (Http3Server, PeerConnection) {
-        let (mut hconn, mut neqo_trans_conn) = connect_and_receive_settings();
-        let control_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
-        let mut sent = neqo_trans_conn.stream_send(
-            control_stream,
-            &[0x0, 0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64],
-        );
-        assert_eq!(sent, Ok(9));
-        let mut encoder = QPackEncoder::new(true);
-        encoder.add_send_stream(neqo_trans_conn.stream_create(StreamType::UniDi).unwrap());
-        encoder.send(&mut neqo_trans_conn).unwrap();
-        let decoder_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
-        sent = neqo_trans_conn.stream_send(decoder_stream, &[0x3]);
-        assert_eq!(sent, Ok(1));
-        let out = neqo_trans_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        // assert no error occured.
-        assert_eq!(hconn.state(), Http3State::Connected);
-        (
-            hconn,
-            PeerConnection {
-                conn: neqo_trans_conn,
-                control_stream_id: control_stream,
-            },
-        )
-    }
-
-    // Server: Test receiving a new control stream and a SETTINGS frame.
-    #[test]
-    fn test_server_receive_control_frame() {
-        let _ = connect();
-    }
-
-    // Server: Test that the connection will be closed if control stream
-    // has been closed.
-    #[test]
-    fn test_server_close_control_stream() {
-        let (mut hconn, mut peer_conn) = connect();
-        peer_conn
-            .conn
-            .stream_close_send(peer_conn.control_stream_id)
-            .unwrap();
-        let out = peer_conn.conn.process(None, now());
-        hconn.process(out.dgram(), now());
-        assert_closed(&hconn, Error::HttpClosedCriticalStream);
-    }
-
-    // Server: test missing SETTINGS frame
-    // (the first frame sent is a MAX_PUSH_ID frame).
-    #[test]
-    fn test_server_missing_settings() {
-        let (mut hconn, mut neqo_trans_conn) = connect_and_receive_settings();
-        // Create client control stream.
-        let control_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
-        // Send a MAX_PUSH_ID frame instead.
-        let sent = neqo_trans_conn.stream_send(control_stream, &[0x0, 0xd, 0x1, 0xf]);
-        assert_eq!(sent, Ok(4));
-        let out = neqo_trans_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-        assert_closed(&hconn, Error::HttpMissingSettings);
-    }
-
-    // Server: receiving SETTINGS frame twice causes connection close
-    // with error HTTP_UNEXPECTED_FRAME.
-    #[test]
-    fn test_server_receive_settings_twice() {
-        let (mut hconn, mut peer_conn) = connect();
-        // send the second SETTINGS frame.
-        let sent = peer_conn.conn.stream_send(
-            peer_conn.control_stream_id,
-            &[0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64],
-        );
-        assert_eq!(sent, Ok(8));
-        let out = peer_conn.conn.process(None, now());
-        hconn.process(out.dgram(), now());
-        assert_closed(&hconn, Error::HttpFrameUnexpected);
-    }
-
-    fn test_wrong_frame_on_control_stream(v: &[u8]) {
-        let (mut hconn, mut peer_conn) = connect();
-
-        // receive a frame that is not allowed on the control stream.
-        let _ = peer_conn.conn.stream_send(peer_conn.control_stream_id, v);
-
-        let out = peer_conn.conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        assert_closed(&hconn, Error::HttpFrameUnexpected);
-    }
-
-    // send DATA frame on a cortrol stream
-    #[test]
-    fn test_server_data_frame_on_control_stream() {
-        test_wrong_frame_on_control_stream(&[0x0, 0x2, 0x1, 0x2]);
-    }
-
-    // send HEADERS frame on a cortrol stream
-    #[test]
-    fn test_server_headers_frame_on_control_stream() {
-        test_wrong_frame_on_control_stream(&[0x1, 0x2, 0x1, 0x2]);
-    }
-
-    // send PUSH_PROMISE frame on a cortrol stream
-    #[test]
-    fn test_server_push_promise_frame_on_control_stream() {
-        test_wrong_frame_on_control_stream(&[0x5, 0x2, 0x1, 0x2]);
-    }
-
-    // send DUPLICATE_PUSH frame on a cortrol stream
-    #[test]
-    fn test_server_duplicate_push_frame_on_control_stream() {
-        test_wrong_frame_on_control_stream(&[0xe, 0x2, 0x1, 0x2]);
-    }
-
-    // Server: receive unkonwn stream type
-    // also test getting stream id that does not fit into a single byte.
-    #[test]
-    fn test_server_received_unknown_stream() {
-        let (mut hconn, mut peer_conn) = connect();
-
-        // create a stream with unknown type.
-        let new_stream_id = peer_conn.conn.stream_create(StreamType::UniDi).unwrap();
-        let _ = peer_conn
-            .conn
-            .stream_send(new_stream_id, &[0x41, 0x19, 0x4, 0x4, 0x6, 0x0, 0x8, 0x0]);
-        let out = peer_conn.conn.process(None, now());
-        let out = hconn.process(out.dgram(), now());
-        peer_conn.conn.process(out.dgram(), now());
-
-        // check for stop-sending with Error::HttpStreamCreationError.
-        let mut stop_sending_event_found = false;
-        while let Some(e) = peer_conn.conn.next_event() {
-            if let ConnectionEvent::SendStreamStopSending {
-                stream_id,
-                app_error,
-            } = e
-            {
-                stop_sending_event_found = true;
-                assert_eq!(stream_id, new_stream_id);
-                assert_eq!(app_error, Error::HttpStreamCreationError.code());
-            }
-        }
-        assert!(stop_sending_event_found);
-        assert_eq!(hconn.state(), Http3State::Connected);
-    }
-
-    // Server: receiving a push stream on a server should cause WrongStreamDirection
-    #[test]
-    fn test_server_received_push_stream() {
-        let (mut hconn, mut peer_conn) = connect();
-
-        // create a push stream.
-        let push_stream_id = peer_conn.conn.stream_create(StreamType::UniDi).unwrap();
-        let _ = peer_conn.conn.stream_send(push_stream_id, &[0x1]);
-        let out = peer_conn.conn.process(None, now());
-        let out = hconn.process(out.dgram(), now());
-        peer_conn.conn.process(out.dgram(), now());
-        assert_closed(&hconn, Error::HttpStreamCreationError);
-    }
-
-    //// Test reading of a slowly streamed frame. bytes are received one by one
-    #[test]
-    fn test_server_frame_reading() {
-        let (mut hconn, mut peer_conn) = connect_and_receive_settings();
-
-        // create a control stream.
-        let control_stream = peer_conn.stream_create(StreamType::UniDi).unwrap();
-
-        // send the stream type
-        let mut sent = peer_conn.stream_send(control_stream, &[0x0]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        // start sending SETTINGS frame
-        sent = peer_conn.stream_send(control_stream, &[0x4]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x4]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x6]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x0]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x8]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x0]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        assert_eq!(hconn.state(), Http3State::Connected);
-
-        // Now test PushPromise
-        sent = peer_conn.stream_send(control_stream, &[0x5]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x5]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        sent = peer_conn.stream_send(control_stream, &[0x4]);
-        assert_eq!(sent, Ok(1));
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        // PUSH_PROMISE on a control stream will cause an error
-        assert_closed(&hconn, Error::HttpFrameUnexpected);
-    }
-
-    // Test reading of a slowly streamed frame. bytes are received one by one
-    fn test_incomplet_frame(res: &[u8]) {
-        let (mut hconn, mut peer_conn) = connect_and_receive_settings();
-
-        // send an incomplete reequest.
-        let stream_id = peer_conn.stream_create(StreamType::BiDi).unwrap();
-        peer_conn.stream_send(stream_id, res).unwrap();
-        peer_conn.stream_close_send(stream_id).unwrap();
-
-        let out = peer_conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        assert_closed(&hconn, Error::HttpFrameError);
-    }
-
-    const REQUEST_WITH_BODY: &[u8] = &[
-        // headers
-        0x01, 0x10, 0x00, 0x00, 0xd1, 0xd7, 0x50, 0x89, 0x41, 0xe9, 0x2a, 0x67, 0x35, 0x53, 0x2e,
-        0x43, 0xd3, 0xc1, // the first data frame.
-        0x0, 0x3, 0x61, 0x62, 0x63, // the second data frame.
-        0x0, 0x3, 0x64, 0x65, 0x66,
-    ];
-
-    // Incomplete DATA frame
-    #[test]
-    fn test_server_incomplet_data_frame() {
-        test_incomplet_frame(&REQUEST_WITH_BODY[..22]);
-    }
-
-    // Incomplete HEADERS frame
-    #[test]
-    fn test_server_incomplet_headers_frame() {
-        test_incomplet_frame(&REQUEST_WITH_BODY[..10]);
-    }
-
-    #[test]
-    fn test_server_incomplet_unknown_frame() {
-        test_incomplet_frame(&[0x21]);
-    }
-
-    #[test]
-    fn test_server_request_with_body() {
-        let (mut hconn, mut peer_conn) = connect();
-
-        let stream_id = peer_conn.conn.stream_create(StreamType::BiDi).unwrap();
-        peer_conn
-            .conn
-            .stream_send(stream_id, REQUEST_WITH_BODY)
-            .unwrap();
-        peer_conn.conn.stream_close_send(stream_id).unwrap();
-
-        let out = peer_conn.conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        // Check connection event. There should be 1 Header and 2 data events.
-        let mut headers_frames = 0;
-        let mut data_frames = 0;
-        while let Some(event) = hconn.next_event() {
-            match event {
-                Http3ServerEvent::Headers { headers, fin, .. } => {
-                    assert_eq!(
-                        headers,
-                        vec![
-                            (String::from(":method"), String::from("GET")),
-                            (String::from(":scheme"), String::from("https")),
-                            (String::from(":authority"), String::from("something.com")),
-                            (String::from(":path"), String::from("/"))
-                        ]
-                    );
-                    assert_eq!(fin, false);
-                    headers_frames += 1;
-                }
-                Http3ServerEvent::Data {
-                    stream_id,
-                    data,
-                    fin,
-                } => {
-                    if data_frames == 0 {
-                        assert_eq!(data, &REQUEST_WITH_BODY[20..23]);
-                    } else {
-                        assert_eq!(data, &REQUEST_WITH_BODY[25..]);
-                        assert_eq!(fin, true);
-                        hconn
-                            .set_response(
-                                stream_id,
-                                &[
-                                    (String::from(":status"), String::from("200")),
-                                    (String::from("content-length"), String::from("3")),
-                                ],
-                                vec![0x67, 0x68, 0x69],
-                            )
-                            .unwrap();
-                    }
-                    data_frames += 1;
-                }
-                _ => {}
-            }
-        }
-        assert_eq!(headers_frames, 1);
-        assert_eq!(data_frames, 2);
-    }
-
-    #[test]
-    fn test_server_request_with_body_send_stop_sending() {
-        let (mut hconn, mut peer_conn) = connect();
-
-        let stream_id = peer_conn.conn.stream_create(StreamType::BiDi).unwrap();
-        // Send only request headers for now.
-        peer_conn
-            .conn
-            .stream_send(stream_id, &REQUEST_WITH_BODY[..20])
-            .unwrap();
-
-        let out = peer_conn.conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        // Check connection event. There should be 1 Header and no data events.
-        let mut headers_frames = 0;
-        while let Some(event) = hconn.next_event() {
-            match event {
-                Http3ServerEvent::Headers {
-                    stream_id,
-                    headers,
-                    fin,
-                } => {
-                    assert_eq!(
-                        headers,
-                        vec![
-                            (String::from(":method"), String::from("GET")),
-                            (String::from(":scheme"), String::from("https")),
-                            (String::from(":authority"), String::from("something.com")),
-                            (String::from(":path"), String::from("/"))
-                        ]
-                    );
-                    assert_eq!(fin, false);
-                    headers_frames += 1;
-                    hconn
-                        .stream_stop_sending(stream_id, Error::HttpEarlyResponse.code())
-                        .unwrap();
-                    hconn
-                        .set_response(
-                            stream_id,
-                            &[
-                                (String::from(":status"), String::from("200")),
-                                (String::from("content-length"), String::from("3")),
-                            ],
-                            vec![0x67, 0x68, 0x69],
-                        )
-                        .unwrap();
-                }
-                Http3ServerEvent::Data { .. } => {
-                    panic!("We should not have a Data event");
-                }
-                _ => {}
-            }
-        }
-        let out = hconn.process(None, now());
-
-        // Send data.
-        peer_conn
-            .conn
-            .stream_send(stream_id, &REQUEST_WITH_BODY[20..])
-            .unwrap();
-        peer_conn.conn.stream_close_send(stream_id).unwrap();
-
-        let out = peer_conn.conn.process(out.dgram(), now());
-        hconn.process(out.dgram(), now());
-
-        while let Some(event) = hconn.next_event() {
-            match event {
-                Http3ServerEvent::Headers { .. } => {
-                    panic!("We should not have a Data event");
-                }
-                Http3ServerEvent::Data { .. } => {
-                    panic!("We should not have a Data event");
-                }
-                _ => {}
-            }
-        }
-        assert_eq!(headers_frames, 1);
-    }
-
-    #[test]
-    fn test_server_request_with_body_server_reset() {
-        let (mut hconn, mut peer_conn) = connect();
-
-        let request_stream_id = peer_conn.conn.stream_create(StreamType::BiDi).unwrap();
-        // Send only request headers for now.
-        peer_conn
-            .conn
-            .stream_send(request_stream_id, &REQUEST_WITH_BODY[..20])
-            .unwrap();
-
-        let out = peer_conn.conn.process(None, now());
-        hconn.process(out.dgram(), now());
-
-        // Check connection event. There should be 1 Header and no data events.
-        // The server will reset the stream.
-        let mut headers_frames = 0;
-        while let Some(event) = hconn.next_event() {
-            match event {
-                Http3ServerEvent::Headers {
-                    stream_id,
-                    headers,
-                    fin,
-                } => {
-                    assert_eq!(request_stream_id, stream_id);
-                    assert_eq!(
-                        headers,
-                        vec![
-                            (String::from(":method"), String::from("GET")),
-                            (String::from(":scheme"), String::from("https")),
-                            (String::from(":authority"), String::from("something.com")),
-                            (String::from(":path"), String::from("/"))
-                        ]
-                    );
-                    assert_eq!(fin, false);
-                    headers_frames += 1;
-                    hconn
-                        .stream_reset(stream_id, Error::HttpRequestRejected.code())
-                        .unwrap();
-                }
-                Http3ServerEvent::Data { .. } => {
-                    panic!("We should not have a Data event");
-                }
-                _ => {}
-            }
-        }
-        let out = hconn.process(None, now());
-
-        let out = peer_conn.conn.process(out.dgram(), now());
-        hconn.process(out.dgram(), now());
-
-        // Check that STOP_SENDING and REET has been received.
-        let mut reset = 0;
-        let mut stop_sending = 0;
-        while let Some(event) = peer_conn.conn.next_event() {
-            match event {
-                ConnectionEvent::RecvStreamReset { stream_id, .. } => {
-                    assert_eq!(request_stream_id, stream_id);
-                    reset += 1;
-                }
-                ConnectionEvent::SendStreamStopSending { stream_id, .. } => {
-                    assert_eq!(request_stream_id, stream_id);
-                    stop_sending += 1;
-                }
-                _ => {}
-            }
-        }
-        assert_eq!(headers_frames, 1);
-        assert_eq!(reset, 1);
-        assert_eq!(stop_sending, 1);
-    }
-}
--- a/third_party/rust/neqo-http3/src/control_stream_local.rs
+++ b/third_party/rust/neqo-http3/src/control_stream_local.rs
@@ -29,30 +29,30 @@ impl ControlStreamLocal {
         let mut enc = Encoder::default();
         f.encode(&mut enc);
         self.buf.append(&mut enc.into());
     }
 
     pub fn send(&mut self, conn: &mut Connection) -> Res<()> {
         if let Some(stream_id) = self.stream_id {
             if !self.buf.is_empty() {
-                qtrace!([self] "sending data.");
+                qtrace!([self], "sending data.");
                 let sent = conn.stream_send(stream_id, &self.buf[..])?;
                 if sent == self.buf.len() {
                     self.buf.clear();
                 } else {
                     let b = self.buf.split_off(sent);
                     self.buf = b;
                 }
             }
         }
         Ok(())
     }
 
     pub fn create(&mut self, conn: &mut Connection) -> Res<()> {
-        qtrace!([self] "Create a control stream.");
+        qtrace!([self], "Create a control stream.");
         self.stream_id = Some(conn.stream_create(StreamType::UniDi)?);
         let mut enc = Encoder::default();
         enc.encode_varint(HTTP3_UNI_STREAM_TYPE_CONTROL as u64);
         self.buf.append(&mut enc.into());
         Ok(())
     }
 }
--- a/third_party/rust/neqo-http3/src/control_stream_remote.rs
+++ b/third_party/rust/neqo-http3/src/control_stream_remote.rs
@@ -28,29 +28,29 @@ impl ControlStreamRemote {
         ControlStreamRemote {
             stream_id: None,
             frame_reader: HFrameReader::new(),
             fin: false,
         }
     }
 
     pub fn add_remote_stream(&mut self, stream_id: u64) -> Res<()> {
-        qinfo!([self] "A new control stream {}.", stream_id);
+        qinfo!([self], "A new control stream {}.", stream_id);
         if self.stream_id.is_some() {
-            qdebug!([self] "A control stream already exists");
+            qdebug!([self], "A control stream already exists");
             return Err(Error::HttpStreamCreationError);
         }
         self.stream_id = Some(stream_id);
         Ok(())
     }
 
     pub fn receive_if_this_stream(&mut self, conn: &mut Connection, stream_id: u64) -> Res<bool> {
         if let Some(id) = self.stream_id {
             if id == stream_id {
-                qdebug!([self] "Receiving data.");
+                qdebug!([self], "Receiving data.");
                 self.fin = self.frame_reader.receive(conn, stream_id)?;
                 return Ok(true);
             }
         }
         Ok(false)
     }
 
     pub fn recvd_fin(&self) -> bool {
--- a/third_party/rust/neqo-http3/src/hframe.rs
+++ b/third_party/rust/neqo-http3/src/hframe.rs
@@ -208,56 +208,71 @@ impl HFrameReader {
     // returns true if quic stream was closed.
     pub fn receive(&mut self, conn: &mut Connection, stream_id: u64) -> Res<bool> {
         loop {
             let to_read = std::cmp::min(self.decoder.min_remaining(), 4096);
             let mut buf = vec![0; to_read];
             let fin;
             let mut input = match conn.stream_recv(stream_id, &mut buf[..]) {
                 Ok((0, true)) => {
-                    qtrace!([conn] "HFrameReader::receive: stream has been closed");
+                    qtrace!([conn], "HFrameReader::receive: stream has been closed");
                     break match self.state {
                         HFrameReaderState::BeforeFrame => Ok(true),
                         _ => Err(Error::HttpFrameError),
                     };
                 }
                 Ok((0, false)) => break Ok(false),
                 Ok((amount, f)) => {
-                    qtrace!([conn] "HFrameReader::receive: reading {} byte, fin={}", amount, f);
+                    qtrace!(
+                        [conn],
+                        "HFrameReader::receive: reading {} byte, fin={}",
+                        amount,
+                        f
+                    );
                     fin = f;
                     Decoder::from(&buf[..amount])
                 }
                 Err(e) => {
-                    qdebug!([conn] "HFrameReader::receive: error reading data from stream {}: {:?}", stream_id, e);
+                    qdebug!(
+                        [conn],
+                        "HFrameReader::receive: error reading data from stream {}: {:?}",
+                        stream_id,
+                        e
+                    );
                     break Err(e.into());
                 }
             };
 
             // TODO(mt) this amount_read thing is terrible.
             let mut amount_read = input.remaining();
             let progress = self.decoder.consume(&mut input);
             amount_read -= input.remaining();
             match self.state {
                 HFrameReaderState::BeforeFrame | HFrameReaderState::GetType => match progress {
                     IncrementalDecoderResult::Uint(v) => {
-                        qtrace!([conn] "HFrameReader::receive: read frame type {}", v);
+                        qtrace!([conn], "HFrameReader::receive: read frame type {}", v);
                         self.hframe_type = v;
                         self.decoder = IncrementalDecoder::decode_varint();
                         self.state = HFrameReaderState::GetLength;
                     }
                     IncrementalDecoderResult::InProgress => {
                         self.state = HFrameReaderState::GetType;
                     }
                     _ => panic!("We must be in one of the states above"),
                 },
 
                 HFrameReaderState::GetLength => {
                     match progress {
                         IncrementalDecoderResult::Uint(len) => {
-                            qtrace!([conn] "HFrameReader::receive: frame type {} length {}", self.hframe_type, len);
+                            qtrace!(
+                                [conn],
+                                "HFrameReader::receive: frame type {} length {}",
+                                self.hframe_type,
+                                len
+                            );
                             self.hframe_len = len;
                             self.state = match self.hframe_type {
                                 // DATA and HEADERS payload are left on the quic stream and picked up separately
                                 H3_FRAME_TYPE_DATA | H3_FRAME_TYPE_HEADERS => {
                                     HFrameReaderState::Done
                                 }
                                 // For push frame we only decode the first varint. Headers blocks will be picked up separately.
                                 H3_FRAME_TYPE_PUSH_PROMISE => {
@@ -305,17 +320,22 @@ impl HFrameReader {
                         }
                         IncrementalDecoderResult::InProgress => {}
                         _ => panic!("We must be in one of the states above"),
                     };
                 }
                 HFrameReaderState::GetData => {
                     match progress {
                         IncrementalDecoderResult::Buffer(data) => {
-                            qtrace!([conn] "received frame {}: {}", self.hframe_type, hex(&data[..]));
+                            qtrace!(
+                                [conn],
+                                "received frame {}: {}",
+                                self.hframe_type,
+                                hex(&data[..])
+                            );
                             self.payload = data;
                             self.state = HFrameReaderState::Done;
                         }
                         IncrementalDecoderResult::InProgress => {}
                         _ => panic!("We must be in one of the states above"),
                     };
                 }
                 HFrameReaderState::UnknownFrameDischargeData => {
--- a/third_party/rust/neqo-http3/src/lib.rs
+++ b/third_party/rust/neqo-http3/src/lib.rs
@@ -4,34 +4,36 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 #![deny(warnings)]
 
 mod client_events;
 mod connection;
 pub mod connection_client;
-pub mod connection_server;
 mod control_stream_local;
 mod control_stream_remote;
 pub mod hframe;
+pub mod server;
+mod server_connection_events;
 mod server_events;
 mod stream_type_reader;
 mod transaction_client;
 pub mod transaction_server;
+//pub mod server;
 
 use neqo_qpack;
 use neqo_transport;
 pub use neqo_transport::Output;
 
 pub use client_events::Http3ClientEvent;
 pub use connection::Http3State;
 pub use connection_client::Http3Client;
-pub use connection_server::Http3Server;
 pub use neqo_qpack::Header;
+pub use server::Http3Server;
 pub use server_events::Http3ServerEvent;
 pub use transaction_server::TransactionServer;
 
 type Res<T> = Result<T, Error>;
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum Error {
     HttpNoError,
new file mode 100644
--- /dev/null
+++ b/third_party/rust/neqo-http3/src/server.rs
@@ -0,0 +1,781 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::connection::Http3State;
+use crate::server_connection_events::Http3ServerConnEvent;
+use crate::server_events::{
+    ClientRequestStream, Http3Handler, Http3ServerEvent, Http3ServerEvents,
+};
+use crate::Res;
+use neqo_common::{qtrace, Datagram};
+use neqo_crypto::AntiReplay;
+use neqo_transport::server::{ActiveConnectionRef, Server};
+use neqo_transport::{ConnectionIdManager, Output};
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+use std::time::Instant;
+
+type HandlerRef = Rc<RefCell<Http3Handler>>;
+
+pub struct Http3Server {
+    server: Server,
+    max_table_size: u32,
+    max_blocked_streams: u16,
+    connections: HashMap<ActiveConnectionRef, HandlerRef>,
+    events: Http3ServerEvents,
+}
+
+impl ::std::fmt::Display for Http3Server {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(f, "Http3 server ")
+    }
+}
+
+impl Http3Server {
+    pub fn new(
+        now: Instant,
+        certs: &[impl AsRef<str>],
+        protocols: &[impl AsRef<str>],
+        anti_replay: AntiReplay,
+        cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
+        max_table_size: u32,
+        max_blocked_streams: u16,
+    ) -> Res<Http3Server> {
+        Ok(Http3Server {
+            server: Server::new(now, certs, protocols, anti_replay, cid_manager)?,
+            max_table_size,
+            max_blocked_streams,
+            connections: HashMap::new(),
+            events: Http3ServerEvents::default(),
+        })
+    }
+
+    pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
+        qtrace!([self], "Process.");
+        let out = self.server.process(dgram, now);
+        self.process_http3(now);
+        // If we do not that a dgram already try again after process_http3.
+        match out {
+            Output::Datagram(d) => {
+                qtrace!([self], "Send packet: {:?}", d);
+                Output::Datagram(d)
+            }
+            _ => self.server.process(None, now),
+        }
+    }
+
+    pub fn process_http3(&mut self, now: Instant) {
+        qtrace!([self], "Process http3 internal.");
+        let mut active_conns = self.server.active_connections();
+
+        // We need to find connections that needs to be process on http3 level.
+        let mut http3_active: Vec<ActiveConnectionRef> = self
+            .connections
+            .iter()
+            .filter(|(conn, handler)| {
+                handler.borrow().should_be_processed() && !active_conns.contains(&conn)
+            })
+            .map(|(conn, _)| conn)
+            .cloned()
+            .collect();
+        // For http_active connection we need to put them in neqo-transport's server
+        // waiting queue.
+        http3_active
+            .iter()
+            .for_each(|conn| self.server.add_to_waiting(conn.clone()));
+        active_conns.append(&mut http3_active);
+        active_conns.dedup();
+        let max_table_size = self.max_table_size;
+        let max_blocked_streams = self.max_blocked_streams;
+        for mut conn in active_conns {
+            let handler = self.connections.entry(conn.clone()).or_insert_with(|| {
+                Rc::new(RefCell::new(Http3Handler::new(
+                    max_table_size,
+                    max_blocked_streams,
+                )))
+            });
+
+            handler
+                .borrow_mut()
+                .process_http3(&mut conn.borrow_mut(), now);
+            let mut remove = false;
+            while let Some(e) = handler.borrow_mut().next_event() {
+                match e {
+                    Http3ServerConnEvent::Headers {
+                        stream_id,
+                        headers,
+                        fin,
+                    } => self.events.headers(
+                        ClientRequestStream::new(conn.clone(), handler.clone(), stream_id),
+                        headers,
+                        fin,
+                    ),
+                    Http3ServerConnEvent::Data {
+                        stream_id,
+                        data,
+                        fin,
+                    } => self.events.data(
+                        ClientRequestStream::new(conn.clone(), handler.clone(), stream_id),
+                        data,
+                        fin,
+                    ),
+                    Http3ServerConnEvent::StateChange(state) => {
+                        self.events
+                            .connection_state_change(conn.clone(), state.clone());
+                        if let Http3State::Closed { .. } = state {
+                            remove = true;
+                        }
+                    }
+                    _ => {}
+                }
+            }
+            if remove {
+                self.connections.remove(&conn.clone());
+            }
+        }
+    }
+
+    /// Get all current events. Best used just in debug/testing code, use
+    /// next_event() instead.
+    pub fn events(&mut self) -> impl Iterator<Item = Http3ServerEvent> {
+        self.events.events()
+    }
+
+    /// Return true if there are outstanding events.
+    pub fn has_events(&self) -> bool {
+        self.events.has_events()
+    }
+
+    /// Get events that indicate state changes on the connection. This method
+    /// correctly handles cases where handling one event can obsolete
+    /// previously-queued events, or cause new events to be generated.
+    pub fn next_event(&mut self) -> Option<Http3ServerEvent> {
+        self.events.next_event()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::Error;
+    use neqo_common::matches;
+    use neqo_crypto::AuthenticationStatus;
+    use neqo_qpack::encoder::QPackEncoder;
+    use neqo_transport::{
+        CloseError, Connection, ConnectionEvent, FixedConnectionIdManager, State, StreamType,
+    };
+    use test_fixture::*;
+
+    /// Create a http3 server with default configuration.
+    pub fn default_http3_server() -> Http3Server {
+        fixture_init();
+        Http3Server::new(
+            now(),
+            DEFAULT_KEYS,
+            DEFAULT_ALPN,
+            anti_replay(),
+            Rc::new(RefCell::new(FixedConnectionIdManager::new(5))),
+            100,
+            100,
+        )
+        .expect("create a default server")
+    }
+
+    fn assert_closed(hconn: &mut Http3Server, expected: Error) {
+        let err = CloseError::Application(expected.code());
+        let closed = |e| {
+            matches!(e,
+            Http3ServerEvent::StateChange{ state: Http3State::Closing(e), .. }
+            | Http3ServerEvent::StateChange{ state: Http3State::Closed(e), .. }
+              if e == err)
+        };
+        assert!(hconn.events().any(closed));
+    }
+
+    fn assert_connected(hconn: &mut Http3Server) {
+        let connected =
+            |e| matches!(e, Http3ServerEvent::StateChange{ state: Http3State::Connected, ..} );
+        assert!(hconn.events().any(connected));
+    }
+
+    fn assert_not_closed(hconn: &mut Http3Server) {
+        let closed = |e| {
+            matches!(e,
+            Http3ServerEvent::StateChange{ state: Http3State::Closing(..), .. })
+        };
+        assert!(!hconn.events().any(closed));
+    }
+
+    // Start a client/server and check setting frame.
+    #[allow(clippy::cognitive_complexity)]
+    fn connect_and_receive_settings() -> (Http3Server, Connection) {
+        // Create a server and connect it to a client.
+        // We will have a http3 server on one side and a neqo_transport
+        // connection on the other side so that we can check what the http3
+        // side sends and also to simulate an incorrectly behaving http3
+        // client.
+
+        fixture_init();
+        let mut hconn = default_http3_server();
+        let mut neqo_trans_conn = default_client();
+
+        let out = neqo_trans_conn.process(None, now());
+        let out = hconn.process(out.dgram(), now());
+        let out = neqo_trans_conn.process(out.dgram(), now());
+        let _ = hconn.process(out.dgram(), now());
+        let authentication_needed = |e| matches!(e, ConnectionEvent::AuthenticationNeeded);
+        assert!(neqo_trans_conn.events().any(authentication_needed));
+        neqo_trans_conn.authenticated(AuthenticationStatus::Ok, now());
+        let out = neqo_trans_conn.process(None, now());
+        let out = hconn.process(out.dgram(), now());
+        assert_connected(&mut hconn);
+        neqo_trans_conn.process(out.dgram(), now());
+
+        let mut connected = false;
+        while let Some(e) = neqo_trans_conn.next_event() {
+            match e {
+                ConnectionEvent::NewStream {
+                    stream_id,
+                    stream_type,
+                } => {
+                    assert!((stream_id == 3) || (stream_id == 7) || (stream_id == 11));
+                    assert_eq!(stream_type, StreamType::UniDi);
+                }
+                ConnectionEvent::RecvStreamReadable { stream_id } => {
+                    if stream_id == 2 || stream_id == 3 {
+                        // the control stream
+                        let mut buf = [0u8; 100];
+                        let (amount, fin) =
+                            neqo_trans_conn.stream_recv(stream_id, &mut buf).unwrap();
+                        assert_eq!(fin, false);
+                        const CONTROL_STREAM_DATA: &[u8] =
+                            &[0x0, 0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64];
+                        assert_eq!(amount, CONTROL_STREAM_DATA.len());
+                        assert_eq!(&buf[..9], CONTROL_STREAM_DATA);
+                    } else if stream_id == 6 || stream_id == 7 {
+                        let mut buf = [0u8; 100];
+                        let (amount, fin) =
+                            neqo_trans_conn.stream_recv(stream_id, &mut buf).unwrap();
+                        assert_eq!(fin, false);
+                        assert_eq!(amount, 1);
+                        assert_eq!(buf[..1], [0x2]);
+                    } else if stream_id == 10 || stream_id == 11 {
+                        let mut buf = [0u8; 100];
+                        let (amount, fin) =
+                            neqo_trans_conn.stream_recv(stream_id, &mut buf).unwrap();
+                        assert_eq!(fin, false);
+                        assert_eq!(amount, 1);
+                        assert_eq!(buf[..1], [0x3]);
+                    } else {
+                        panic!("unexpected event");
+                    }
+                }
+                ConnectionEvent::SendStreamWritable { stream_id } => {
+                    assert!((stream_id == 2) || (stream_id == 6) || (stream_id == 10));
+                }
+                ConnectionEvent::StateChange(State::Connected) => connected = true,
+                ConnectionEvent::StateChange(_) => (),
+                _ => panic!("unexpected event"),
+            }
+        }
+        assert!(connected);
+        (hconn, neqo_trans_conn)
+    }
+
+    // Test http3 connection inintialization.
+    // The server will open the control and qpack streams and send SETTINGS frame.
+    #[test]
+    fn test_server_connect() {
+        let _ = connect_and_receive_settings();
+    }
+
+    struct PeerConnection {
+        conn: Connection,
+        control_stream_id: u64,
+    }
+
+    // Connect transport, send and receive settings.
+    fn connect() -> (Http3Server, PeerConnection) {
+        let (mut hconn, mut neqo_trans_conn) = connect_and_receive_settings();
+        let control_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
+        let mut sent = neqo_trans_conn.stream_send(
+            control_stream,
+            &[0x0, 0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64],
+        );
+        assert_eq!(sent, Ok(9));
+        let mut encoder = QPackEncoder::new(true);
+        encoder.add_send_stream(neqo_trans_conn.stream_create(StreamType::UniDi).unwrap());
+        encoder.send(&mut neqo_trans_conn).unwrap();
+        let decoder_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
+        sent = neqo_trans_conn.stream_send(decoder_stream, &[0x3]);
+        assert_eq!(sent, Ok(1));
+        let out = neqo_trans_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        // assert no error occured.
+        assert_not_closed(&mut hconn);
+        (
+            hconn,
+            PeerConnection {
+                conn: neqo_trans_conn,
+                control_stream_id: control_stream,
+            },
+        )
+    }
+
+    // Server: Test receiving a new control stream and a SETTINGS frame.
+    #[test]
+    fn test_server_receive_control_frame() {
+        let _ = connect();
+    }
+
+    // Server: Test that the connection will be closed if control stream
+    // has been closed.
+    #[test]
+    fn test_server_close_control_stream() {
+        let (mut hconn, mut peer_conn) = connect();
+        peer_conn
+            .conn
+            .stream_close_send(peer_conn.control_stream_id)
+            .unwrap();
+        let out = peer_conn.conn.process(None, now());
+        hconn.process(out.dgram(), now());
+        assert_closed(&mut hconn, Error::HttpClosedCriticalStream);
+    }
+
+    // Server: test missing SETTINGS frame
+    // (the first frame sent is a MAX_PUSH_ID frame).
+    #[test]
+    fn test_server_missing_settings() {
+        let (mut hconn, mut neqo_trans_conn) = connect_and_receive_settings();
+        // Create client control stream.
+        let control_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
+        // Send a MAX_PUSH_ID frame instead.
+        let sent = neqo_trans_conn.stream_send(control_stream, &[0x0, 0xd, 0x1, 0xf]);
+        assert_eq!(sent, Ok(4));
+        let out = neqo_trans_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+        assert_closed(&mut hconn, Error::HttpMissingSettings);
+    }
+
+    // Server: receiving SETTINGS frame twice causes connection close
+    // with error HTTP_UNEXPECTED_FRAME.
+    #[test]
+    fn test_server_receive_settings_twice() {
+        let (mut hconn, mut peer_conn) = connect();
+        // send the second SETTINGS frame.
+        let sent = peer_conn.conn.stream_send(
+            peer_conn.control_stream_id,
+            &[0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64],
+        );
+        assert_eq!(sent, Ok(8));
+        let out = peer_conn.conn.process(None, now());
+        hconn.process(out.dgram(), now());
+        assert_closed(&mut hconn, Error::HttpFrameUnexpected);
+    }
+
+    fn test_wrong_frame_on_control_stream(v: &[u8]) {
+        let (mut hconn, mut peer_conn) = connect();
+
+        // receive a frame that is not allowed on the control stream.
+        let _ = peer_conn.conn.stream_send(peer_conn.control_stream_id, v);
+
+        let out = peer_conn.conn.process(None, now());
+        hconn.process(out.dgram(), now());
+        assert_closed(&mut hconn, Error::HttpFrameUnexpected);
+    }
+
+    // send DATA frame on a cortrol stream
+    #[test]
+    fn test_server_data_frame_on_control_stream() {
+        test_wrong_frame_on_control_stream(&[0x0, 0x2, 0x1, 0x2]);
+    }
+
+    // send HEADERS frame on a cortrol stream
+    #[test]
+    fn test_server_headers_frame_on_control_stream() {
+        test_wrong_frame_on_control_stream(&[0x1, 0x2, 0x1, 0x2]);
+    }
+
+    // send PUSH_PROMISE frame on a cortrol stream
+    #[test]
+    fn test_server_push_promise_frame_on_control_stream() {
+        test_wrong_frame_on_control_stream(&[0x5, 0x2, 0x1, 0x2]);
+    }
+
+    // send DUPLICATE_PUSH frame on a cortrol stream
+    #[test]
+    fn test_server_duplicate_push_frame_on_control_stream() {
+        test_wrong_frame_on_control_stream(&[0xe, 0x2, 0x1, 0x2]);
+    }
+
+    // Server: receive unkonwn stream type
+    // also test getting stream id that does not fit into a single byte.
+    #[test]
+    fn test_server_received_unknown_stream() {
+        let (mut hconn, mut peer_conn) = connect();
+
+        // create a stream with unknown type.
+        let new_stream_id = peer_conn.conn.stream_create(StreamType::UniDi).unwrap();
+        let _ = peer_conn
+            .conn
+            .stream_send(new_stream_id, &[0x41, 0x19, 0x4, 0x4, 0x6, 0x0, 0x8, 0x0]);
+        let out = peer_conn.conn.process(None, now());
+        let out = hconn.process(out.dgram(), now());
+        peer_conn.conn.process(out.dgram(), now());
+        let out = hconn.process(None, now());
+        peer_conn.conn.process(out.dgram(), now());
+
+        // check for stop-sending with Error::HttpStreamCreationError.
+        let mut stop_sending_event_found = false;
+        while let Some(e) = peer_conn.conn.next_event() {
+            if let ConnectionEvent::SendStreamStopSending {
+                stream_id,
+                app_error,
+            } = e
+            {
+                stop_sending_event_found = true;
+                assert_eq!(stream_id, new_stream_id);
+                assert_eq!(app_error, Error::HttpStreamCreationError.code());
+            }
+        }
+        assert!(stop_sending_event_found);
+        assert_not_closed(&mut hconn);
+    }
+
+    // Server: receiving a push stream on a server should cause WrongStreamDirection
+    #[test]
+    fn test_server_received_push_stream() {
+        let (mut hconn, mut peer_conn) = connect();
+
+        // create a push stream.
+        let push_stream_id = peer_conn.conn.stream_create(StreamType::UniDi).unwrap();
+        let _ = peer_conn.conn.stream_send(push_stream_id, &[0x1]);
+        let out = peer_conn.conn.process(None, now());
+        let out = hconn.process(out.dgram(), now());
+        peer_conn.conn.process(out.dgram(), now());
+        assert_closed(&mut hconn, Error::HttpStreamCreationError);
+    }
+
+    //// Test reading of a slowly streamed frame. bytes are received one by one
+    #[test]
+    fn test_server_frame_reading() {
+        let (mut hconn, mut peer_conn) = connect_and_receive_settings();
+
+        // create a control stream.
+        let control_stream = peer_conn.stream_create(StreamType::UniDi).unwrap();
+
+        // send the stream type
+        let mut sent = peer_conn.stream_send(control_stream, &[0x0]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        // start sending SETTINGS frame
+        sent = peer_conn.stream_send(control_stream, &[0x4]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x4]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x6]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x0]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x8]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x0]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        assert_not_closed(&mut hconn);
+
+        // Now test PushPromise
+        sent = peer_conn.stream_send(control_stream, &[0x5]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x5]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        sent = peer_conn.stream_send(control_stream, &[0x4]);
+        assert_eq!(sent, Ok(1));
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        // PUSH_PROMISE on a control stream will cause an error
+        assert_closed(&mut hconn, Error::HttpFrameUnexpected);
+    }
+
+    // Test reading of a slowly streamed frame. bytes are received one by one
+    fn test_incomplet_frame(res: &[u8]) {
+        let (mut hconn, mut peer_conn) = connect_and_receive_settings();
+
+        // send an incomplete reequest.
+        let stream_id = peer_conn.stream_create(StreamType::BiDi).unwrap();
+        peer_conn.stream_send(stream_id, res).unwrap();
+        peer_conn.stream_close_send(stream_id).unwrap();
+
+        let out = peer_conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        assert_closed(&mut hconn, Error::HttpFrameError);
+    }
+
+    const REQUEST_WITH_BODY: &[u8] = &[
+        // headers
+        0x01, 0x10, 0x00, 0x00, 0xd1, 0xd7, 0x50, 0x89, 0x41, 0xe9, 0x2a, 0x67, 0x35, 0x53, 0x2e,
+        0x43, 0xd3, 0xc1, // the first data frame.
+        0x0, 0x3, 0x61, 0x62, 0x63, // the second data frame.
+        0x0, 0x3, 0x64, 0x65, 0x66,
+    ];
+
+    // Incomplete DATA frame
+    #[test]
+    fn test_server_incomplet_data_frame() {
+        test_incomplet_frame(&REQUEST_WITH_BODY[..22]);
+    }
+
+    // Incomplete HEADERS frame
+    #[test]
+    fn test_server_incomplet_headers_frame() {
+        test_incomplet_frame(&REQUEST_WITH_BODY[..10]);
+    }
+
+    #[test]
+    fn test_server_incomplet_unknown_frame() {
+        test_incomplet_frame(&[0x21]);
+    }
+
+    #[test]
+    fn test_server_request_with_body() {
+        let (mut hconn, mut peer_conn) = connect();
+
+        let stream_id = peer_conn.conn.stream_create(StreamType::BiDi).unwrap();
+        peer_conn
+            .conn
+            .stream_send(stream_id, REQUEST_WITH_BODY)
+            .unwrap();
+        peer_conn.conn.stream_close_send(stream_id).unwrap();
+
+        let out = peer_conn.conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        // Check connection event. There should be 1 Header and 2 data events.
+        let mut headers_frames = 0;
+        let mut data_frames = 0;
+        while let Some(event) = hconn.next_event() {
+            match event {
+                Http3ServerEvent::Headers { headers, fin, .. } => {
+                    assert_eq!(
+                        headers,
+                        vec![
+                            (String::from(":method"), String::from("GET")),
+                            (String::from(":scheme"), String::from("https")),
+                            (String::from(":authority"), String::from("something.com")),
+                            (String::from(":path"), String::from("/"))
+                        ]
+                    );
+                    assert_eq!(fin, false);
+                    headers_frames += 1;
+                }
+                Http3ServerEvent::Data {
+                    mut request,
+                    data,
+                    fin,
+                } => {
+                    if data_frames == 0 {
+                        assert_eq!(data, &REQUEST_WITH_BODY[20..23]);
+                    } else {
+                        assert_eq!(data, &REQUEST_WITH_BODY[25..]);
+                        assert_eq!(fin, true);
+                        request
+                            .set_response(
+                                &[
+                                    (String::from(":status"), String::from("200")),
+                                    (String::from("content-length"), String::from("3")),
+                                ],
+                                vec![0x67, 0x68, 0x69],
+                            )
+                            .unwrap();
+                    }
+                    data_frames += 1;
+                }
+                _ => {}
+            }
+        }
+        assert_eq!(headers_frames, 1);
+        assert_eq!(data_frames, 2);
+    }
+
+    #[test]
+    fn test_server_request_with_body_send_stop_sending() {
+        let (mut hconn, mut peer_conn) = connect();
+
+        let stream_id = peer_conn.conn.stream_create(StreamType::BiDi).unwrap();
+        // Send only request headers for now.
+        peer_conn
+            .conn
+            .stream_send(stream_id, &REQUEST_WITH_BODY[..20])
+            .unwrap();
+
+        let out = peer_conn.conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        // Check connection event. There should be 1 Header and no data events.
+        let mut headers_frames = 0;
+        while let Some(event) = hconn.next_event() {
+            match event {
+                Http3ServerEvent::Headers {
+                    mut request,
+                    headers,
+                    fin,
+                } => {
+                    assert_eq!(
+                        headers,
+                        vec![
+                            (String::from(":method"), String::from("GET")),
+                            (String::from(":scheme"), String::from("https")),
+                            (String::from(":authority"), String::from("something.com")),
+                            (String::from(":path"), String::from("/"))
+                        ]
+                    );
+                    assert_eq!(fin, false);
+                    headers_frames += 1;
+                    request
+                        .stream_stop_sending(Error::HttpEarlyResponse.code())
+                        .unwrap();
+                    request
+                        .set_response(
+                            &[
+                                (String::from(":status"), String::from("200")),
+                                (String::from("content-length"), String::from("3")),
+                            ],
+                            vec![0x67, 0x68, 0x69],
+                        )
+                        .unwrap();
+                }
+                Http3ServerEvent::Data { .. } => {
+                    panic!("We should not have a Data event");
+                }
+                _ => {}
+            }
+        }
+        let out = hconn.process(None, now());
+
+        // Send data.
+        peer_conn
+            .conn
+            .stream_send(stream_id, &REQUEST_WITH_BODY[20..])
+            .unwrap();
+        peer_conn.conn.stream_close_send(stream_id).unwrap();
+
+        let out = peer_conn.conn.process(out.dgram(), now());
+        hconn.process(out.dgram(), now());
+
+        while let Some(event) = hconn.next_event() {
+            match event {
+                Http3ServerEvent::Headers { .. } => {
+                    panic!("We should not have a Data event");
+                }
+                Http3ServerEvent::Data { .. } => {
+                    panic!("We should not have a Data event");
+                }
+                _ => {}
+            }
+        }
+        assert_eq!(headers_frames, 1);
+    }
+
+    #[test]
+    fn test_server_request_with_body_server_reset() {
+        let (mut hconn, mut peer_conn) = connect();
+
+        let request_stream_id = peer_conn.conn.stream_create(StreamType::BiDi).unwrap();
+        // Send only request headers for now.
+        peer_conn
+            .conn
+            .stream_send(request_stream_id, &REQUEST_WITH_BODY[..20])
+            .unwrap();
+
+        let out = peer_conn.conn.process(None, now());
+        hconn.process(out.dgram(), now());
+
+        // Check connection event. There should be 1 Header and no data events.
+        // The server will reset the stream.
+        let mut headers_frames = 0;
+        while let Some(event) = hconn.next_event() {
+            match event {
+                Http3ServerEvent::Headers {
+                    mut request,
+                    headers,
+                    fin,
+                } => {
+                    assert_eq!(
+                        headers,
+                        vec![
+                            (String::from(":method"), String::from("GET")),
+                            (String::from(":scheme"), String::from("https")),
+                            (String::from(":authority"), String::from("something.com")),
+                            (String::from(":path"), String::from("/"))
+                        ]
+                    );
+                    assert_eq!(fin, false);
+                    headers_frames += 1;
+                    request
+                        .stream_reset(Error::HttpRequestRejected.code())
+                        .unwrap();
+                }
+                Http3ServerEvent::Data { .. } => {
+                    panic!("We should not have a Data event");
+                }
+                _ => {}
+            }
+        }
+        let out = hconn.process(None, now());
+
+        let out = peer_conn.conn.process(out.dgram(), now());
+        hconn.process(out.dgram(), now());
+
+        // Check that STOP_SENDING and REET has been received.
+        let mut reset = 0;
+        let mut stop_sending = 0;
+        while let Some(event) = peer_conn.conn.next_event() {
+            match event {
+                ConnectionEvent::RecvStreamReset { stream_id, .. } => {
+                    assert_eq!(request_stream_id, stream_id);
+                    reset += 1;
+                }
+                ConnectionEvent::SendStreamStopSending { stream_id, .. } => {
+                    assert_eq!(request_stream_id, stream_id);
+                    stop_sending += 1;
+                }
+                _ => {}
+            }
+        }
+        assert_eq!(headers_frames, 1);
+        assert_eq!(reset, 1);
+        assert_eq!(stop_sending, 1);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/neqo-http3/src/server_connection_events.rs
@@ -0,0 +1,97 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::connection::{Http3Events, Http3State};
+use crate::Header;
+use neqo_common::matches;
+use neqo_transport::AppError;
+
+use std::cell::RefCell;
+use std::collections::VecDeque;
+use std::rc::Rc;
+
+#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone)]
+pub enum Http3ServerConnEvent {
+    /// Headers are ready.
+    Headers {
+        stream_id: u64,
+        headers: Vec<Header>,
+        fin: bool,
+    },
+    /// Request data is ready.
+    Data {
+        stream_id: u64,
+        data: Vec<u8>,
+        fin: bool,
+    },
+    /// Peer reset the stream.
+    Reset { stream_id: u64, error: AppError },
+    /// Connection state change.
+    StateChange(Http3State),
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct Http3ServerConnEvents {
+    events: Rc<RefCell<VecDeque<Http3ServerConnEvent>>>,
+}
+
+impl Http3ServerConnEvents {
+    fn insert(&self, event: Http3ServerConnEvent) {
+        self.events.borrow_mut().push_back(event);
+    }
+
+    fn remove<F>(&self, f: F)
+    where
+        F: Fn(&Http3ServerConnEvent) -> bool,
+    {
+        self.events.borrow_mut().retain(|evt| !f(evt))
+    }
+
+    pub fn events(&self) -> impl Iterator<Item = Http3ServerConnEvent> {
+        self.events.replace(VecDeque::new()).into_iter()
+    }
+
+    pub fn has_events(&self) -> bool {
+        !self.events.borrow().is_empty()
+    }
+
+    pub fn next_event(&self) -> Option<Http3ServerConnEvent> {
+        self.events.borrow_mut().pop_front()
+    }
+
+    pub fn headers(&self, stream_id: u64, headers: Vec<Header>, fin: bool) {
+        self.insert(Http3ServerConnEvent::Headers {
+            stream_id,
+            headers,
+            fin,
+        });
+    }
+
+    pub fn data(&self, stream_id: u64, data: Vec<u8>, fin: bool) {
+        self.insert(Http3ServerConnEvent::Data {
+            stream_id,
+            data,
+            fin,
+        });
+    }
+}
+
+impl Http3Events for Http3ServerConnEvents {
+    fn reset(&self, stream_id: u64, error: AppError) {
+        self.insert(Http3ServerConnEvent::Reset { stream_id, error });
+    }
+
+    fn connection_state_change(&self, state: Http3State) {
+        self.insert(Http3ServerConnEvent::StateChange(state));
+    }
+
+    fn remove_events_for_stream_id(&self, stream_id: u64) {
+        self.remove(|evt| {
+            matches!(evt,
+                Http3ServerConnEvent::Reset { stream_id: x, .. } if *x == stream_id)
+        });
+    }
+}
--- a/third_party/rust/neqo-http3/src/server_events.rs
+++ b/third_party/rust/neqo-http3/src/server_events.rs
@@ -1,97 +1,184 @@
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use crate::connection::{Http3Events, Http3State};
-use crate::Header;
-use neqo_common::matches;
-use neqo_transport::AppError;
+use crate::connection::{Http3Connection, Http3ServerHandler, Http3State};
+use crate::server_connection_events::{Http3ServerConnEvent, Http3ServerConnEvents};
+use crate::transaction_server::TransactionServer;
+use crate::{Error, Header, Res};
+use neqo_common::{qdebug, qinfo};
+use neqo_transport::server::ActiveConnectionRef;
+use neqo_transport::{AppError, Connection};
 
 use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::rc::Rc;
+use std::time::Instant;
 
-#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone)]
+pub type Http3ServerConnection =
+    Http3Connection<Http3ServerConnEvents, TransactionServer, Http3ServerHandler>;
+
+#[derive(Debug)]
+pub struct Http3Handler {
+    handler: Http3ServerConnection,
+}
+
+impl Http3Handler {
+    pub fn new(max_table_size: u32, max_blocked_streams: u16) -> Self {
+        Http3Handler {
+            handler: Http3Connection::new(max_table_size, max_blocked_streams),
+        }
+    }
+    pub fn set_response(&mut self, stream_id: u64, headers: &[Header], data: Vec<u8>) -> Res<()> {
+        self.handler
+            .transactions
+            .get_mut(&stream_id)
+            .ok_or(Error::InvalidStreamId)?
+            .set_response(headers, data, &mut self.handler.qpack_encoder);
+        self.handler.insert_streams_have_data_to_send(stream_id);
+        Ok(())
+    }
+
+    pub fn stream_reset(
+        &mut self,
+        conn: &mut Connection,
+        stream_id: u64,
+        app_error: AppError,
+    ) -> Res<()> {
+        self.handler.stream_reset(conn, stream_id, app_error)
+    }
+
+    pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) {
+        self.handler.process_http3(conn, now);
+    }
+
+    pub fn next_event(&mut self) -> Option<Http3ServerConnEvent> {
+        self.handler.events.next_event()
+    }
+
+    pub fn should_be_processed(&self) -> bool {
+        self.handler.has_data_to_send() | self.handler.events.has_events()
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct ClientRequestStream {
+    conn: ActiveConnectionRef,
+    handler: Rc<RefCell<Http3Handler>>,
+    stream_id: u64,
+}
+
+impl ::std::fmt::Display for ClientRequestStream {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        let conn: &Connection = &self.conn.borrow();
+        write!(
+            f,
+            "Http3 server conn={:?} stream_id={}",
+            conn, self.stream_id
+        )
+    }
+}
+
+impl ClientRequestStream {
+    pub fn new(
+        conn: ActiveConnectionRef,
+        handler: Rc<RefCell<Http3Handler>>,
+        stream_id: u64,
+    ) -> Self {
+        ClientRequestStream {
+            conn,
+            handler,
+            stream_id,
+        }
+    }
+    pub fn set_response(&mut self, headers: &[Header], data: Vec<u8>) -> Res<()> {
+        qinfo!([self], "Set new response.");
+        self.handler
+            .borrow_mut()
+            .set_response(self.stream_id, headers, data)
+    }
+
+    pub fn stream_stop_sending(&mut self, app_error: AppError) -> Res<()> {
+        qdebug!(
+            [self],
+            "stop sending stream_id:{} error:{}.",
+            self.stream_id,
+            app_error
+        );
+        self.conn
+            .borrow_mut()
+            .stream_stop_sending(self.stream_id, app_error)?;
+        Ok(())
+    }
+
+    pub fn stream_reset(&mut self, app_error: AppError) -> Res<()> {
+        qdebug!([self], "reset error:{}.", app_error);
+        self.handler.borrow_mut().stream_reset(
+            &mut self.conn.borrow_mut(),
+            self.stream_id,
+            app_error,
+        )
+    }
+}
+
+#[derive(Debug, Clone)]
 pub enum Http3ServerEvent {
     /// Headers are ready.
     Headers {
-        stream_id: u64,
+        request: ClientRequestStream,
         headers: Vec<Header>,
         fin: bool,
     },
     /// Request data is ready.
     Data {
-        stream_id: u64,
+        request: ClientRequestStream,
         data: Vec<u8>,
         fin: bool,
     },
-    /// Peer reset the stream.
-    Reset { stream_id: u64, error: AppError },
-    /// Connection state change.
-    StateChange(Http3State),
+    /// When individual connection change state. It is only used for tests.
+    StateChange {
+        conn: ActiveConnectionRef,
+        state: Http3State,
+    },
 }
 
 #[derive(Debug, Default, Clone)]
 pub struct Http3ServerEvents {
     events: Rc<RefCell<VecDeque<Http3ServerEvent>>>,
 }
 
 impl Http3ServerEvents {
     fn insert(&self, event: Http3ServerEvent) {
         self.events.borrow_mut().push_back(event);
     }
 
-    fn remove<F>(&self, f: F)
-    where
-        F: Fn(&Http3ServerEvent) -> bool,
-    {
-        self.events.borrow_mut().retain(|evt| !f(evt))
-    }
-
     pub fn events(&self) -> impl Iterator<Item = Http3ServerEvent> {
         self.events.replace(VecDeque::new()).into_iter()
     }
 
     pub fn has_events(&self) -> bool {
         !self.events.borrow().is_empty()
     }
 
     pub fn next_event(&self) -> Option<Http3ServerEvent> {
         self.events.borrow_mut().pop_front()
     }
 
-    pub fn headers(&self, stream_id: u64, headers: Vec<Header>, fin: bool) {
+    pub fn headers(&self, request: ClientRequestStream, headers: Vec<Header>, fin: bool) {
         self.insert(Http3ServerEvent::Headers {
-            stream_id,
+            request,
             headers,
             fin,
         });
     }
 
-    pub fn data(&self, stream_id: u64, data: Vec<u8>, fin: bool) {
-        self.insert(Http3ServerEvent::Data {
-            stream_id,
-            data,
-            fin,
-        });
+    pub fn connection_state_change(&self, conn: ActiveConnectionRef, state: Http3State) {
+        self.insert(Http3ServerEvent::StateChange { conn, state });
+    }
+
+    pub fn data(&self, request: ClientRequestStream, data: Vec<u8>, fin: bool) {
+        self.insert(Http3ServerEvent::Data { request, data, fin });
     }
 }
-
-impl Http3Events for Http3ServerEvents {
-    fn reset(&self, stream_id: u64, error: AppError) {
-        self.insert(Http3ServerEvent::Reset { stream_id, error });
-    }
-
-    fn connection_state_change(&self, state: Http3State) {
-        self.insert(Http3ServerEvent::StateChange(state));
-    }
-
-    fn remove_events_for_stream_id(&self, stream_id: u64) {
-        self.remove(|evt| {
-            matches!(evt,
-                Http3ServerEvent::Reset { stream_id: x, .. } if *x == stream_id)
-        });
-    }
-}
--- a/third_party/rust/neqo-http3/src/stream_type_reader.rs
+++ b/third_party/rust/neqo-http3/src/stream_type_reader.rs
@@ -41,17 +41,22 @@ impl NewStreamTypeReader {
                         }
                         IncrementalDecoderResult::InProgress => {}
                         _ => {
                             return None;
                         }
                     }
                 }
                 Err(e) => {
-                    qdebug!([conn] "Error reading stream type for stream {}: {:?}", stream_id, e);
+                    qdebug!(
+                        [conn],
+                        "Error reading stream type for stream {}: {:?}",
+                        stream_id,
+                        e
+                    );
                     self.fin = true;
                     return None;
                 }
             }
         }
     }
 
     pub fn fin(&self) -> bool {
--- a/third_party/rust/neqo-http3/src/transaction_client.rs
+++ b/third_party/rust/neqo-http3/src/transaction_client.rs
@@ -53,17 +53,17 @@ impl Request {
         r
     }
 
     pub fn ensure_encoded(&mut self, encoder: &mut QPackEncoder, stream_id: u64) {
         if self.buf.is_some() {
             return;
         }
 
-        qinfo!([self] "Encoding headers for {}/{}", self.host, self.path);
+        qinfo!([self], "Encoding headers for {}/{}", self.host, self.path);
         let encoded_headers = encoder.encode_header_block(&self.headers, stream_id);
         let f = HFrame::Headers {
             len: encoded_headers.len() as u64,
         };
         let mut d = Encoder::default();
         f.encode(&mut d);
         d.encode(&encoded_headers[..]);
         self.buf = Some(d.into());
@@ -78,20 +78,20 @@ impl Request {
         let label = if ::log::log_enabled!(::log::Level::Debug) {
             format!("{}", self)
         } else {
             String::new()
         };
         self.ensure_encoded(encoder, stream_id);
         if let Some(buf) = &mut self.buf {
             let sent = conn.stream_send(stream_id, &buf)?;
-            qinfo!([label] "{} bytes sent", sent);
+            qinfo!([label], "{} bytes sent", sent);
 
             if sent == buf.len() {
-                qinfo!([label] "done sending request");
+                qinfo!([label], "done sending request");
                 Ok(true)
             } else {
                 let b = buf.split_off(sent);
                 self.buf = Some(b);
                 Ok(false)
             }
         } else {
             panic!("We must have buffer in this state")
@@ -191,17 +191,22 @@ impl TransactionClient {
             stream_id,
             response_headers_state: ResponseHeadersState::NoHeaders,
             frame_reader: HFrameReader::new(),
             conn_events,
         }
     }
 
     pub fn send_request_body(&mut self, conn: &mut Connection, buf: &[u8]) -> Res<usize> {
-        qinfo!([self] "send_request_body: send_state={:?} len={}", self.send_state, buf.len());
+        qinfo!(
+            [self],
+            "send_request_body: send_state={:?} len={}",
+            self.send_state,
+            buf.len()
+        );
         match self.send_state {
             TransactionSendState::SendingHeaders { .. } => Ok(0),
             TransactionSendState::SendingData => {
                 let available = conn.stream_avail_send_space(self.stream_id)? as usize;
                 if available <= 2 {
                     return Ok(0);
                 }
                 let to_send;
@@ -213,17 +218,22 @@ impl TransactionClient {
                     to_send = min(min(buf.len(), available - 3), MAX_DATA_HEADER_SIZE_3);
                 } else if available <= MAX_DATA_HEADER_SIZE_5 {
                     // 1073741823 + 9
                     to_send = min(min(buf.len(), available - 5), MAX_DATA_HEADER_SIZE_5_LIMIT);
                 } else {
                     to_send = min(buf.len(), available - 9);
                 }
 
-                qinfo!([self] "send_request_body: available={} to_send={}.", available, to_send);
+                qinfo!(
+                    [self],
+                    "send_request_body: available={} to_send={}.",
+                    available,
+                    to_send
+                );
 
                 let data_frame = HFrame::Data {
                     len: to_send as u64,
                 };
                 let mut enc = Encoder::default();
                 data_frame.encode(&mut enc);
                 match conn.stream_send(self.stream_id, &enc) {
                     Ok(sent) => {
@@ -236,17 +246,22 @@ impl TransactionClient {
                     Err(e) => Err(Error::TransportError(e)),
                 }
             }
             TransactionSendState::Closed => Err(Error::AlreadyClosed),
         }
     }
 
     fn handle_frame_in_state_waiting_for_headers(&mut self, frame: HFrame, fin: bool) -> Res<()> {
-        qinfo!([self] "A new frame has been received: {:?}; state={:?}", frame, self.recv_state);
+        qinfo!(
+            [self],
+            "A new frame has been received: {:?}; state={:?}",
+            frame,
+            self.recv_state
+        );
         match frame {
             HFrame::Headers { len } => self.handle_headers_frame(len, fin),
             HFrame::PushPromise { .. } => Err(Error::HttpIdError),
             _ => Err(Error::HttpFrameUnexpected),
         }
     }
 
     fn handle_headers_frame(&mut self, len: u64, fin: bool) -> Res<()> {
@@ -260,17 +275,22 @@ impl TransactionClient {
                 buf: vec![0; len as usize],
                 offset: 0,
             };
             Ok(())
         }
     }
 
     fn handle_frame_in_state_waiting_for_data(&mut self, frame: HFrame, fin: bool) -> Res<()> {
-        qinfo!([self] "A new frame has been received: {:?}; state={:?}", frame, self.recv_state);
+        qinfo!(
+            [self],
+            "A new frame has been received: {:?}; state={:?}",
+            frame,
+            self.recv_state
+        );
         match frame {
             HFrame::Data { len } => self.handle_data_frame(len, fin),
             HFrame::PushPromise { .. } => Err(Error::HttpIdError),
             HFrame::Headers { .. } => {
                 // TODO implement trailers!
                 Err(Error::HttpFrameUnexpected)
             }
             _ => Err(Error::HttpFrameUnexpected),
@@ -297,44 +317,48 @@ impl TransactionClient {
         self.conn_events.header_ready(self.stream_id);
         self.recv_state = TransactionRecvState::WaitingForData;
         Ok(())
     }
 
     fn set_state_to_close_pending(&mut self) {
         // Stream has received fin. Depending on headers state set header_ready
         // or data_readable event so that app can pick up the fin.
-        qdebug!([self] "set_state_to_close_pending:  response_headers_state={:?}", self.response_headers_state);
+        qdebug!(
+            [self],
+            "set_state_to_close_pending:  response_headers_state={:?}",
+            self.response_headers_state
+        );
         match self.response_headers_state {
             ResponseHeadersState::NoHeaders => {
                 self.conn_events.header_ready(self.stream_id);
                 self.response_headers_state = ResponseHeadersState::Ready(None);
             }
             // In Ready state we are already waiting for app to pick up headers
             // it can also pick up fin, so we do not need a new event.
             ResponseHeadersState::Ready(..) => {}
             ResponseHeadersState::Read => self.conn_events.data_readable(self.stream_id),
         }
         self.recv_state = TransactionRecvState::ClosePending;
     }
 
     fn recv_frame_header(&mut self, conn: &mut Connection) -> Res<Option<(HFrame, bool)>> {
-        qtrace!([self] "receiving frame header");
+        qtrace!([self], "receiving frame header");
         let fin = self.frame_reader.receive(conn, self.stream_id)?;
         if !self.frame_reader.done() {
             if fin {
                 //we have received stream fin while waiting for a frame.
                 // !self.frame_reader.done() means that we do not have a new
                 // frame at all. Set state to ClosePending and waith for app
                 // to pick up fin.
                 self.set_state_to_close_pending();
             }
             Ok(None)
         } else {
-            qdebug!([self] "A new frame has been received.");
+            qdebug!([self], "A new frame has been received.");
             Ok(Some((self.frame_reader.get_frame()?, fin)))
         }
     }
 
     fn read_headers_frame_body(
         &mut self,
         conn: &mut Connection,
         decoder: &mut QPackDecoder,
@@ -345,28 +369,31 @@ impl TransactionClient {
             String::new()
         };
         if let TransactionRecvState::ReadingHeaders {
             ref mut buf,
             ref mut offset,
         } = self.recv_state
         {
             let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[*offset..])?;
-            qdebug!([label] "read_headers: read {} bytes fin={}.", amount, fin);
+            qdebug!([label], "read_headers: read {} bytes fin={}.", amount, fin);
             *offset += amount as usize;
             if *offset < buf.len() {
                 if fin {
                     // Malformated frame
                     return Err(Error::HttpFrameError);
                 }
                 return Ok(true);
             }
 
             // we have read the headers, try decoding them.
-            qinfo!([label] "read_headers: read all headers, try decoding them.");
+            qinfo!(
+                [label],
+                "read_headers: read all headers, try decoding them."
+            );
             match decoder.decode_header_block(buf, self.stream_id)? {
                 Some(headers) => {
                     self.add_headers(Some(headers))?;
                     if fin {
                         self.set_state_to_close_pending();
                     }
                     Ok(fin)
                 }
@@ -464,35 +491,40 @@ impl Http3Transaction for TransactionCli
             ref mut request,
             fin,
         } = self.send_state
         {
             if request.send(conn, encoder, self.stream_id)? {
                 if fin {
                     conn.stream_close_send(self.stream_id)?;
                     self.send_state = TransactionSendState::Closed;
-                    qinfo!([label] "done sending request");
+                    qinfo!([label], "done sending request");
                 } else {
                     self.send_state = TransactionSendState::SendingData;
                     self.conn_events.data_writable(self.stream_id);
-                    qinfo!([label] "change to state SendingData");
+                    qinfo!([label], "change to state SendingData");
                 }
             }
         }
         Ok(())
     }
 
     fn receive(&mut self, conn: &mut Connection, decoder: &mut QPackDecoder) -> Res<()> {
         let label = if ::log::log_enabled!(::log::Level::Debug) {
             format!("{}", self)
         } else {
             String::new()
         };
         loop {
-            qdebug!([label] "send_state={:?} recv_state={:?}.", self.send_state, self.recv_state);
+            qdebug!(
+                [label],
+                "send_state={:?} recv_state={:?}.",
+                self.send_state,
+                self.recv_state
+            );
             match self.recv_state {
                 TransactionRecvState::WaitingForResponseHeaders => {
                     match self.recv_frame_header(conn)? {
                         None => break Ok(()),
                         Some((f, fin)) => {
                             self.handle_frame_in_state_waiting_for_headers(f, fin)?;
                             if fin {
                                 self.set_state_to_close_pending();
@@ -511,17 +543,17 @@ impl Http3Transaction for TransactionCli
                         Some(headers) => {
                             self.add_headers(Some(headers))?;
                             if fin {
                                 self.set_state_to_close_pending();
                                 break Ok(());
                             }
                         }
                         None => {
-                            qinfo!([self] "decoding header is blocked.");
+                            qinfo!([self], "decoding header is blocked.");
                             break Ok(());
                         }
                     }
                 }
                 TransactionRecvState::WaitingForData => {
                     match self.recv_frame_header(conn)? {
                         None => break Ok(()),
                         Some((f, fin)) => {
--- a/third_party/rust/neqo-http3/src/transaction_server.rs
+++ b/third_party/rust/neqo-http3/src/transaction_server.rs
@@ -1,20 +1,20 @@
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 use crate::connection::Http3Transaction;
 use crate::hframe::{HFrame, HFrameReader};
-use crate::server_events::Http3ServerEvents;
+use crate::server_connection_events::Http3ServerConnEvents;
 use crate::Header;
 use crate::{Error, Res};
-use neqo_common::{qdebug, qinfo, qtrace, Encoder};
+use neqo_common::{matches, qdebug, qinfo, qtrace, Encoder};
 use neqo_qpack::decoder::QPackDecoder;
 use neqo_qpack::encoder::QPackEncoder;
 use neqo_transport::Connection;
 use std::mem;
 
 #[derive(PartialEq, Debug)]
 enum TransactionRecvState {
     WaitingForHeaders,
@@ -33,59 +33,59 @@ enum TransactionSendState {
 }
 
 #[derive(Debug)]
 pub struct TransactionServer {
     recv_state: TransactionRecvState,
     send_state: TransactionSendState,
     stream_id: u64,
     frame_reader: HFrameReader,
-    conn_events: Http3ServerEvents,
+    conn_events: Http3ServerConnEvents,
 }
 
 impl TransactionServer {
-    pub fn new(stream_id: u64, conn_events: Http3ServerEvents) -> TransactionServer {
+    pub fn new(stream_id: u64, conn_events: Http3ServerConnEvents) -> TransactionServer {
         qinfo!("Create a request stream_id={}", stream_id);
         TransactionServer {
             recv_state: TransactionRecvState::WaitingForHeaders,
             send_state: TransactionSendState::Initial,
             stream_id,
             frame_reader: HFrameReader::new(),
             conn_events,
         }
     }
 
     pub fn set_response(&mut self, headers: &[Header], data: Vec<u8>, encoder: &mut QPackEncoder) {
-        qdebug!([self] "Encoding headers");
+        qdebug!([self], "Encoding headers");
         let encoded_headers = encoder.encode_header_block(&headers, self.stream_id);
         let hframe = HFrame::Headers {
             len: encoded_headers.len() as u64,
         };
         let mut d = Encoder::default();
         hframe.encode(&mut d);
         d.encode(&encoded_headers);
         if !data.is_empty() {
-            qdebug!([self] "Encoding data");
+            qdebug!([self], "Encoding data");
             let d_frame = HFrame::Data {
                 len: data.len() as u64,
             };
             d_frame.encode(&mut d);
             d.encode(&data);
         }
 
         self.send_state = TransactionSendState::SendingResponse { buf: d.into() };
     }
 
     fn recv_frame_header(&mut self, conn: &mut Connection) -> Res<(Option<HFrame>, bool)> {
-        qtrace!([self] "receiving frame header");
+        qtrace!([self], "receiving frame header");
         let fin = self.frame_reader.receive(conn, self.stream_id)?;
         if !self.frame_reader.done() {
             Ok((None, fin))
         } else {
-            qinfo!([self] "A new frame has been received.");
+            qinfo!([self], "A new frame has been received.");
             Ok((Some(self.frame_reader.get_frame()?), fin))
         }
     }
 
     fn read_headers_frame_body(
         &mut self,
         conn: &mut Connection,
         decoder: &mut QPackDecoder,
@@ -96,28 +96,31 @@ impl TransactionServer {
             String::new()
         };
         if let TransactionRecvState::ReadingHeaders {
             ref mut buf,
             ref mut offset,
         } = self.recv_state
         {
             let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[*offset..])?;
-            qdebug!([label] "read_headers: read {} bytes fin={}.", amount, fin);
+            qdebug!([label], "read_headers: read {} bytes fin={}.", amount, fin);
             *offset += amount as usize;
             if *offset < buf.len() {
                 if fin {
                     // Malformed frame
                     return Err(Error::HttpFrameError);
                 }
                 return Ok(true);
             }
 
             // we have read the headers, try decoding them.
-            qinfo!([label] "read_headers: read all headers, try decoding them.");
+            qinfo!(
+                [label],
+                "read_headers: read all headers, try decoding them."
+            );
             match decoder.decode_header_block(buf, self.stream_id)? {
                 Some(headers) => {
                     self.conn_events.headers(self.stream_id, headers, fin);
                     if fin {
                         self.recv_state = TransactionRecvState::Closed;
                     } else {
                         self.recv_state = TransactionRecvState::WaitingForData;
                     }
@@ -132,49 +135,49 @@ impl TransactionServer {
                 }
             }
         } else {
             panic!("This is only called when recv_state is ReadingHeaders.");
         }
     }
 
     fn handle_frame_in_state_waiting_for_headers(&mut self, frame: HFrame, fin: bool) -> Res<()> {
-        qdebug!([self] "A new frame has been received: {:?}", frame);
+        qdebug!([self], "A new frame has been received: {:?}", frame);
         match frame {
             HFrame::Headers { len } => self.handle_headers_frame(len, fin),
             _ => Err(Error::HttpFrameUnexpected),
         }
     }
 
     fn handle_frame_in_state_waiting_for_data(&mut self, frame: HFrame, fin: bool) -> Res<()> {
-        qdebug!([self] "A new frame has been received: {:?}", frame);
+        qdebug!([self], "A new frame has been received: {:?}", frame);
         match frame {
             HFrame::Data { len } => self.handle_data_frame(len, fin),
             _ => Err(Error::HttpFrameUnexpected),
         }
     }
 
     fn handle_headers_frame(&mut self, len: u64, fin: bool) -> Res<()> {
-        qinfo!([self] "A new header frame len={} fin={}", len, fin);
+        qinfo!([self], "A new header frame len={} fin={}", len, fin);
         if len == 0 {
             self.conn_events.headers(self.stream_id, Vec::new(), fin);
         } else {
             if fin {
                 return Err(Error::HttpFrameError);
             }
             self.recv_state = TransactionRecvState::ReadingHeaders {
                 buf: vec![0; len as usize],
                 offset: 0,
             };
         }
         Ok(())
     }
 
     fn handle_data_frame(&mut self, len: u64, fin: bool) -> Res<()> {
-        qinfo!([self] "A new data frame len={} fin={}", len, fin);
+        qinfo!([self], "A new data frame len={} fin={}", len, fin);
         if len > 0 {
             if fin {
                 return Err(Error::HttpFrameError);
             }
             self.recv_state = TransactionRecvState::ReadingData {
                 remaining_data_len: len as usize,
             };
         } else if fin {
@@ -188,29 +191,29 @@ impl TransactionServer {
 impl ::std::fmt::Display for TransactionServer {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "TransactionServer {}", self.stream_id)
     }
 }
 
 impl Http3Transaction for TransactionServer {
     fn send(&mut self, conn: &mut Connection, _encoder: &mut QPackEncoder) -> Res<()> {
-        qtrace!([self] "Sending response.");
+        qtrace!([self], "Sending response.");
         let label = if ::log::log_enabled!(::log::Level::Debug) {
             format!("{}", self)
         } else {
             String::new()
         };
         if let TransactionSendState::SendingResponse { ref mut buf } = self.send_state {
             let sent = conn.stream_send(self.stream_id, &buf[..])?;
-            qinfo!([label] "{} bytes sent", sent);
+            qinfo!([label], "{} bytes sent", sent);
             if sent == buf.len() {
                 conn.stream_close_send(self.stream_id)?;
                 self.send_state = TransactionSendState::Closed;
-                qinfo!([label] "done sending request");
+                qinfo!([label], "done sending request");
             } else {
                 let mut b = buf.split_off(sent);
                 mem::swap(buf, &mut b);
             }
         }
 
         Ok(())
     }
@@ -218,17 +221,21 @@ impl Http3Transaction for TransactionSer
     fn receive(&mut self, conn: &mut Connection, decoder: &mut QPackDecoder) -> Res<()> {
         let label = if ::log::log_enabled!(::log::Level::Debug) {
             format!("{}", self)
         } else {
             String::new()
         };
 
         loop {
-            qtrace!([label] "[recv_state={:?}] receiving data.", self.recv_state);
+            qtrace!(
+                [label],
+                "[recv_state={:?}] receiving data.",
+                self.recv_state
+            );
             match self.recv_state {
                 TransactionRecvState::WaitingForHeaders => {
                     let (f, fin) = self.recv_frame_header(conn)?;
                     match f {
                         None => {
                             if fin {
                                 self.conn_events.headers(self.stream_id, Vec::new(), true);
                                 self.recv_state = TransactionRecvState::Closed;
@@ -253,17 +260,17 @@ impl Http3Transaction for TransactionSer
                     match decoder.decode_header_block(buf, self.stream_id)? {
                         Some(headers) => {
                             self.conn_events.headers(self.stream_id, headers, fin);
                             if fin {
                                 return Ok(());
                             }
                         }
                         None => {
-                            qinfo!([self] "decoding header is blocked.");
+                            qinfo!([self], "decoding header is blocked.");
                             return Ok(());
                         }
                     }
                 }
                 TransactionRecvState::WaitingForData => {
                     let (f, fin) = self.recv_frame_header(conn)?;
                     match f {
                         None => {
@@ -318,21 +325,17 @@ impl Http3Transaction for TransactionSer
                 TransactionRecvState::Closed => {
                     panic!("Stream readable after being closed!");
                 }
             };
         }
     }
 
     fn has_data_to_send(&self) -> bool {
-        if let TransactionSendState::SendingResponse { .. } = self.send_state {
-            true
-        } else {
-            false
-        }
+        matches!(self.send_state, TransactionSendState::SendingResponse { .. })
     }
 
     fn is_state_sending_data(&self) -> bool {
         self.has_data_to_send()
     }
 
     fn reset_receiving_side(&mut self) {}
 
--- a/third_party/rust/neqo-http3/tests/httpconn.rs
+++ b/third_party/rust/neqo-http3/tests/httpconn.rs
@@ -8,44 +8,44 @@
 
 use neqo_common::{matches, Datagram};
 use neqo_crypto::AuthenticationStatus;
 use neqo_http3::{Http3Client, Http3ClientEvent, Http3Server, Http3ServerEvent, Http3State};
 use test_fixture::*;
 
 const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
 
-fn process_server_events(conn: &mut Http3Server) {
+fn process_server_events(server: &mut Http3Server) {
     let mut request_found = false;
-    while let Some(event) = conn.next_event() {
+    while let Some(event) = server.next_event() {
         if let Http3ServerEvent::Headers {
-            stream_id,
+            mut request,
             headers,
             fin,
         } = event
         {
             assert_eq!(
                 headers,
                 vec![
                     (String::from(":method"), String::from("GET")),
                     (String::from(":scheme"), String::from("https")),
                     (String::from(":authority"), String::from("something.com")),
                     (String::from(":path"), String::from("/"))
                 ]
             );
             assert_eq!(fin, true);
-            conn.set_response(
-                stream_id,
-                &[
-                    (String::from(":status"), String::from("200")),
-                    (String::from("content-length"), String::from("3")),
-                ],
-                RESPONSE_DATA.to_vec(),
-            )
-            .unwrap();
+            request
+                .set_response(
+                    &[
+                        (String::from(":status"), String::from("200")),
+                        (String::from("content-length"), String::from("3")),
+                    ],
+                    RESPONSE_DATA.to_vec(),
+                )
+                .unwrap();
             request_found = true;
         }
     }
     assert_eq!(request_found, true);
 }
 
 fn process_client_events(conn: &mut Http3Client) {
     let mut response_header_found = false;
@@ -81,28 +81,26 @@ fn process_client_events(conn: &mut Http
     assert_eq!(response_data_found, true)
 }
 
 fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
     let mut hconn_c = default_http3_client();
     let mut hconn_s = default_http3_server();
 
     assert_eq!(hconn_c.state(), Http3State::Initializing);
-    assert_eq!(hconn_s.state(), Http3State::Initializing);
     let out = hconn_c.process(None, now()); // Initial
     let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake
     let out = hconn_c.process(out.dgram(), now()); // ACK
     let _ = hconn_s.process(out.dgram(), now()); //consume ACK
     let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
     assert!(hconn_c.events().any(authentication_needed));
     hconn_c.authenticated(AuthenticationStatus::Ok, now());
     let out = hconn_c.process(None, now()); // Handshake
     assert_eq!(hconn_c.state(), Http3State::Connected);
     let out = hconn_s.process(out.dgram(), now()); // Handshake
-    assert_eq!(hconn_s.state(), Http3State::Connected);
     let out = hconn_c.process(out.dgram(), now());
     let out = hconn_s.process(out.dgram(), now());
     // assert_eq!(hconn_s.settings_received, true);
     let out = hconn_c.process(out.dgram(), now());
     // assert_eq!(hconn_c.settings_received, true);
 
     (hconn_c, hconn_s, out.dgram())
 }
@@ -126,10 +124,12 @@ fn test_fetch() {
     eprintln!("-----server");
     let out = hconn_s.process(out.dgram(), now());
     let _ = hconn_c.process(out.dgram(), now());
     process_server_events(&mut hconn_s);
     let out = hconn_s.process(None, now());
 
     eprintln!("-----client");
     let _ = hconn_c.process(out.dgram(), now());
+    let out = hconn_s.process(None, now());
+    let _ = hconn_c.process(out.dgram(), now());
     process_client_events(&mut hconn_c);
 }
--- a/third_party/rust/neqo-qpack/.cargo-checksum.json
+++ b/third_party/rust/neqo-qpack/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"1b0641ab11933da85b807fc64e9b9c19d49a53602359e8b51722d80ac3774a63","src/decoder.rs":"bbbeae34f8d1d42d51fd344a4d558aec1ddaa3c3bb41b0428796c316c160a778","src/encoder.rs":"854864b93d63b127659c5ed85822fe9452eb5f40a362cb2a19dc8273a7c2e81e","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"b223e4a709a9cc144d36777d2bcf78d81780bdbc09e9f2f09c7bffa110a098da","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"f4f09692bf6ec863b0f066c88837d99f59a1fc4a8ca61bee4ed76d45a77c3cc4"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"96d0220db0a96108e39ca9d277a4979bd387e4d9d6ac92da7bbd590a86b2fa12","src/decoder.rs":"18f08a510d8a63012146eb0bb063218bf691a720624f521a29dc8cc3b1e52237","src/encoder.rs":"78da509611b5869d320795c42bef944b6499c0f207c73818c1908f1a1cf001fc","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"b223e4a709a9cc144d36777d2bcf78d81780bdbc09e9f2f09c7bffa110a098da","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"f4f09692bf6ec863b0f066c88837d99f59a1fc4a8ca61bee4ed76d45a77c3cc4"},"package":null}
\ No newline at end of file
--- a/third_party/rust/neqo-qpack/Cargo.toml
+++ b/third_party/rust/neqo-qpack/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "neqo-qpack"
-version = "0.1.4"
+version = "0.1.6"
 authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
 edition = "2018"
 license = "MIT/Apache-2.0"
 
 [dependencies]
 neqo-common = { path = "./../neqo-common" }
 neqo-transport = { path = "./../neqo-transport" }
 neqo-crypto = { path = "./../neqo-crypto" }
--- a/third_party/rust/neqo-qpack/src/decoder.rs
+++ b/third_party/rust/neqo-qpack/src/decoder.rs
@@ -128,17 +128,17 @@ impl QPackDecoder {
         self.blocked_streams.retain(|(_, req)| *req > base);
         Ok(r)
     }
 
     #[allow(clippy::cognitive_complexity)]
     #[allow(clippy::useless_let_if_seq)]
     fn read_instructions(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
         let label = self.to_string();
-        qdebug!([self] "reading instructions");
+        qdebug!([self], "reading instructions");
         loop {
             match self.state {
                 QPackDecoderState::ReadInstruction => {
                     let mut b = [0; 1];
                     match conn.stream_recv(stream_id, &mut b) {
                         Err(_) => break Err(Error::DecoderStreamError),
                         Ok((amount, fin)) => {
                             if fin {
@@ -204,17 +204,17 @@ impl QPackDecoder {
                     } else if (b[0] & 0x20) == 0 {
                         // Duplicate
                         let mut v: u64 = 0;
                         let mut cnt: u8 = 0;
                         let done = read_prefixed_encoded_int_with_connection_wrap(
                             conn, stream_id, &mut v, &mut cnt, 3, b[0], true,
                         )?;
                         if done {
-                            qdebug!([label] "received instruction - duplicate index={}", v);
+                            qdebug!([label], "received instruction - duplicate index={}", v);
                             self.table.duplicate(v)?;
                             self.total_num_of_inserts += 1;
                             self.increment += 1;
                             self.state = QPackDecoderState::ReadInstruction;
                         } else {
                             self.state = QPackDecoderState::Duplicate { index: v, cnt };
                             // wait for more data
                             break Ok(());
@@ -305,17 +305,17 @@ impl QPackDecoder {
                             if value.len() == *offset {
                                 // We are done reading instruction, insert the new entry.
                                 let mut value_to_insert: Vec<u8> = Vec::new();
                                 if *value_is_huffman {
                                     value_to_insert = Huffman::default().decode(value)?;
                                 } else {
                                     mem::swap(&mut value_to_insert, value);
                                 }
-                                qdebug!([label] "received instruction - insert with name ref index={} static={} value={:x?}", name_index, name_static_table, value_to_insert);
+                                qdebug!([label], "received instruction - insert with name ref index={} static={} value={:x?}", name_index, name_static_table, value_to_insert);
                                 self.table.insert_with_name_ref(
                                     *name_static_table,
                                     *name_index,
                                     value_to_insert,
                                 )?;
                                 self.total_num_of_inserts += 1;
                                 self.increment += 1;
                                 self.state = QPackDecoderState::ReadInstruction;
@@ -425,17 +425,17 @@ impl QPackDecoder {
                                     mem::swap(&mut name_to_insert, name);
                                 }
                                 let mut value_to_insert: Vec<u8> = Vec::new();
                                 if *value_is_huffman {
                                     value_to_insert = Huffman::default().decode(value)?;
                                 } else {
                                     mem::swap(&mut value_to_insert, value);
                                 }
-                                qdebug!([label] "received instruction - insert with name literal name={:x?} value={:x?}", name_to_insert, value_to_insert);
+                                qdebug!([label], "received instruction - insert with name literal name={:x?} value={:x?}", name_to_insert, value_to_insert);
                                 self.table.insert(name_to_insert, value_to_insert)?;
                                 self.total_num_of_inserts += 1;
                                 self.increment += 1;
                                 self.state = QPackDecoderState::ReadInstruction;
                             } else {
                                 // waiting for more data
                                 break Ok(());
                             }
@@ -445,17 +445,17 @@ impl QPackDecoder {
                 QPackDecoderState::Duplicate {
                     ref mut index,
                     ref mut cnt,
                 } => {
                     let done = read_prefixed_encoded_int_with_connection_wrap(
                         conn, stream_id, index, cnt, 0, 0x0, false,
                     )?;
                     if done {
-                        qdebug!([label] "received instruction - duplicate index={}", index);
+                        qdebug!([label], "received instruction - duplicate index={}", index);
                         self.table.duplicate(*index)?;
                         self.total_num_of_inserts += 1;
                         self.increment += 1;
                         self.state = QPackDecoderState::ReadInstruction;
                     } else {
                         // waiting for more data
                         break Ok(());
                     }
@@ -476,17 +476,17 @@ impl QPackDecoder {
                         break Ok(());
                     }
                 }
             }
         }
     }
 
     pub fn set_capacity(&mut self, cap: u64) -> Res<()> {
-        qdebug!([self] "received instruction capacity cap={}", cap);
+        qdebug!([self], "received instruction capacity cap={}", cap);
         if cap > u64::from(self.max_table_size) {
             return Err(Error::EncoderStreamError);
         }
         self.table.set_capacity(cap);
         Ok(())
     }
 
     fn header_ack(&mut self, stream_id: u64) {
@@ -507,41 +507,41 @@ impl QPackDecoder {
             self.increment = 0;
         }
         if self.send_buf.len() == 0 {
             Ok(())
         } else if let Some(stream_id) = self.local_stream_id {
             match conn.stream_send(stream_id, &self.send_buf[..]) {
                 Err(_) => Err(Error::DecoderStreamError),
                 Ok(r) => {
-                    qdebug!([self] "{} bytes sent.", r);
+                    qdebug!([self], "{} bytes sent.", r);
                     self.send_buf.read(r as usize);
                     Ok(())
                 }
             }
         } else {
             Ok(())
         }
     }
 
     // this function returns None if the stream is blocked waiting for table insertions.
     pub fn decode_header_block(&mut self, buf: &[u8], stream_id: u64) -> Res<Option<Vec<Header>>> {
-        qdebug!([self] "decode header block.");
+        qdebug!([self], "decode header block.");
         let mut reader = BufWrapper { buf, offset: 0 };
 
         let (req_inserts, base) = self.read_base(&mut reader)?;
         qdebug!(
-            [self]
+            [self],
             "requested inserts count is {} and base is {}",
             req_inserts,
             base
         );
         if self.table.base() < req_inserts {
             qdebug!(
-                [self]
+                [self],
                 "stream is blocked stream_id={} requested inserts count={}",
                 stream_id,
                 req_inserts
             );
             self.blocked_streams.push((stream_id, req_inserts));
             if self.blocked_streams.len() > self.max_blocked_streams as usize {
                 return Err(Error::DecompressionFailed);
             }
@@ -550,17 +550,17 @@ impl QPackDecoder {
         let mut h: Vec<Header> = Vec::new();
 
         loop {
             if reader.done() {
                 // Send header_ack
                 if req_inserts != 0 {
                     self.header_ack(stream_id);
                 }
-                qdebug!([self] "done decoding header block.");
+                qdebug!([self], "done decoding header block.");
                 break Ok(Some(h));
             }
 
             let b = reader.peek()?;
             if b & 0x80 != 0 {
                 h.push(self.read_indexed(&mut reader, base)?);
             } else if b & 0x40 != 0 {
                 h.push(self.read_literal_with_name_ref(&mut reader, base)?);
@@ -589,41 +589,41 @@ impl QPackDecoder {
             req_insert_cnt - base_delta - 1
         };
         Ok((req_insert_cnt, base))
     }
 
     fn read_indexed(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
         let static_table = buf.peek()? & 0x40 != 0;
         let index = read_prefixed_encoded_int_slice(buf, 2)?;
-        qdebug!([self] "decoder indexed {} static={}.", index, static_table);
+        qdebug!([self], "decoder indexed {} static={}.", index, static_table);
         if static_table {
             match self.table.get_static(index) {
                 Ok(entry) => Ok((to_string(entry.name())?, to_string(entry.value())?)),
                 Err(_) => Err(Error::DecompressionFailed),
             }
         } else if let Ok(entry) = self.table.get_dynamic(index, base, false) {
             Ok((to_string(entry.name())?, to_string(entry.value())?))
         } else {
             Err(Error::DecompressionFailed)
         }
     }
 
     fn read_post_base_index(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
         let index = read_prefixed_encoded_int_slice(buf, 4)?;
-        qdebug!([self] "decode post-based {}.", index);
+        qdebug!([self], "decode post-based {}.", index);
         if let Ok(entry) = self.table.get_dynamic(index, base, true) {
             Ok((to_string(entry.name())?, to_string(entry.value())?))
         } else {
             Err(Error::DecompressionFailed)
         }
     }
 
     fn read_literal_with_name_ref(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
-        qdebug!([self] "read literal with name reference.");
+        qdebug!([self], "read literal with name reference.");
         // ignore n bit.
         let static_table = buf.peek()? & 0x10 != 0;
         let index = read_prefixed_encoded_int_slice(buf, 4)?;
 
         let name: Vec<u8>;
         if static_table {
             if let Ok(entry) = self.table.get_static(index) {
                 name = entry.name().to_vec();
@@ -640,27 +640,27 @@ impl QPackDecoder {
         let value_len = read_prefixed_encoded_int_slice(buf, 1)? as usize;
 
         let value = if value_is_huffman {
             Huffman::default().decode(buf.slice(value_len)?)?
         } else {
             buf.slice(value_len)?.to_vec()
         };
         qdebug!(
-            [self]
+            [self],
             "name index={} static={} value={:x?}.",
             index,
             static_table,
             value
         );
         Ok((to_string(&name)?, to_string(&value)?))
     }
 
     fn read_literal_with_post_base_name_ref(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
-        qdebug!([self] "decoder literal with post-based index.");
+        qdebug!([self], "decoder literal with post-based index.");
         // ignore n bit.
         let index = read_prefixed_encoded_int_slice(buf, 5)?;
         let name: Vec<u8>;
         if let Ok(entry) = self.table.get_dynamic(index, base, true) {
             name = entry.name().to_vec();
         } else {
             return Err(Error::DecompressionFailed);
         }
@@ -669,22 +669,22 @@ impl QPackDecoder {
         let value_len = read_prefixed_encoded_int_slice(buf, 1)? as usize;
 
         let value = if value_is_huffman {
             Huffman::default().decode(buf.slice(value_len)?)?
         } else {
             buf.slice(value_len)?.to_vec()
         };
 
-        qdebug!([self] "name={:x?} value={:x?}.", name, value);
+        qdebug!([self], "name={:x?} value={:x?}.", name, value);
         Ok((to_string(&name)?, to_string(&value)?))
     }
 
     fn read_literal_with_name_literal(&self, buf: &mut BufWrapper) -> Res<Header> {
-        qdebug!([self] "decode literal with name literal.");
+        qdebug!([self], "decode literal with name literal.");
         // ignore n bit.
 
         let name_is_huffman = buf.peek()? & 0x08 != 0;
         let name_len = read_prefixed_encoded_int_slice(buf, 5)? as usize;
 
         let name = if name_is_huffman {
             Huffman::default().decode(buf.slice(name_len)?)?
         } else {
@@ -695,17 +695,17 @@ impl QPackDecoder {
         let value_len = read_prefixed_encoded_int_slice(buf, 1)? as usize;
 
         let value = if value_is_huffman {
             Huffman::default().decode(buf.slice(value_len)?)?
         } else {
             buf.slice(value_len)?.to_vec()
         };
 
-        qdebug!([self] "name={:x?} value={:x?}.", name, value);
+        qdebug!([self], "name={:x?} value={:x?}.", name, value);
         Ok((to_string(&name)?, to_string(&value)?))
     }
 
     fn calc_req_insert_cnt(&self, encoded: u64) -> Res<u64> {
         if encoded == 0 {
             Ok(0)
         } else if self.max_entries == 0 {
             Err(Error::DecompressionFailed)
--- a/third_party/rust/neqo-qpack/src/encoder.rs
+++ b/third_party/rust/neqo-qpack/src/encoder.rs
@@ -67,28 +67,28 @@ impl QPackEncoder {
         }
     }
 
     pub fn set_max_capacity(&mut self, cap: u64) -> Res<()> {
         if cap > (1 << 30) - 1 {
             // TODO dragana check wat is the correct error.
             return Err(Error::EncoderStreamError);
         }
-        qdebug!([self] "Set max capacity to {}.", cap);
+        qdebug!([self], "Set max capacity to {}.", cap);
         self.max_entries = (cap as f64 / 32.0).floor() as u64;
         // we also set our table to the max allowed. TODO we may not want to use max allowed.
         self.change_capacity(cap);
         Ok(())
     }
 
     pub fn set_max_blocked_streams(&mut self, blocked_streams: u64) -> Res<()> {
         if blocked_streams > (1 << 16) - 1 {
             return Err(Error::EncoderStreamError);
         }
-        qdebug!([self] "Set max blocked streams to {}.", blocked_streams);
+        qdebug!([self], "Set max blocked streams to {}.", blocked_streams);
         self.max_blocked_streams = blocked_streams as u16;
         Ok(())
     }
 
     pub fn recv_if_encoder_stream(&mut self, conn: &mut Connection, stream_id: u64) -> Res<bool> {
         match self.remote_stream_id {
             Some(id) => {
                 if id == stream_id {
@@ -98,17 +98,17 @@ impl QPackEncoder {
                     Ok(false)
                 }
             }
             None => Ok(false),
         }
     }
 
     fn read_instructions(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
-        qdebug!([self] "read a new instraction");
+        qdebug!([self], "read a new instraction");
         loop {
             match self.instruction_reader_current_inst {
                 None => {
                     // get new instruction
                     let mut b = [0];
                     match conn.stream_recv(stream_id, &mut b) {
                         Err(_) => break Err(Error::EncoderStreamError),
                         Ok((amount, fin)) => {
@@ -169,17 +169,17 @@ impl QPackEncoder {
                     }
                 }
             }
         }
     }
 
     fn call_instruction(&mut self) {
         if let Some(inst) = &self.instruction_reader_current_inst {
-            qdebug!([self] "call intruction {:?}", inst);
+            qdebug!([self], "call intruction {:?}", inst);
             match inst {
                 DecoderInstructions::InsertCountIncrement => {
                     self.table.increment_acked(self.instruction_reader_value);
                     let inserts = self.table.get_acked_inserts_cnt();
                     self.blocked_streams.retain(|req| *req <= inserts);
                 }
                 DecoderInstructions::HeaderAck => {
                     self.table.header_ack(self.instruction_reader_value)
@@ -198,17 +198,17 @@ impl QPackEncoder {
 
     pub fn insert_with_name_ref(
         &mut self,
         name_static_table: bool,
         name_index: u64,
         value: Vec<u8>,
     ) -> Res<()> {
         qdebug!(
-            [self]
+            [self],
             "insert with name reference {} from {} value={:x?}.",
             name_index,
             if name_static_table {
                 "static table"
             } else {
                 "dynamic table"
             },
             value
@@ -221,60 +221,60 @@ impl QPackEncoder {
         let instr = 0x80 | (if name_static_table { 0x40 } else { 0x00 });
         self.send_buf
             .encode_prefixed_encoded_int(instr, 2, name_index);
         encode_literal(self.use_huffman, &mut self.send_buf, 0x0, 0, entry.value());
         Ok(())
     }
 
     pub fn insert_with_name_literal(&mut self, name: Vec<u8>, value: Vec<u8>) -> Res<()> {
-        qdebug!([self] "insert name {:x?}, value={:x?}.", name, value);
+        qdebug!([self], "insert name {:x?}, value={:x?}.", name, value);
         // try to insert a new entry
         self.table.insert(name, value)?;
 
         let entry = self.table.get_last_added_entry().unwrap();
         // encode instruction.
         encode_literal(self.use_huffman, &mut self.send_buf, 0x40, 2, entry.name());
         encode_literal(self.use_huffman, &mut self.send_buf, 0x0, 0, entry.value());
 
         Ok(())
     }
 
     pub fn duplicate(&mut self, index: u64) -> Res<()> {
-        qdebug!([self] "duplicate entry {}.", index);
+        qdebug!([self], "duplicate entry {}.", index);
         self.table.duplicate(index)?;
         self.send_buf.encode_prefixed_encoded_int(0x00, 3, index);
         Ok(())
     }
 
     pub fn change_capacity(&mut self, cap: u64) {
-        qdebug!([self] "change capacity: {}", cap);
+        qdebug!([self], "change capacity: {}", cap);
         self.table.set_capacity(cap);
         self.send_buf.encode_prefixed_encoded_int(0x20, 3, cap);
     }
 
     pub fn send(&mut self, conn: &mut Connection) -> Res<()> {
         if self.send_buf.is_empty() {
             Ok(())
         } else if let Some(stream_id) = self.local_stream_id {
             match conn.stream_send(stream_id, &self.send_buf[..]) {
                 Err(_) => Err(Error::EncoderStreamError),
                 Ok(r) => {
-                    qdebug!([self] "{} bytes sent.", r);
+                    qdebug!([self], "{} bytes sent.", r);
                     self.send_buf.read(r as usize);
                     Ok(())
                 }
             }
         } else {
             Ok(())
         }
     }
 
     pub fn encode_header_block(&mut self, h: &[Header], stream_id: u64) -> QPData {
-        qdebug!([self] "encoding headers.");
+        qdebug!([self], "encoding headers.");
         let mut encoded_h = QPData::default();
         let base = self.table.base();
         let mut req_insert_cnt = 0;
         self.encode_header_block_prefix(&mut encoded_h, false, 0, base, true);
         for iter in h.iter() {
             let name = iter.0.clone().into_bytes();
             let value = iter.1.clone().into_bytes();
             qtrace!("encoding {:x?} {:x?}.", name, value);
@@ -285,27 +285,27 @@ impl QPackEncoder {
             let mut is_dynamic = false;
             let acked_inserts_cnt = self.table.get_acked_inserts_cnt(); // we need to read it here because of borrowing problem.
             let can_be_blocked = self.blocked_streams.len() < self.max_blocked_streams as usize;
             {
                 let label = self.to_string();
                 // this is done in this way because otherwise it is complaining about mut borrow. TODO: look if we can do this better
                 let (e_s, e_d, found_value) = self.table.lookup(&name, &value);
                 if let Some(entry) = e_s {
-                    qtrace!([label] "found a static entry, value-match={}", found_value);
+                    qtrace!([label], "found a static entry, value-match={}", found_value);
                     can_use = true;
                     index = entry.index();
                     value_as_well = found_value;
                 }
                 if !can_use {
                     if let Some(entry) = e_d {
                         index = entry.index();
                         can_use = index < acked_inserts_cnt || can_be_blocked;
                         qtrace!(
-                            [label]
+                            [label],
                             "found a dynamic entry - can_use={} value-match={},",
                             can_use,
                             found_value
                         );
                         if can_use {
                             value_as_well = found_value;
                             is_dynamic = true;
                             entry.add_ref(stream_id, 1);
@@ -380,17 +380,17 @@ impl QPackEncoder {
         &self,
         buf: &mut QPData,
         fix: bool,
         req_insert_cnt: u64,
         delta: u64,
         positive: bool,
     ) {
         qdebug!(
-            [self]
+            [self],
             "encode header block prefix req_insert_cnt={} delta={} (fix={}).",
             req_insert_cnt,
             delta,
             fix
         );
         let enc_insert_cnt = if req_insert_cnt != 0 {
             (req_insert_cnt % (2 * self.max_entries)) + 1
         } else {
@@ -430,59 +430,59 @@ impl QPackEncoder {
                     req_insert_cnt - base - 1,
                     false,
                 );
             }
         }
     }
 
     fn encode_indexed(&self, buf: &mut QPData, is_static: bool, index: u64) {
-        qdebug!([self] "encode index {} (static={}).", index, is_static);
+        qdebug!([self], "encode index {} (static={}).", index, is_static);
         let prefix = if is_static { 0xc0 } else { 0x80 };
         buf.encode_prefixed_encoded_int(prefix, 2, index);
     }
 
     fn encode_literal_with_name_ref(
         &self,
         buf: &mut QPData,
         is_static: bool,
         index: u64,
         value: &[u8],
     ) {
         qdebug!(
-            [self]
+            [self],
             "encode literal with name ref - index={}, static={}, value={:x?}",
             index,
             is_static,
             value
         );
         let prefix = if is_static { 0x50 } else { 0x40 };
         buf.encode_prefixed_encoded_int(prefix, 4, index);
         encode_literal(self.use_huffman, buf, 0x0, 0, value);
     }
 
     fn encode_post_base_index(&self, buf: &mut QPData, index: u64) {
-        qdebug!([self] "encode post base index {}.", index);
+        qdebug!([self], "encode post base index {}.", index);
         buf.encode_prefixed_encoded_int(0x10, 4, index);
     }
 
     fn encode_literal_with_post_based_name_ref(&self, buf: &mut QPData, index: u64, value: &[u8]) {
         qdebug!(
-            [self]
+            [self],
             "encode literal with post base index - index={}, value={:x?}.",
             index,
             value
         );
         buf.encode_prefixed_encoded_int(0x00, 5, index);
         encode_literal(self.use_huffman, buf, 0x0, 0, value);
     }
 
     fn encode_literal_with_name_literal(&self, buf: &mut QPData, name: &[u8], value: &[u8]) {
         qdebug!(
-            [self]
+            [self],
             "encode literal with name literal - name={:x?}, value={:x?}.",
             name,
             value
         );
         encode_literal(self.use_huffman, buf, 0x20, 4, name);
         encode_literal(self.use_huffman, buf, 0x0, 0, value);
     }
 
--- a/third_party/rust/neqo-transport/.cargo-checksum.json
+++ b/third_party/rust/neqo-transport/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"82faeea7483f4181d323f7e6889d336606c52dd52d9e7cb900b9e51e6f3e3a83","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/connection.rs":"ced6150694f2bfda6f7ff1799087a52dabe07155401919fe84cbb3cdbf5ef307","src/crypto.rs":"2eccba8925d74b199f524686c70de3c6715fab95af7654e0657e58cfd338b640","src/dump.rs":"d3c327d303c1257094687f750b3d468eedf945b06166484bee75dc4cab7ca001","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"9ced2d8f9a8747a960795c80aad384bde7a9a25ed4ac3ebf4ea0ebf1133d8e7a","src/frame.rs":"97fc6b83a71e51106d5f947ca9855892bae657d50c7f3aa55e18c67c1bf71359","src/lib.rs":"784bc483e981c92a9f2301ed67cee62654405c6bdb854dadb1f2464b8e3ac5a5","src/packet.rs":"7fa31e596082d577397853b2043b4e0ac534218a7fdc6cfc52eeba1224948970","src/recovery.rs":"5fea4291a54ef6693ed7d2022b6e0574f94224421015714e090e38132b1f7cff","src/recv_stream.rs":"f092be0c94655938461d69cdbb146200681341145f15c57817873c64bc25c538","src/send_stream.rs":"f778f0904d1a944c934198af9138dc872912c45662338ae8562093f648735b3e","src/server.rs":"a3b44025a9ee5f1071ca75f5ae8f8e7e5070ae7b9c053737d1e090e7855907c1","src/stats.rs":"dca5afcb6252f3f32f494513f76964cffb945afd6d18b8669dea98a7aeed1689","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"d35e2ec14958de74c315710bce80d8a72262f2437ddd1121fe28e752a1b4244d","src/tracking.rs":"9ce66170fa240db42a8c596f70846cc8e62925c30be6e622bc40b1a8f1ec73f2","tests/conn_vectors.rs":"5c381c8f1e0d126cb675bea302d1d118ea2ae988ec9c1536db2b18552074d845","tests/connection.rs":"195f52a876b9bd92f4368f301c98169a36438b5c9c1bb9ebaab146c7f8e0bb24","tests/server.rs":"8126ee12424487ee723d062169295e20858b041284a66c019173d39a7eaaa066"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"aa4e0d0fe520b00cca715828f066d6827c039f5127b1db9a3514318b53f36c51","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/connection.rs":"1994a978b6e6a970bb4d6870d0b932c92067f1288b81a871b6bdb7933c212211","src/crypto.rs":"dca8ce0a92f2ae12d87fcaa903cfd69048d6867eadd0eaf71670d000a23343de","src/dump.rs":"e4058d89acf50c3dea7e9f067e6fa1d8abfe0a65a77acf187f5012b53ed2568d","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"acd567f932be71ac4d342308369dd1620f6498fdb1c9a35a7325725702575c41","src/frame.rs":"17b85f48d20752dabaa2cd529ee65294ab0d37c4498134bb844958c9d901f2b0","src/lib.rs":"784bc483e981c92a9f2301ed67cee62654405c6bdb854dadb1f2464b8e3ac5a5","src/packet.rs":"7fa31e596082d577397853b2043b4e0ac534218a7fdc6cfc52eeba1224948970","src/recovery.rs":"f7bfbc605a03ba5c60a403fecbf843129d2868cb77e6378aa17c7c27c3dc6003","src/recv_stream.rs":"e3f8339aa8152587ec093ed426618a37a3b836fac56417fdf7822270bb5e87de","src/send_stream.rs":"69ee5867aa66a6d838dfc16e79b75d6fa9e0074d54229ccfc2e770f9f7deba57","src/server.rs":"d391a1d585bb1e45d025cdd1adb25f986128302178926b71e17dce8105346dda","src/stats.rs":"dca5afcb6252f3f32f494513f76964cffb945afd6d18b8669dea98a7aeed1689","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"d35e2ec14958de74c315710bce80d8a72262f2437ddd1121fe28e752a1b4244d","src/tracking.rs":"49d2ca42ade8c2f9d119a0b96c25106a657f5e15022a1a19ddababb097944aea","tests/conn_vectors.rs":"5c381c8f1e0d126cb675bea302d1d118ea2ae988ec9c1536db2b18552074d845","tests/connection.rs":"195f52a876b9bd92f4368f301c98169a36438b5c9c1bb9ebaab146c7f8e0bb24","tests/server.rs":"8126ee12424487ee723d062169295e20858b041284a66c019173d39a7eaaa066"},"package":null}
\ No newline at end of file
--- a/third_party/rust/neqo-transport/Cargo.toml
+++ b/third_party/rust/neqo-transport/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "neqo-transport"
-version = "0.1.4"
+version = "0.1.6"
 authors = ["EKR <ekr@rtfm.com>"]
 edition = "2018"
 license = "MIT/Apache-2.0"
 
 [dependencies]
 neqo-crypto = { path = "../neqo-crypto" }
 neqo-common = { path = "../neqo-common" }
 derive_more = "0.13"
--- a/third_party/rust/neqo-transport/src/connection.rs
+++ b/third_party/rust/neqo-transport/src/connection.rs
@@ -1,37 +1,35 @@
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 // The class implementing a QUIC connection.
 
-#![allow(dead_code)]
 use std::cell::RefCell;
 use std::cmp::{max, Ordering};
 use std::collections::HashMap;
 use std::convert::TryInto;
 use std::fmt::{self, Debug};
-use std::mem;
 use std::net::SocketAddr;
 use std::rc::Rc;
 use std::time::{Duration, Instant};
 
 use smallvec::SmallVec;
 
 use neqo_common::{hex, matches, qdebug, qerror, qinfo, qtrace, qwarn, Datagram, Decoder, Encoder};
 use neqo_crypto::agent::CertificateInfo;
 use neqo_crypto::{
-    Agent, AntiReplay, AuthenticationStatus, Client, Epoch, HandshakeState, Record, RecordList,
+    Agent, AntiReplay, AuthenticationStatus, Client, Epoch, HandshakeState, Record,
     SecretAgentInfo, Server,
 };
 
-use crate::crypto::Crypto;
+use crate::crypto::{Crypto, CryptoState};
 use crate::dump::*;
 use crate::events::{ConnectionEvent, ConnectionEvents};
 use crate::flow_mgr::FlowMgr;
 use crate::frame::{decode_frame, AckRange, Frame, FrameType, StreamType, TxMode};
 use crate::packet::{
     decode_packet_hdr, decrypt_packet, encode_packet, ConnectionId, ConnectionIdDecoder, PacketHdr,
     PacketNumberDecoder, PacketType,
 };
@@ -150,16 +148,24 @@ impl Path {
             local_cids: Vec::new(),
             remote_cid,
         }
     }
 
     pub fn received_on(&self, d: &Datagram) -> bool {
         self.local == d.destination() && self.remote == d.source()
     }
+
+    fn mtu(&self) -> usize {
+        if self.local.is_ipv4() {
+            1252
+        } else {
+            1232 // IPv6
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq)]
 /// Type returned from process() and `process_output()`. Users are required to
 /// call these repeatedly until `Callback` or `None` is returned.
 pub enum Output {
     /// Connection requires no action.
     None,
@@ -344,17 +350,17 @@ impl Connection {
             protocols,
             Some(Path {
                 local: local_addr,
                 remote: remote_addr,
                 local_cids,
                 remote_cid: dcid.clone(),
             }),
         );
-        c.crypto.states[0] = Some(c.crypto.create_initial_state(Role::Client, &dcid));
+        c.crypto.create_initial_state(Role::Client, &dcid);
         Ok(c)
     }
 
     /// Create a new QUIC connection with Server role.
     pub fn new_server(
         certs: &[impl AsRef<str>],
         protocols: &[impl AsRef<str>],
         anti_replay: &AntiReplay,
@@ -432,24 +438,16 @@ impl Connection {
         }
     }
 
     /// Set a local transport parameter, possibly overriding a default value.
     pub fn set_local_tparam(&self, key: u16, value: TransportParameter) {
         self.tps.borrow_mut().local.set(key, value)
     }
 
-    fn pmtu(&self) -> usize {
-        match &self.path {
-            Some(path) if path.local.is_ipv4() => 1252,
-            Some(_) => 1232, // IPv6
-            None => 1280,
-        }
-    }
-
     /// Set the connection ID that was originally chosen by the client.
     pub(crate) fn original_connection_id(&mut self, odcid: &ConnectionId) {
         assert_eq!(self.role, Role::Server);
         self.tps
             .borrow_mut()
             .local
             .set_bytes(tp_const::ORIGINAL_CONNECTION_ID, odcid.to_vec());
     }
@@ -490,31 +488,31 @@ impl Connection {
     }
 
     /// Enable resumption, using a token previously provided.
     /// This can only be called once and only on the client.
     /// After calling the function, it should be possible to attempt 0-RTT
     /// if the token supports that.
     pub fn set_resumption_token(&mut self, now: Instant, token: &[u8]) -> Res<()> {
         if self.state != State::Init {
-            qerror!([self] "set token in state {:?}", self.state);
+            qerror!([self], "set token in state {:?}", self.state);
             return Err(Error::ConnectionState);
         }
-        qinfo!([self] "resumption token {}", hex(token));
+        qinfo!([self], "resumption token {}", hex(token));
         let mut dec = Decoder::from(token);
         let tp_slice = match dec.decode_vvec() {
             Some(v) => v,
             _ => return Err(Error::InvalidResumptionToken),
         };
-        qtrace!([self] "  transport parameters {}", hex(&tp_slice));
+        qtrace!([self], "  transport parameters {}", hex(&tp_slice));
         let mut dec_tp = Decoder::from(tp_slice);
         let tp = TransportParameters::decode(&mut dec_tp)?;
 
         let tok = dec.decode_remainder();
-        qtrace!([self] "  TLS token {}", hex(&tok));
+        qtrace!([self], "  TLS token {}", hex(&tok));
         match self.crypto.tls {
             Agent::Client(ref mut c) => c.set_resumption_token(&tok)?,
             Agent::Server(_) => return Err(Error::WrongRole),
         }
 
         self.tps.borrow_mut().remote_0rtt = Some(tp);
         self.set_initial_limits();
         // Start up TLS, which has the effect of setting up all the necessary
@@ -528,18 +526,18 @@ impl Connection {
         match self.crypto.tls {
             Agent::Server(ref mut s) => {
                 let mut enc = Encoder::default();
                 enc.encode_vvec_with(|mut enc_inner| {
                     tps.borrow().local.encode(&mut enc_inner);
                 });
                 enc.encode(extra);
                 let records = s.send_ticket(now, &enc)?;
-                qinfo!([self] "send session ticket {}", hex(&enc));
-                self.buffer_crypto_records(records);
+                qinfo!([self], "send session ticket {}", hex(&enc));
+                self.crypto.buffer_records(records);
                 Ok(())
             }
             Agent::Client(_) => Err(Error::WrongRole),
         }
     }
 
     pub fn tls_info(&self) -> Option<&SecretAgentInfo> {
         self.crypto.tls.info()
@@ -576,17 +574,17 @@ impl Connection {
     // properly if that call fails.
     fn capture_error<T>(&mut self, now: Instant, frame_type: FrameType, res: Res<T>) -> Res<T> {
         if let Err(v) = &res {
             #[cfg(debug_assertions)]
             let msg = format!("{:?}", v);
             #[cfg(not(debug_assertions))]
             let msg = String::from("");
             if let State::Closed(err) | State::Closing { error: err, .. } = &self.state {
-                qwarn!([self] "Closing again after error {:?}", err);
+                qwarn!([self], "Closing again after error {:?}", err);
             } else {
                 self.set_state(State::Closing {
                     error: ConnectionError::Transport(v.clone()),
                     frame_type,
                     msg,
                     timeout: self.get_closing_period_time(now),
                 });
             }
@@ -621,17 +619,17 @@ impl Connection {
     pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
         let res = self.input(dgram, now);
         self.absorb_error(now, res);
         self.cleanup_streams();
     }
 
     /// Get the time that we next need to be called back, relative to `now`.
     fn next_delay(&mut self, now: Instant) -> Duration {
-        self.loss_recovery_state = self.loss_recovery.get_timer(&self.state);
+        self.loss_recovery_state = self.loss_recovery.get_timer();
 
         let mut delays = SmallVec::<[_; 4]>::new();
 
         if let Some(lr_time) = self.loss_recovery_state.callback_time() {
             delays.push(lr_time);
         }
 
         if let Some(ack_time) = self.acks.ack_time() {
@@ -700,77 +698,85 @@ impl Connection {
     }
 
     fn is_valid_initial(&self, hdr: &PacketHdr) -> bool {
         if let PacketType::Initial(token) = &hdr.tipe {
             // Server checks the token, so if we have one,
             // assume that the DCID is OK.
             if hdr.dcid.len() < 8 {
                 if token.is_empty() {
-                    qinfo!([self] "Drop Initial with short DCID");
+                    qinfo!([self], "Drop Initial with short DCID");
                     false
                 } else {
-                    qinfo!([self] "Initial received with token, assuming OK");
+                    qinfo!([self], "Initial received with token, assuming OK");
                     true
                 }
             } else {
                 // This is the normal path. Don't log.
                 true
             }
         } else {
-            qdebug!([self] "Dropping non-Initial packet");
+            qdebug!([self], "Dropping non-Initial packet");
             false
         }
     }
 
     fn handle_retry(&mut self, scid: &ConnectionId, odcid: &ConnectionId, token: &[u8]) -> Res<()> {
-        qdebug!([self] "received Retry");
+        qdebug!([self], "received Retry");
         if self.retry_info.is_some() {
-            qinfo!([self] "Dropping extra Retry");
+            qinfo!([self], "Dropping extra Retry");
             return Ok(());
         }
         if token.is_empty() {
-            qinfo!([self] "Dropping Retry without a token");
+            qinfo!([self], "Dropping Retry without a token");
             return Ok(());
         }
         match self.path.iter_mut().find(|p| p.remote_cid == *odcid) {
             None => {
-                qinfo!([self] "Ignoring Retry with mismatched ODCID");
+                qinfo!([self], "Ignoring Retry with mismatched ODCID");
                 return Ok(());
             }
             Some(path) => {
                 path.remote_cid = scid.clone();
             }
         }
-        qinfo!([self] "Valid Retry received, restarting with provided token");
+        qinfo!(
+            [self],
+            "Valid Retry received, restarting with provided token"
+        );
         self.retry_info = Some(RetryInfo {
             token: token.to_vec(),
             odcid: odcid.clone(),
         });
         let lost_packets = self.loss_recovery.retry();
         self.handle_lost_packets(lost_packets);
 
         // Switching crypto state here might not happen eventually.
         // https://github.com/quicwg/base-drafts/issues/2823
-        self.crypto.states[0] = Some(self.crypto.create_initial_state(self.role, scid));
+        self.crypto.create_initial_state(self.role, scid);
         Ok(())
     }
 
     fn input(&mut self, d: Datagram, now: Instant) -> Res<()> {
         let mut slc = &d[..];
 
-        qinfo!([self] "input {}", hex( &**d));
+        qinfo!([self], "input {}", hex(&**d));
 
         // Handle each packet in the datagram
         while !slc.is_empty() {
             let res = decode_packet_hdr(self.cid_manager.borrow().as_decoder(), slc);
             let mut hdr = match res {
                 Ok(h) => h,
                 Err(e) => {
-                    qinfo!([self] "Received indecipherable packet header {} {}", hex(slc), e);
+                    qinfo!(
+                        [self],
+                        "Received indecipherable packet header {} {}",
+                        hex(slc),
+                        e
+                    );
                     return Ok(()); // Drop the remainder of the datagram.
                 }
             };
             self.stats.packets_rx += 1;
             match (&hdr.tipe, &self.state, &self.role) {
                 (PacketType::VN(_), State::WaitInitial, Role::Client) => {
                     self.set_state(State::Closed(ConnectionError::Transport(
                         Error::VersionNegotiation,
@@ -795,100 +801,106 @@ impl Connection {
                         self.version,
                     );
                     return Ok(());
                 }
             }
 
             match self.state {
                 State::Init => {
-                    qinfo!([self] "Received message while in Init state");
+                    qinfo!([self], "Received message while in Init state");
                     return Ok(());
                 }
                 State::WaitInitial => {
-                    qinfo!([self] "Received packet in WaitInitial");
+                    qinfo!([self], "Received packet in WaitInitial");
                     if self.role == Role::Server {
                         if !self.is_valid_initial(&hdr) {
                             return Ok(());
                         }
-                        self.crypto.states[0] =
-                            Some(self.crypto.create_initial_state(self.role, &hdr.dcid));
+                        self.crypto.create_initial_state(self.role, &hdr.dcid);
                     }
                 }
                 State::Handshaking | State::Connected => {
                     if !self.is_valid_cid(&hdr.dcid) {
-                        qinfo!([self] "Ignoring packet with CID {:?}", hdr.dcid);
+                        qinfo!([self], "Ignoring packet with CID {:?}", hdr.dcid);
                         return Ok(());
                     }
                 }
                 State::Closing { .. } => {
                     // Don't bother processing the packet. Instead ask to get a
                     // new close frame.
                     self.flow_mgr.borrow_mut().set_need_close_frame(true);
                     return Ok(());
                 }
                 State::Closed(..) => {
                     // Do nothing.
                     return Ok(());
                 }
             }
 
-            qdebug!([self] "Received unverified packet {:?}", hdr);
+            qdebug!([self], "Received unverified packet {:?}", hdr);
 
             let body = self.decrypt_body(&mut hdr, slc);
             slc = &slc[hdr.hdr_len + hdr.body_len()..];
             if let Some(body) = body {
                 // TODO(ekr@rtfm.com): Have the server blow away the initial
                 // crypto state if this fails? Otherwise, we will get a panic
                 // on the assert for doesn't exist.
                 // OK, we have a valid packet.
                 self.idle_timeout.on_packet_received(now);
-                dump_packet(self, "<- RX", &hdr, &body);
+                dump_packet(self, "-> RX", &hdr, &body);
                 if self.process_packet(&hdr, body, now)? {
                     continue;
                 }
                 self.start_handshake(hdr, &d)?;
                 self.process_migrations(&d)?;
             }
         }
         Ok(())
     }
 
     fn decrypt_body(&mut self, mut hdr: &mut PacketHdr, slc: &[u8]) -> Option<Vec<u8>> {
         // Decryption failure, or not having keys is not fatal.
         // If the state isn't available, or we can't decrypt the packet, drop
         // the rest of the datagram on the floor, but don't generate an error.
         let largest_acknowledged = self
             .loss_recovery
-            .largest_acknowledged(PNSpace::from(hdr.epoch));
+            .largest_acknowledged_pn(PNSpace::from(hdr.epoch));
+        if (self.state == State::Handshaking) && (hdr.epoch == 3) {
+            // Server has keys for epoch 3 but it is still in state Handshaking -> discharge packet.
+            debug_assert_eq!(self.role(), Role::Server);
+            return None;
+        }
         match self.crypto.obtain_crypto_state(self.role, hdr.epoch) {
-            Ok(cs) => match cs.rx.as_ref() {
-                Some(rx) => {
-                    let pn_decoder = PacketNumberDecoder::new(largest_acknowledged);
-                    decrypt_packet(rx, pn_decoder, &mut hdr, slc).ok()
-                }
-                _ => None,
-            },
+            Ok(CryptoState { rx: Some(rx), .. }) => {
+                let pn_decoder = PacketNumberDecoder::new(largest_acknowledged);
+                decrypt_packet(rx, pn_decoder, &mut hdr, slc).ok()
+            }
             _ => None,
         }
     }
 
     /// Ok(true) if the packet is a duplicate
     fn process_packet(&mut self, hdr: &PacketHdr, body: Vec<u8>, now: Instant) -> Res<bool> {
         // TODO(ekr@rtfm.com): Have the server blow away the initial
         // crypto state if this fails? Otherwise, we will get a panic
         // on the assert for doesn't exist.
         // OK, we have a valid packet.
 
         // TODO(ekr@rtfm.com): Filter for valid for this epoch.
 
         let ack_eliciting = self.input_packet(hdr.epoch, Decoder::from(&body[..]), now)?;
         let space = PNSpace::from(hdr.epoch);
         if self.acks[space].is_duplicate(hdr.pn) {
-            qdebug!([self] "Received duplicate packet epoch={} pn={}", hdr.epoch, hdr.pn);
+            qdebug!(
+                [self],
+                "Received duplicate packet epoch={} pn={}",
+                hdr.epoch,
+                hdr.pn
+            );
             self.stats.dups_rx += 1;
             Ok(true)
         } else {
             self.acks[space].set_received(now, hdr.pn, ack_eliciting);
             Ok(false)
         }
     }
 
@@ -911,17 +923,21 @@ impl Connection {
             // SecretAgentPreinfo::early_data() always returns false for a server,
             // but a non-zero maximum tells us if we are accepting 0-RTT.
             self.zero_rtt_state = if self.crypto.tls.preinfo()?.max_early_data() > 0 {
                 ZeroRttState::Accepted
             } else {
                 ZeroRttState::Rejected
             };
         } else {
-            qdebug!([self] "Changing to use Server CID={}", hdr.scid.as_ref().unwrap());
+            qdebug!(
+                [self],
+                "Changing to use Server CID={}",
+                hdr.scid.as_ref().unwrap()
+            );
             let p = self
                 .path
                 .iter_mut()
                 .find(|p| p.received_on(&d))
                 .expect("should have a path for sending Initial");
             p.remote_cid = hdr.scid.unwrap();
         }
         self.set_state(State::Handshaking);
@@ -934,91 +950,88 @@ impl Connection {
         } else {
             // Right now, we don't support any form of migration.
             // So generate an error if a packet is received on a new path.
             Err(Error::InvalidMigration)
         }
     }
 
     // Return whether the packet had ack-eliciting frames.
-    fn input_packet(&mut self, epoch: Epoch, mut d: Decoder, now: Instant) -> Res<(bool)> {
+    fn input_packet(&mut self, epoch: Epoch, mut d: Decoder, now: Instant) -> Res<bool> {
         let mut ack_eliciting = false;
 
         // Handle each frame in the packet
         while d.remaining() > 0 {
             let f = decode_frame(&mut d)?;
             ack_eliciting |= f.ack_eliciting();
             let t = f.get_type();
             let res = self.input_frame(epoch, f, now);
             self.capture_error(now, t, res)?;
         }
 
         Ok(ack_eliciting)
     }
 
     fn output(&mut self, now: Instant) -> Option<Datagram> {
         let mut out = None;
-        // Can't call a method on self while iterating over self.paths
-        let paths = mem::replace(&mut self.path, Default::default());
-        for p in &paths {
-            match self.output_path(&p, now) {
-                Ok(Some(dgram)) => {
-                    out = Some(dgram);
-                    break;
+        if self.path.is_some() {
+            match self.output_pkt_for_path(now) {
+                Ok(res) => {
+                    out = res;
                 }
                 Err(e) => {
                     if !matches!(self.state, State::Closing{..}) {
                         // An error here causes us to transition to closing.
                         self.absorb_error(now, Err(e));
                         // Rerun to give a chance to send a CONNECTION_CLOSE.
-                        out = match self.output_path(&p, now) {
+                        out = match self.output_pkt_for_path(now) {
                             Ok(x) => x,
                             Err(e) => {
-                                qwarn!([self] "two output_path errors in a row: {:?}", e);
+                                qwarn!([self], "two output_path errors in a row: {:?}", e);
                                 None
                             }
                         };
-                        break;
                     }
                 }
-                _ => (),
             };
         }
-        self.path = paths;
         out
     }
 
+    #[allow(clippy::cognitive_complexity)]
     /// Build a datagram, possibly from multiple packets (for different PN
     /// spaces) and each containing 1+ frames.
-    fn output_path(&mut self, path: &Path, now: Instant) -> Res<Option<Datagram>> {
+    fn output_pkt_for_path(&mut self, now: Instant) -> Res<Option<Datagram>> {
         let mut out_bytes = Vec::new();
         let mut needs_padding = false;
+        let path = self
+            .path
+            .take()
+            .expect("we know we have a path because calling fn checked");
 
         // Frames for different epochs must go in different packets, but then these
         // packets can go in a single datagram
         for epoch in 0..NUM_EPOCHS {
             let space = PNSpace::from(epoch);
             let mut encoder = Encoder::default();
             let mut tokens = Vec::new();
 
-            // Try to make our own crypo state and if we can't, skip this epoch.
-            match self.crypto.obtain_crypto_state(self.role, epoch) {
-                Ok(cs) => {
-                    if cs.tx.is_none() {
-                        continue;
-                    }
-                }
-                _ => continue,
+            // Ensure we have tx crypto state for this epoch, or skip it.
+            if !matches!(
+                self.crypto.obtain_crypto_state(self.role, epoch),
+                Ok(CryptoState { tx: Some(_), .. })
+            ) {
+                continue;
             }
 
             let mut ack_eliciting = false;
             match &self.state {
                 State::Init | State::WaitInitial | State::Handshaking | State::Connected => {
                     loop {
-                        let remaining = self.pmtu() - out_bytes.len() - encoder.len();
+                        let remaining = path.mtu() - out_bytes.len() - encoder.len();
 
                         // Check sources in turn for available frames
                         if let Some((frame, token)) = self
                             .acks
                             .get_frame(now, epoch)
                             .or_else(|| self.crypto.get_frame(epoch, TxMode::Normal, remaining))
                             .or_else(|| self.flow_mgr.borrow_mut().get_frame(epoch, remaining))
                             .or_else(|| {
@@ -1026,18 +1039,17 @@ impl Connection {
                                     .get_frame(epoch, TxMode::Normal, remaining)
                             })
                         {
                             ack_eliciting |= frame.ack_eliciting();
                             frame.marshal(&mut encoder);
                             if let Some(t) = token {
                                 tokens.push(t);
                             }
-                            assert!(encoder.len() <= self.pmtu());
-                            if out_bytes.len() + encoder.len() == self.pmtu() {
+                            if out_bytes.len() + encoder.len() == path.mtu() {
                                 // No more space for frames.
                                 break;
                             }
                         } else {
                             // No more frames to send.
                             break;
                         }
                     }
@@ -1064,17 +1076,17 @@ impl Connection {
                 }
                 State::Closed { .. } => unimplemented!(),
             }
 
             if encoder.len() == 0 {
                 continue;
             }
 
-            qdebug!([self] "Need to send a packet");
+            qdebug!([self], "Need to send a packet");
             match epoch {
                 // Packets containing Initial packets need padding.
                 0 => needs_padding = true,
                 1 => (),
                 // ...unless they include higher epochs.
                 _ => needs_padding = false,
             }
             let hdr = PacketHdr::new(
@@ -1113,39 +1125,42 @@ impl Connection {
             let cs = self
                 .crypto
                 .obtain_crypto_state(self.role, hdr.epoch)
                 .unwrap();
             let tx = cs.tx.as_ref().unwrap();
             let mut packet = encode_packet(tx, &hdr, &encoder);
             dump_packet(self, "TX ->", &hdr, &encoder);
             out_bytes.append(&mut packet);
-            if out_bytes.len() >= self.pmtu() {
+            if out_bytes.len() >= path.mtu() {
                 break;
             }
         }
 
         if out_bytes.is_empty() {
+            self.path = Some(path);
             return Ok(None);
         }
 
         // Pad Initial packets sent by the client to 1200 bytes.
         if self.role == Role::Client && needs_padding {
-            qdebug!([self] "pad Initial to 1200");
+            qdebug!([self], "pad Initial to 1200");
             out_bytes.resize(1200, 0);
         }
-        Ok(Some(Datagram::new(path.local, path.remote, out_bytes)))
+        let dgram = Some(Datagram::new(path.local, path.remote, out_bytes));
+        self.path = Some(path);
+        Ok(dgram)
     }
 
     fn client_start(&mut self, now: Instant) -> Res<()> {
-        qinfo!([self] "client_start");
+        qinfo!([self], "client_start");
         self.handshake(now, 0, None)?;
         self.set_state(State::WaitInitial);
         if self.crypto.tls.preinfo()?.early_data() {
-            qdebug!([self] "Enabling 0-RTT");
+            qdebug!([self], "Enabling 0-RTT");
             self.zero_rtt_state = ZeroRttState::Enabled;
         }
         Ok(())
     }
 
     fn get_closing_period_time(&self, now: Instant) -> Instant {
         // Spec says close time should be at least PTO times 3.
         now + (self.loss_recovery.pto() * 3)
@@ -1156,25 +1171,16 @@ impl Connection {
         self.set_state(State::Closing {
             error: ConnectionError::Application(error),
             frame_type: 0,
             msg: msg.into(),
             timeout: self.get_closing_period_time(now),
         });
     }
 
-    /// Buffer crypto records for sending.
-    fn buffer_crypto_records(&mut self, records: RecordList) {
-        for r in records {
-            assert_eq!(r.ct, 22);
-            qdebug!([self] "Adding CRYPTO data {:?}", r);
-            self.crypto.streams[r.epoch as usize].tx.send(&r.data);
-        }
-    }
-
     fn set_initial_limits(&mut self) {
         let tps = self.tps.borrow();
         let remote = tps.remote();
         self.indexes.remote_max_stream_bidi =
             StreamIndex::new(remote.get_integer(tp_const::INITIAL_MAX_STREAMS_BIDI));
         self.indexes.remote_max_stream_uni =
             StreamIndex::new(remote.get_integer(tp_const::INITIAL_MAX_STREAMS_UNI));
         self.flow_mgr
@@ -1197,47 +1203,46 @@ impl Connection {
             }
         } else {
             Ok(())
         }
     }
 
     fn handshake(&mut self, now: Instant, epoch: u16, data: Option<&[u8]>) -> Res<()> {
         qdebug!("Handshake epoch={} data={:0x?}", epoch, data);
-        let mut rec: Option<Record> = None;
 
-        if let Some(d) = data {
-            qdebug!([self] "Handshake received {:0x?} ", d);
-            rec = Some(Record {
-                ct: 22, // TODO(ekr@rtfm.com): Symbolic constants for CT. This is handshake.
-                epoch,
-                data: d.to_vec(),
-            });
-        }
+        let rec = data
+            .map(|d| {
+                qdebug!([self], "Handshake received {:0x?} ", d);
+                Some(Record {
+                    ct: 22, // TODO(ekr@rtfm.com): Symbolic constants for CT. This is handshake.
+                    epoch,
+                    data: d.to_vec(),
+                })
+            })
+            .unwrap_or(None);
 
-        let m = self.crypto.tls.handshake_raw(now, rec);
-        if *self.crypto.tls.state() == HandshakeState::AuthenticationPending {
-            self.events.authentication_needed();
-        }
-
-        match m {
+        match self.crypto.tls.handshake_raw(now, rec) {
             Err(e) => {
-                qwarn!([self] "Handshake failed");
+                qwarn!([self], "Handshake failed");
                 return Err(match self.crypto.tls.alert() {
                     Some(a) => Error::CryptoAlert(*a),
                     _ => Error::CryptoError(e),
                 });
             }
-            Ok(msgs) => self.buffer_crypto_records(msgs),
+            Ok(msgs) => self.crypto.buffer_records(msgs),
         }
-        if self.crypto.tls.state().connected() {
-            qinfo!([self] "TLS handshake completed");
+
+        if *self.crypto.tls.state() == HandshakeState::AuthenticationPending {
+            self.events.authentication_needed();
+        } else if matches!(self.crypto.tls.state(), HandshakeState::Complete(_)) {
+            qinfo!([self], "TLS handshake completed");
 
             if self.crypto.tls.info().map(SecretAgentInfo::alpn).is_none() {
-                qwarn!([self] "No ALPN. Closing connection.");
+                qwarn!([self], "No ALPN. Closing connection.");
                 // 120 = no_application_protocol
                 return Err(Error::CryptoAlert(120));
             }
 
             self.validate_odcid()?;
             self.set_state(State::Connected);
             self.set_initial_limits();
         }
@@ -1258,16 +1263,19 @@ impl Connection {
                     // uses up all the conn credit. Not our fault.
                     self.events.send_stream_writable(*id)
                 }
             }
         }
     }
 
     fn input_frame(&mut self, epoch: Epoch, frame: Frame, now: Instant) -> Res<()> {
+        if !frame.is_allowed(epoch) {
+            return Err(Error::ProtocolViolation);
+        }
         match frame {
             Frame::Padding => {
                 // Ignore
             }
             Frame::Ping => {
                 // Ack elicited with no further handling needed
             }
             Frame::Ack {
@@ -1302,17 +1310,17 @@ impl Connection {
                 self.events
                     .send_stream_stop_sending(stream_id.into(), application_error_code);
                 if let (Some(ss), _) = self.obtain_stream(stream_id.into())? {
                     ss.reset(application_error_code);
                 }
             }
             Frame::Crypto { offset, data } => {
                 qdebug!(
-                    [self]
+                    [self],
                     "Crypto frame on epoch={} offset={}, data={:0x?}",
                     epoch,
                     offset,
                     &data
                 );
                 let rx = &mut self.crypto.streams[epoch as usize].rx;
                 rx.inbound_frame(offset, data)?;
                 if rx.data_ready() {
@@ -1323,16 +1331,17 @@ impl Connection {
                 }
             }
             Frame::NewToken { token } => self.token = Some(token),
             Frame::Stream {
                 fin,
                 stream_id,
                 offset,
                 data,
+                ..
             } => {
                 if let (_, Some(rs)) = self.obtain_stream(stream_id.into())? {
                     rs.inbound_stream_frame(fin, offset, data)?;
                 }
             }
             Frame::MaxData { maximum_data } => self.handle_max_data(maximum_data),
             Frame::MaxStreamData {
                 stream_id,
@@ -1353,17 +1362,21 @@ impl Connection {
 
                 if maximum_streams > *remote_max {
                     *remote_max = maximum_streams;
                     self.events.send_stream_creatable(stream_type);
                 }
             }
             Frame::DataBlocked { data_limit } => {
                 // Should never happen since we set data limit to 2^62-1
-                qwarn!([self] "Received DataBlocked with data limit {}", data_limit);
+                qwarn!(
+                    [self],
+                    "Received DataBlocked with data limit {}",
+                    data_limit
+                );
             }
             Frame::StreamDataBlocked { stream_id, .. } => {
                 // TODO(agrover@mozilla.com): how should we be using
                 // currently-unused stream_data_limit?
 
                 let stream_id: StreamId = stream_id.into();
 
                 // Terminate connection with STREAM_STATE_ERROR if send-only
@@ -1397,29 +1410,31 @@ impl Connection {
             }
             Frame::RetireConnectionId { sequence_number } => {
                 self.connection_ids.remove(&sequence_number);
             }
             Frame::PathChallenge { data } => self.flow_mgr.borrow_mut().path_response(data),
             Frame::PathResponse { .. } => {
                 // Should never see this, we don't support migration atm and
                 // do not send path challenges
-                qwarn!([self] "Received Path Response");
+                qwarn!([self], "Received Path Response");
             }
             Frame::ConnectionClose {
                 error_code,
                 frame_type,
                 reason_phrase,
             } => {
                 let reason_phrase = String::from_utf8_lossy(&reason_phrase);
-                qinfo!([self]
-                       "ConnectionClose received. Error code: {:?} frame type {:x} reason {}",
-                       error_code,
-                       frame_type,
-                       reason_phrase);
+                qinfo!(
+                    [self],
+                    "ConnectionClose received. Error code: {:?} frame type {:x} reason {}",
+                    error_code,
+                    frame_type,
+                    reason_phrase
+                );
                 self.set_state(State::Closed(error_code.into()));
             }
         };
 
         Ok(())
     }
 
     fn handle_lost_packets<I>(&mut self, lost_packets: I)
@@ -1429,17 +1444,17 @@ impl Connection {
         for lost in lost_packets {
             for token in lost.tokens {
                 qtrace!([self], "Lost: {:?}", token);
                 match token {
                     RecoveryToken::Ack(_) => {}
                     RecoveryToken::Stream(st) => self.send_streams.lost(&st),
                     RecoveryToken::Crypto(ct) => self.crypto.lost(ct),
                     RecoveryToken::Flow(ft) => self.flow_mgr.borrow_mut().lost(
-                        ft,
+                        &ft,
                         &mut self.send_streams,
                         &mut self.recv_streams,
                         &mut self.indexes,
                     ),
                 }
             }
         }
     }
@@ -1449,17 +1464,17 @@ impl Connection {
         epoch: Epoch,
         largest_acknowledged: u64,
         ack_delay: u64,
         first_ack_range: u64,
         ack_ranges: Vec<AckRange>,
         now: Instant,
     ) -> Res<()> {
         qinfo!(
-            [self]
+            [self],
             "Rx ACK epoch={}, largest_acked={}, first_ack_range={}, ranges={:?}",
             epoch,
             largest_acknowledged,
             first_ack_range,
             ack_ranges
         );
 
         let acked_ranges =
@@ -1498,32 +1513,32 @@ impl Connection {
         // have a congestion controller.
         for dropped in self.loss_recovery.drop_0rtt() {
             for token in dropped.tokens {
                 match token {
                     RecoveryToken::Ack(_) => {}
                     RecoveryToken::Stream(st) => self.send_streams.lost(&st),
                     RecoveryToken::Crypto(ct) => self.crypto.lost(ct),
                     RecoveryToken::Flow(ft) => self.flow_mgr.borrow_mut().lost(
-                        ft,
+                        &ft,
                         &mut self.send_streams,
                         &mut self.recv_streams,
                         &mut self.indexes,
                     ),
                 }
             }
         }
         self.send_streams.clear();
         self.recv_streams.clear();
         self.events.client_0rtt_rejected();
     }
 
     fn set_state(&mut self, state: State) {
         if state > self.state {
-            qinfo!([self] "State change from {:?} -> {:?}", self.state, state);
+            qinfo!([self], "State change from {:?} -> {:?}", self.state, state);
             self.state = state.clone();
             match &self.state {
                 State::Connected => {
                     if self.role == Role::Server {
                         // Remove the randomized client CID from the list of acceptable CIDs.
                         assert_eq!(1, self.valid_cids.len());
                         self.valid_cids.clear();
                     } else {
@@ -1610,30 +1625,36 @@ impl Connection {
             } else {
                 &mut self.indexes.local_next_stream_uni
             };
             let stream_idx: StreamIndex = stream_id.into();
 
             if stream_idx >= *next_stream_idx {
                 let recv_initial_max_stream_data = if stream_id.is_bidi() {
                     if stream_idx > self.indexes.local_max_stream_bidi {
-                        qwarn!([self] "remote bidi stream create blocked, next={:?} max={:?}",
-                               stream_idx,
-                               self.indexes.local_max_stream_bidi);
+                        qwarn!(
+                            [self],
+                            "remote bidi stream create blocked, next={:?} max={:?}",
+                            stream_idx,
+                            self.indexes.local_max_stream_bidi
+                        );
                         return Err(Error::StreamLimitError);
                     }
                     self.tps
                         .borrow()
                         .local
                         .get_integer(tp_const::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE)
                 } else {
                     if stream_idx > self.indexes.local_max_stream_uni {
-                        qwarn!([self] "remote uni stream create blocked, next={:?} max={:?}",
-                               stream_idx,
-                               self.indexes.local_max_stream_uni);
+                        qwarn!(
+                            [self],
+                            "remote uni stream create blocked, next={:?} max={:?}",
+                            stream_idx,
+                            self.indexes.local_max_stream_uni
+                        );
                         return Err(Error::StreamLimitError);
                     }
                     self.tps
                         .borrow()
                         .local
                         .get_integer(tp_const::INITIAL_MAX_STREAM_DATA_UNI)
                 };
 
@@ -1705,19 +1726,22 @@ impl Connection {
         }
 
         Ok(match st {
             StreamType::UniDi => {
                 if self.indexes.remote_next_stream_uni >= self.indexes.remote_max_stream_uni {
                     self.flow_mgr
                         .borrow_mut()
                         .streams_blocked(self.indexes.remote_max_stream_uni, StreamType::UniDi);
-                    qwarn!([self] "local uni stream create blocked, next={:?} max={:?}",
-                           self.indexes.remote_next_stream_uni,
-                           self.indexes.remote_max_stream_uni);
+                    qwarn!(
+                        [self],
+                        "local uni stream create blocked, next={:?} max={:?}",
+                        self.indexes.remote_next_stream_uni,
+                        self.indexes.remote_max_stream_uni
+                    );
                     return Err(Error::StreamLimitError);
                 }
                 let new_id = self
                     .indexes
                     .remote_next_stream_uni
                     .to_stream_id(StreamType::UniDi, self.role);
                 self.indexes.remote_next_stream_uni += 1;
                 let initial_max_stream_data = self
@@ -1737,19 +1761,22 @@ impl Connection {
                 );
                 new_id.as_u64()
             }
             StreamType::BiDi => {
                 if self.indexes.remote_next_stream_bidi >= self.indexes.remote_max_stream_bidi {
                     self.flow_mgr
                         .borrow_mut()
                         .streams_blocked(self.indexes.remote_max_stream_bidi, StreamType::BiDi);
-                    qwarn!([self] "local bidi stream create blocked, next={:?} max={:?}",
-                           self.indexes.remote_next_stream_bidi,
-                           self.indexes.remote_max_stream_bidi);
+                    qwarn!(
+                        [self],
+                        "local bidi stream create blocked, next={:?} max={:?}",
+                        self.indexes.remote_next_stream_bidi,
+                        self.indexes.remote_max_stream_bidi
+                    );
                     return Err(Error::StreamLimitError);
                 }
                 let new_id = self
                     .indexes
                     .remote_next_stream_bidi
                     .to_stream_id(StreamType::BiDi, self.role);
                 self.indexes.remote_next_stream_bidi += 1;
                 let send_initial_max_stream_data = self
@@ -1851,17 +1878,17 @@ impl Connection {
     /// Get events that indicate state changes on the connection. This method
     /// correctly handles cases where handling one event can obsolete
     /// previously-queued events, or cause new events to be generated.
     pub fn next_event(&mut self) -> Option<ConnectionEvent> {
         self.events.next_event()
     }
 
     fn check_loss_detection_timeout(&mut self, now: Instant) {
-        qdebug!([self] "check_loss_timeouts");
+        qdebug!([self], "check_loss_timeouts");
 
         if matches!(self.loss_recovery_state.mode(), LossRecoveryMode::None) {
             // LR not the active timer
             return;
         }
 
         if self.loss_recovery_state.callback_time() > Some(now) {
             // LR timer, but hasn't expired.
@@ -1882,28 +1909,28 @@ impl Connection {
                 qinfo!("lost packets: {}", packets.len());
                 for lost in packets {
                     for token in lost.tokens {
                         match token {
                             RecoveryToken::Ack(_) => {} // Do nothing
                             RecoveryToken::Stream(st) => self.send_streams.lost(&st),
                             RecoveryToken::Crypto(ct) => self.crypto.lost(ct),
                             RecoveryToken::Flow(ft) => self.flow_mgr.borrow_mut().lost(
-                                ft,
+                                &ft,
                                 &mut self.send_streams,
                                 &mut self.recv_streams,
                                 &mut self.indexes,
                             ),
                         }
                     }
                 }
             }
             LossRecoveryMode::PTO => {
                 qinfo!(
-                    [self]
+                    [self],
                     "check_loss_detection_timeout -send_one_or_two_packets"
                 );
                 self.loss_recovery.increment_pto_count();
                 // TODO
                 // if (has unacknowledged crypto data):
                 //   RetransmitUnackedCryptoData()
                 // else if (endpoint is client without 1-RTT keys):
                 //   // Client sends an anti-deadlock packet: Initial is padded
@@ -1925,16 +1952,17 @@ impl ::std::fmt::Display for Connection 
         write!(f, "{:?} {:p}", self.role, self as *const Connection)
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use crate::frame::StreamType;
+    use std::mem;
     use test_fixture::{self, assertions, fixture_init, loopback, now};
 
     // This is fabulous: because test_fixture uses the public API for Connection,
     // it gets a different type to the ones that are referenced via super::*.
     // Thus, this code can't use default_client() and default_server() from
     // test_fixture because they produce different types.
     //
     // These are a direct copy of those functions.
@@ -2810,9 +2838,47 @@ mod tests {
 
         // The client gets the STOP_SENDING frame.
         client.process(out.dgram(), now());
         assert_eq!(
             Err(Error::InvalidStreamId),
             client.stream_send(stream_id, &[0x00])
         );
     }
+
+    #[test]
+    fn test_client_fin_reorder() {
+        let mut client = default_client();
+        let mut server = default_server();
+
+        // Send ClientHello.
+        let client_hs = client.process(None, now());
+        assert!(client_hs.as_dgram_ref().is_some());
+
+        let server_hs = server.process(client_hs.dgram(), now());
+        assert!(server_hs.as_dgram_ref().is_some()); // ServerHello, etc...
+
+        let client_ack = client.process(server_hs.dgram(), now());
+        assert!(client_ack.as_dgram_ref().is_some());
+
+        let server_out = server.process(client_ack.dgram(), now());
+        assert!(server_out.as_dgram_ref().is_none());
+
+        assert!(maybe_authenticate(&mut client));
+        assert_eq!(*client.state(), State::Connected);
+
+        let client_fin = client.process(None, now());
+        assert!(client_fin.as_dgram_ref().is_some());
+
+        let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
+        client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
+        let client_stream_data = client.process(None, now());
+        assert!(client_stream_data.as_dgram_ref().is_some());
+
+        // Now stream data gets before client_fin
+        let server_out = server.process(client_stream_data.dgram(), now());
+        assert!(server_out.as_dgram_ref().is_none()); // the packet will be discarded
+
+        assert_eq!(*server.state(), State::Handshaking);
+        let server_out = server.process(client_fin.dgram(), now());
+        assert!(server_out.as_dgram_ref().is_some());
+    }
 }
--- a/third_party/rust/neqo-transport/src/crypto.rs
+++ b/third_party/rust/neqo-transport/src/crypto.rs
@@ -1,28 +1,27 @@
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 use std::cell::RefCell;
-use std::cmp::min;
 use std::rc::Rc;
 
 use neqo_common::{hex, qdebug, qinfo, qtrace};
 use neqo_crypto::aead::Aead;
 use neqo_crypto::hp::HpKey;
 use neqo_crypto::{
-    hkdf, Agent, AntiReplay, Cipher, Epoch, SymKey, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384,
-    TLS_VERSION_1_3,
+    hkdf, Agent, AntiReplay, Cipher, Epoch, RecordList, SymKey, TLS_AES_128_GCM_SHA256,
+    TLS_AES_256_GCM_SHA384, TLS_VERSION_1_3,
 };
 
 use crate::connection::Role;
-use crate::frame::{crypto_frame_hdr_len, Frame, TxMode};
+use crate::frame::{Frame, TxMode};
 use crate::packet::{CryptoCtx, PacketNumber};
 use crate::recovery::RecoveryToken;
 use crate::recv_stream::RxStreamOrderer;
 use crate::send_stream::TxBuffer;
 use crate::tparams::{TpZeroRttChecker, TransportParametersHandler};
 use crate::{Error, Res};
 
 const MAX_AUTH_TAG: usize = 32;
@@ -57,58 +56,67 @@ impl Crypto {
         Ok(Crypto {
             tls: agent,
             streams: Default::default(),
             states: Default::default(),
         })
     }
 
     // Create the initial crypto state.
-    pub fn create_initial_state(&mut self, role: Role, dcid: &[u8]) -> CryptoState {
+    pub fn create_initial_state(&mut self, role: Role, dcid: &[u8]) {
         const CLIENT_INITIAL_LABEL: &str = "client in";
         const SERVER_INITIAL_LABEL: &str = "server in";
 
         qinfo!(
-            [self]
+            [self],
             "Creating initial cipher state role={:?} dcid={}",
             role,
             hex(dcid)
         );
 
         let (write_label, read_label) = match role {
             Role::Client => (CLIENT_INITIAL_LABEL, SERVER_INITIAL_LABEL),
             Role::Server => (SERVER_INITIAL_LABEL, CLIENT_INITIAL_LABEL),
         };
 
-        CryptoState {
+        self.states[0] = Some(CryptoState {
             epoch: 0,
             tx: CryptoDxState::new_initial(CryptoDxDirection::Write, write_label, dcid),
             rx: CryptoDxState::new_initial(CryptoDxDirection::Read, read_label, dcid),
+        });
+    }
+
+    /// Buffer crypto records for sending.
+    pub fn buffer_records(&mut self, records: RecordList) {
+        for r in records {
+            assert_eq!(r.ct, 22);
+            qdebug!([self], "Adding CRYPTO data {:?}", r);
+            self.streams[r.epoch as usize].tx.send(&r.data);
         }
     }
 
     // Get a crypto state, making it if necessary, otherwise return an error.
     pub fn obtain_crypto_state(&mut self, role: Role, epoch: Epoch) -> Res<&mut CryptoState> {
         #[cfg(debug_assertions)]
         let label = format!("{}", self);
         #[cfg(not(debug_assertions))]
         let label = "";
 
         let cs = &mut self.states[epoch as usize];
         if cs.is_none() {
-            qtrace!([label] "Build crypto state for epoch {}", epoch);
+            qtrace!([label], "Build crypto state for epoch {}", epoch);
             assert!(epoch != 0); // This state is made directly.
 
             let cipher = match (epoch, self.tls.info()) {
                 (1, _) => self.tls.preinfo()?.early_data_cipher(),
                 (_, None) => self.tls.preinfo()?.cipher_suite(),
                 (_, Some(info)) => Some(info.cipher_suite()),
             };
             if cipher.is_none() {
-                qdebug!([label] "cipher info not available yet");
+                qdebug!([label], "cipher info not available yet");
                 return Err(Error::KeysNotFound);
             }
             let cipher = cipher.unwrap();
 
             let rx = self
                 .tls
                 .read_secret(epoch)
                 .map(|rs| CryptoDxState::new(CryptoDxDirection::Read, epoch, rs, cipher));
@@ -118,17 +126,17 @@ impl Crypto {
                 .map(|ws| CryptoDxState::new(CryptoDxDirection::Write, epoch, ws, cipher));
 
             // Validate the key setup.
             match (&rx, &tx, role, epoch) {
                 (None, Some(_), Role::Client, 1)
                 | (Some(_), None, Role::Server, 1)
                 | (Some(_), Some(_), _, _) => {}
                 (None, None, _, _) => {
-                    qdebug!([label] "Keying material not available for epoch {}", epoch);
+                    qdebug!([label], "Keying material not available for epoch {}", epoch);
                     return Err(Error::KeysNotFound);
                 }
                 _ => panic!("bad configuration of keys"),
             }
 
             *cs = Some(CryptoState { epoch, rx, tx });
         }
 
@@ -162,22 +170,17 @@ impl Crypto {
     pub fn get_frame(
         &mut self,
         epoch: u16,
         mode: TxMode,
         remaining: usize,
     ) -> Option<(Frame, Option<RecoveryToken>)> {
         let tx_stream = &mut self.streams[epoch as usize].tx;
         if let Some((offset, data)) = tx_stream.next_bytes(mode) {
-            let frame_hdr_len = crypto_frame_hdr_len(offset, remaining);
-            let length = min(data.len(), remaining - frame_hdr_len);
-            let frame = Frame::Crypto {
-                offset,
-                data: data[..length].to_vec(),
-            };
+            let (frame, length) = Frame::new_crypto(offset, data, remaining);
             tx_stream.mark_as_sent(offset, length);
 
             qdebug!(
                 "Emitting crypto frame epoch={}, offset={}, len={}",
                 epoch,
                 offset,
                 length
             );
@@ -271,41 +274,41 @@ impl CryptoCtx for CryptoDxState {
     fn compute_mask(&self, sample: &[u8]) -> Res<Vec<u8>> {
         let mask = self.hpkey.mask(sample)?;
         qdebug!("HP sample={} mask={}", hex(sample), hex(&mask));
         Ok(mask)
     }
 
     fn aead_decrypt(&self, pn: PacketNumber, hdr: &[u8], body: &[u8]) -> Res<Vec<u8>> {
         qinfo!(
-            [self]
+            [self],
             "aead_decrypt pn={} hdr={} body={}",
             pn,
             hex(hdr),
             hex(body)
         );
         let mut out = vec![0; body.len()];
         let res = self.aead.decrypt(pn, hdr, body, &mut out)?;
         Ok(res.to_vec())
     }
 
     fn aead_encrypt(&self, pn: PacketNumber, hdr: &[u8], body: &[u8]) -> Res<Vec<u8>> {
         qdebug!(
-            [self]
+            [self],
             "aead_encrypt pn={} hdr={} body={}",
             pn,
             hex(hdr),
             hex(body)
         );
 
         let size = body.len() + MAX_AUTH_TAG;
         let mut out = vec![0; size];
         let res = self.aead.encrypt(pn, hdr, body, &mut out)?;
 
-        qdebug!([self] "aead_encrypt ct={}", hex(res),);
+        qdebug!([self], "aead_encrypt ct={}", hex(res),);
 
         Ok(res.to_vec())
     }
 }
 
 impl std::fmt::Display for CryptoDxState {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "epoch {} {:?}", self.epoch, self.direction)
--- a/third_party/rust/neqo-transport/src/dump.rs
+++ b/third_party/rust/neqo-transport/src/dump.rs
@@ -23,10 +23,10 @@ pub fn dump_packet(conn: &Connection, di
                 s.push_str(" [broken]...");
                 break;
             }
         };
         if let Some(x) = f.dump() {
             s.push_str(&format!("\n  {} {}", dir, &x));
         }
     }
-    qdebug!([conn] "pn={} type={:?}{}", hdr.pn, hdr.tipe, s);
+    qdebug!([conn], "pn={} type={:?}{}", hdr.pn, hdr.tipe, s);
 }
--- a/third_party/rust/neqo-transport/src/flow_mgr.rs
+++ b/third_party/rust/neqo-transport/src/flow_mgr.rs
@@ -46,20 +46,26 @@ impl FlowMgr {
         self.max_data - self.used_data
     }
 
     pub fn conn_increase_credit_used(&mut self, amount: u64) {
         self.used_data += amount;
         assert!(self.used_data <= self.max_data)
     }
 
+    // Dummy DataBlocked frame for discriminant use below
+
     /// Returns whether max credit was actually increased.
     pub fn conn_increase_max_credit(&mut self, new: u64) -> bool {
         if new > self.max_data {
             self.max_data = new;
+
+            const DB_FRAME: Frame = Frame::DataBlocked { data_limit: 0 };
+            self.from_conn.remove(&mem::discriminant(&DB_FRAME));
+
             true
         } else {
             false
         }
     }
 
     // -- frames scoped on connection --
 
@@ -70,16 +76,21 @@ impl FlowMgr {
         self.from_conn.insert(mem::discriminant(&frame), frame);
     }
 
     pub fn path_response(&mut self, data: [u8; 8]) {
         let frame = Frame::PathResponse { data };
         self.from_conn.insert(mem::discriminant(&frame), frame);
     }
 
+    pub fn max_data(&mut self, maximum_data: u64) {
+        let frame = Frame::MaxData { maximum_data };
+        self.from_conn.insert(mem::discriminant(&frame), frame);
+    }
+
     // -- frames scoped on stream --
 
     /// Indicate to receiving remote the stream is reset
     pub fn stream_reset(
         &mut self,
         stream_id: StreamId,
         application_error_code: AppError,
         final_size: u64,
@@ -200,22 +211,22 @@ impl FlowMgr {
             }
 
             send_streams.reset_acked(stream_id.into());
         }
     }
 
     pub(crate) fn lost(
         &mut self,
-        token: FlowControlRecoveryToken,
+        token: &FlowControlRecoveryToken,
         send_streams: &mut SendStreams,
         recv_streams: &mut RecvStreams,
         indexes: &mut StreamIndexes,
     ) {
-        match token {
+        match *token {
             // Always resend ResetStream if lost
             Frame::ResetStream {
                 stream_id,
                 application_error_code,
                 final_size,
             } => {
                 qinfo!(
                     "Reset lost stream={} err={} final_size={}",
--- a/third_party/rust/neqo-transport/src/frame.rs
+++ b/third_party/rust/neqo-transport/src/frame.rs
@@ -1,22 +1,26 @@
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 // Directly relating to QUIC frames.
 
-use neqo_common::{qdebug, Decoder, Encoder};
+use neqo_common::{matches, qdebug, Decoder, Encoder};
+use neqo_crypto::Epoch;
 
 use crate::stream_id::StreamIndex;
 use crate::{AppError, TransportError};
 use crate::{ConnectionError, Error, Res};
 
+use std::cmp::min;
+use std::convert::TryFrom;
+
 #[allow(clippy::module_name_repetitions)]
 pub type FrameType = u64;
 
 const FRAME_TYPE_PADDING: FrameType = 0x0;
 const FRAME_TYPE_PING: FrameType = 0x1;
 const FRAME_TYPE_ACK: FrameType = 0x2;
 const FRAME_TYPE_ACK_ECN: FrameType = 0x3;
 const FRAME_TYPE_RST_STREAM: FrameType = 0x4;
@@ -137,16 +141,17 @@ pub enum Frame {
     NewToken {
         token: Vec<u8>,
     },
     Stream {
         fin: bool,
         stream_id: u64,
         offset: u64,
         data: Vec<u8>,
+        fill: bool,
     },
     MaxData {
         maximum_data: u64,
     },
     MaxStreamData {
         stream_id: u64,
         maximum_stream_data: u64,
     },
@@ -192,25 +197,29 @@ impl Frame {
         match self {
             Frame::Padding => FRAME_TYPE_PADDING,
             Frame::Ping => FRAME_TYPE_PING,
             Frame::Ack { .. } => FRAME_TYPE_ACK, // We don't do ACK ECN.
             Frame::ResetStream { .. } => FRAME_TYPE_RST_STREAM,
             Frame::StopSending { .. } => FRAME_TYPE_STOP_SENDING,
             Frame::Crypto { .. } => FRAME_TYPE_CRYPTO,
             Frame::NewToken { .. } => FRAME_TYPE_NEW_TOKEN,
-            Frame::Stream { fin, offset, .. } => {
+            Frame::Stream {
+                fin, offset, fill, ..
+            } => {
                 let mut t = FRAME_TYPE_STREAM;
                 if *fin {
                     t |= STREAM_FRAME_BIT_FIN;
                 }
                 if *offset > 0 {
                     t |= STREAM_FRAME_BIT_OFF;
                 }
-                t |= STREAM_FRAME_BIT_LEN;
+                if !*fill {
+                    t |= STREAM_FRAME_BIT_LEN;
+                }
                 t
             }
             Frame::MaxData { .. } => FRAME_TYPE_MAX_DATA,
             Frame::MaxStreamData { .. } => FRAME_TYPE_MAX_STREAM_DATA,
             Frame::MaxStreams { stream_type, .. } => {
                 FRAME_TYPE_MAX_STREAMS_BIDI + stream_type.frame_type_bit()
             }
             Frame::DataBlocked { .. } => FRAME_TYPE_DATA_BLOCKED,
@@ -223,16 +232,78 @@ impl Frame {
             Frame::PathChallenge { .. } => FRAME_TYPE_PATH_CHALLENGE,
             Frame::PathResponse { .. } => FRAME_TYPE_PATH_RESPONSE,
             Frame::ConnectionClose { error_code, .. } => {
                 FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT + error_code.frame_type_bit()
             }
         }
     }
 
+    /// Create a CRYPTO frame that fits the available space and its length.
+    pub fn new_crypto(offset: u64, data: &[u8], space: usize) -> (Frame, usize) {
+        // Subtract the frame type and offset from available space.
+        let mut remaining = space - 1 - Encoder::varint_len(offset);
+        // Then subtract space for the length field.
+        let data_len = min(remaining - 1, data.len());
+        remaining -= Encoder::varint_len(u64::try_from(data_len).unwrap());
+        remaining = min(data.len(), remaining);
+        (
+            Frame::Crypto {
+                offset,
+                data: data[..remaining].to_vec(),
+            },
+            remaining,
+        )
+    }
+
+    /// Create a STREAM frame that fits the available space.
+    /// Return a tuple of a frame and the amount of data it carries.
+    pub fn new_stream(
+        stream_id: u64,
+        offset: u64,
+        data: &[u8],
+        fin: bool,
+        space: usize,
+    ) -> (Frame, usize) {
+        let mut remaining = space - 1 - Encoder::varint_len(stream_id);
+        if offset > 0 {
+            remaining -= Encoder::varint_len(offset);
+        }
+        let (fin, fill) = if data.len() > remaining {
+            // More data than fits, fill the packet and negate |fin|.
+            (false, true)
+        } else if data.len() == remaining {
+            // Exact fit, fill the packet, keep |fin|.
+            (fin, true)
+        } else {
+            // Too small, so include a length.
+            let data_len = min(remaining - 1, data.len());
+            remaining -= Encoder::varint_len(u64::try_from(data_len).unwrap());
+            remaining = min(data.len(), remaining);
+            // In case the added length causes this to spill over, check |fin| again.
+            (fin && remaining == data.len(), false)
+        };
+        qdebug!(
+            "Frame::new_stream fill {} fin {} data {}",
+            fill,
+            fin,
+            remaining
+        );
+        (
+            Frame::Stream {
+                stream_id,
+                offset,
+                data: data[..remaining].to_vec(),
+                fin,
+                fill,
+            },
+            remaining,
+        )
+    }
+
     pub fn marshal(&self, enc: &mut Encoder) {
         enc.encode_varint(self.get_type());
 
         match self {
             Frame::Padding | Frame::Ping => (),
             Frame::Ack {
                 largest_acknowledged,
                 ack_delay,
@@ -270,23 +341,28 @@ impl Frame {
             }
             Frame::NewToken { token } => {
                 enc.encode_vvec(token);
             }
             Frame::Stream {
                 stream_id,
                 offset,
                 data,
+                fill,
                 ..
             } => {
                 enc.encode_varint(*stream_id);
                 if *offset > 0 {
                     enc.encode_varint(*offset);
                 }
-                enc.encode_vvec(&data);
+                if *fill {
+                    enc.encode(&data);
+                } else {
+                    enc.encode_vvec(&data);
+                }
             }
             Frame::MaxData { maximum_data } => {
                 enc.encode_varint(*maximum_data);
             }
             Frame::MaxStreamData {
                 stream_id,
                 maximum_stream_data,
             } => {
@@ -340,20 +416,17 @@ impl Frame {
                 enc.encode_varint(error_code.code());
                 enc.encode_varint(*frame_type);
                 enc.encode_vvec(reason_phrase);
             }
         }
     }
 
     pub fn ack_eliciting(&self) -> bool {
-        match self {
-            Frame::Ack { .. } | Frame::Padding => false,
-            _ => true,
-        }
+        !matches!(self, Frame::Ack { .. } | Frame::Padding | Frame::ConnectionClose { .. })
     }
 
     /// Converts AckRanges as encoded in a ACK frame (see -transport
     /// 19.3.1) into ranges of acked packets (end, start), inclusive of
     /// start and end values.
     pub fn decode_ack_frame(
         largest_acked: u64,
         first_ack_range: u64,
@@ -399,36 +472,45 @@ impl Frame {
             Frame::Crypto { offset, data } => Some(format!(
                 "Crypto {{ offset: {}, len: {} }}",
                 offset,
                 data.len()
             )),
             Frame::Stream {
                 stream_id,
                 offset,
+                fill,
                 data,
                 fin,
             } => Some(format!(
-                "Stream {{ stream_id: {}, offset: {}, len: {} fin: {} }}",
+                "Stream {{ stream_id: {}, offset: {}, len: {}{} fin: {} }}",
                 stream_id,
                 offset,
+                if *fill { ">>" } else { "" },
                 data.len(),
                 fin,
             )),
             Frame::Padding => None,
             _ => Some(format!("{:?}", self)),
         }
     }
-}
 
-/// Calculate the crypto frame header size so we know how much data we can fit
-pub fn crypto_frame_hdr_len(offset: u64, remaining: usize) -> usize {
-    let mut hdr_len = 1; // for frame type
-    hdr_len += Encoder::varint_len(offset);
-    hdr_len + Encoder::varint_len(remaining as u64)
+    pub fn is_allowed(&self, epoch: Epoch) -> bool {
+        qdebug!("is_allowed {:?} {}", self, epoch);
+        if matches!(self, Frame::Padding | Frame::Ping) {
+            true
+        } else if matches!(self, Frame::Crypto {..} | Frame::Ack {..} | Frame::ConnectionClose { error_code: CloseError::Transport(_), .. })
+        {
+            epoch != 1
+        } else if matches!(self, Frame::NewToken {..} | Frame::ConnectionClose {..}) {
+            epoch >= 3
+        } else {
+            epoch == 1 || epoch >= 3 // Application data
+        }
+    }
 }
 
 #[allow(clippy::module_name_repetitions)]
 pub fn decode_frame(dec: &mut Decoder) -> Res<Frame> {
     macro_rules! d {
         ($d:expr) => {
             match $d {
                 Some(v) => v,
@@ -503,28 +585,30 @@ pub fn decode_frame(dec: &mut Decoder) -
         FRAME_TYPE_STREAM..=FRAME_TYPE_STREAM_MAX => {
             let s = dv!(dec);
             let o = if t & STREAM_FRAME_BIT_OFF == 0 {
                 0
             } else {
                 dv!(dec)
             };
             qdebug!("STREAM {}", t);
-            let data = if (t & STREAM_FRAME_BIT_LEN) == 0 {
+            let fill = (t & STREAM_FRAME_BIT_LEN) == 0;
+            let data = if fill {
                 qdebug!("STREAM frame extends to the end of the packet");
                 dec.decode_remainder()
             } else {
                 qdebug!("STREAM frame has a length");
                 d!(dec.decode_vvec())
             };
             Ok(Frame::Stream {
                 fin: (t & STREAM_FRAME_BIT_FIN) != 0,
                 stream_id: s,
                 offset: o,
                 data: data.to_vec(), // TODO(mt) unnecessary copy.
+                fill,
             })
         }
         FRAME_TYPE_MAX_DATA => Ok(Frame::MaxData {
             maximum_data: dv!(dec),
         }),
         FRAME_TYPE_MAX_STREAM_DATA => Ok(Frame::MaxStreamData {
             stream_id: dv!(dec),
             maximum_stream_data: dv!(dec),
@@ -586,17 +670,16 @@ pub fn decode_frame(dec: &mut Decoder) -
         }
         _ => Err(Error::UnknownFrameType),
     }
 }
 
 #[derive(Debug, PartialEq, Clone, Copy)]
 pub enum TxMode {
     Normal,
-    #[allow(dead_code)]
     Pto,
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use neqo_common::hex;
 
@@ -684,40 +767,45 @@ mod tests {
         };
 
         enc_dec(&f, "0703123456");
     }
 
     #[test]
     fn test_stream() {
         // First, just set the length bit.
-        let mut f = Frame::Stream {
+        let f = Frame::Stream {
             fin: false,
             stream_id: 5,
             offset: 0,
             data: vec![1, 2, 3],
+            fill: false,
         };
 
         enc_dec(&f, "0a0503010203");
 
-        // Now verify that we can parse without the length
-        // bit, because we never generate this.
-        let enc = Encoder::from_hex("0805010203");
-        let mut dec = enc.as_decoder();
-        let f2 = decode_frame(&mut dec).unwrap();
-        assert_eq!(f, f2);
-
         // Now with offset != 0 and FIN
-        f = Frame::Stream {
+        let f = Frame::Stream {
             fin: true,
             stream_id: 5,
             offset: 1,
             data: vec![1, 2, 3],
+            fill: false,
         };
         enc_dec(&f, "0f050103010203");
+
+        // Now to fill the packet.
+        let f = Frame::Stream {
+            fin: true,
+            stream_id: 5,
+            offset: 0,
+            data: vec![1, 2, 3],
+            fill: true,
+        };
+        enc_dec(&f, "0905010203");
     }
 
     #[test]
     fn test_max_data() {
         let f = Frame::MaxData {
             maximum_data: 0x1234,
         };
 
--- a/third_party/rust/neqo-transport/src/recovery.rs
+++ b/third_party/rust/neqo-transport/src/recovery.rs
@@ -14,17 +14,16 @@ use std::time::{Duration, Instant};
 use smallvec::SmallVec;
 
 use neqo_common::{qdebug, qinfo};
 
 use crate::crypto::CryptoRecoveryToken;
 use crate::flow_mgr::FlowControlRecoveryToken;
 use crate::send_stream::StreamRecoveryToken;
 use crate::tracking::{AckToken, PNSpace};
-use crate::State;
 
 const GRANULARITY: Duration = Duration::from_millis(20);
 // Defined in -recovery 6.2 as 500ms but using lower value until we have RTT
 // caching. See https://github.com/mozilla/neqo/issues/79
 const INITIAL_RTT: Duration = Duration::from_millis(100);
 
 const PACKET_THRESHOLD: u64 = 3;
 
@@ -239,17 +238,17 @@ impl LossRecovery {
         self.spaces[pn_space].tx_pn += 1;
         val
     }
 
     pub fn increment_pto_count(&mut self) {
         self.pto_count += 1;
     }
 
-    pub fn largest_acknowledged(&self, pn_space: PNSpace) -> Option<u64> {
+    pub fn largest_acknowledged_pn(&self, pn_space: PNSpace) -> Option<u64> {
         self.spaces[pn_space].largest_acked
     }
 
     pub fn pto(&self) -> Duration {
         self.rtt_vals.pto()
     }
 
     pub fn drop_0rtt(&mut self) -> impl Iterator<Item = SentPacket> {
@@ -259,17 +258,17 @@ impl LossRecovery {
     pub fn on_packet_sent(
         &mut self,
         pn_space: PNSpace,
         packet_number: u64,
         ack_eliciting: bool,
         tokens: Vec<RecoveryToken>,
         now: Instant,
     ) {
-        qdebug!([self] "packet {:?}-{} sent.", pn_space, packet_number);
+        qdebug!([self], "packet {:?}-{} sent.", pn_space, packet_number);
         self.spaces[pn_space].sent_packets.insert(
             packet_number,
             SentPacket {
                 time_sent: now,
                 ack_eliciting,
                 tokens,
                 time_declared_lost: None,
             },
@@ -285,18 +284,22 @@ impl LossRecovery {
     pub fn on_ack_received(
         &mut self,
         pn_space: PNSpace,
         largest_acked: u64,
         acked_ranges: Vec<(u64, u64)>,
         ack_delay: Duration,
         now: Instant,
     ) -> (Vec<SentPacket>, Vec<SentPacket>) {
-        qdebug!([self] "ack received for {:?} - largest_acked={}.",
-                pn_space, largest_acked);
+        qdebug!(
+            [self],
+            "ack received for {:?} - largest_acked={}.",
+            pn_space,
+            largest_acked
+        );
 
         let (acked_packets, any_ack_eliciting) = self.spaces[pn_space].remove_acked(acked_ranges);
         if acked_packets.is_empty() {
             // No new information.
             return (Vec::new(), Vec::new());
         }
 
         // Track largest PN acked per space
@@ -349,19 +352,22 @@ impl LossRecovery {
 
     /// Detect packets whose contents may need to be retransmitted.
     pub fn detect_lost_packets(&mut self, pn_space: PNSpace, now: Instant) -> Vec<SentPacket> {
         self.enable_timed_loss_detection = false;
         let loss_delay = self.loss_delay();
 
         // Packets sent before this time are deemed lost.
         let lost_deadline = now - loss_delay;
-        qdebug!([self]
+        qdebug!(
+            [self],
             "detect lost packets = now {:?} loss delay {:?} lost_deadline {:?}",
-            now, loss_delay, lost_deadline
+            now,
+            loss_delay,
+            lost_deadline
         );
 
         let packet_space = &mut self.spaces[pn_space];
 
         // Lost for retrans/CC purposes
         let mut lost_pns = SmallVec::<[_; 8]>::new();
 
         // Lost for we-can-actually-forget-about-it purposes
@@ -431,36 +437,33 @@ impl LossRecovery {
                 .expect("PN must be in sent_packets")
                 .clone();
             lost_packets.push(lost_packet);
         }
 
         lost_packets
     }
 
-    pub fn get_timer(&mut self, conn_state: &State) -> LossRecoveryState {
-        qdebug!([self] "get_loss_detection_timer.");
+    pub fn get_timer(&mut self) -> LossRecoveryState {
+        qdebug!([self], "get_loss_detection_timer.");
 
         let has_ack_eliciting_out = self
             .spaces
             .iter()
             .flat_map(|spc| spc.sent_packets.values())
             .any(|sp| sp.ack_eliciting);
 
-        qdebug!(
-            [self]
-            "has_ack_eliciting_out={}",
-            has_ack_eliciting_out,
-        );
+        qdebug!([self], "has_ack_eliciting_out={}", has_ack_eliciting_out,);
 
-        if !has_ack_eliciting_out && *conn_state == State::Connected {
+        if !has_ack_eliciting_out {
             return LossRecoveryState::new(LossRecoveryMode::None, None);
         }
 
-        qinfo!([self]
+        qinfo!(
+            [self],
             "sent packets {} {} {}",
             self.spaces[PNSpace::Initial].sent_packets.len(),
             self.spaces[PNSpace::Handshake].sent_packets.len(),
             self.spaces[PNSpace::ApplicationData].sent_packets.len()
         );
 
         // QUIC only has one timer, but it does double duty because it falls
         // back to other uses if first use is not needed: first the loss
@@ -473,17 +476,22 @@ impl LossRecovery {
             let timeout = self.rtt_vals.pto() * 2_u32.pow(self.pto_count);
             (
                 LossRecoveryMode::PTO,
                 self.time_of_last_sent_ack_eliciting_packet
                     .map(|i| i + timeout),
             )
         };
 
-        qdebug!([self] "loss_detection_timer mode={:?} timer={:?}", mode, maybe_timer);
+        qdebug!(
+            [self],
+            "loss_detection_timer mode={:?} timer={:?}",
+            mode,
+            maybe_timer
+        );
         LossRecoveryState::new(mode, maybe_timer)
     }
 
     /// Find when the earliest sent packet should be considered lost.
     pub fn get_earliest_loss_time(&self) -> Option<(PNSpace, Instant)> {
         if !self.enable_timed_loss_detection {
             return None;
         }
@@ -738,17 +746,17 @@ mod tests {
             ACK_DELAY,
             pn_time(2) + INITIAL_RTT,
         );
         assert!(lost.is_empty());
         let pn1_sent_time = pn_time(1);
         assert_sent_times(&lr, None, None, Some(pn1_sent_time));
 
         // After time elapses, pn 1 is marked lost.
-        let lr_state = lr.get_timer(&State::Connected);
+        let lr_state = lr.get_timer();
         let pn1_lost_time = pn1_sent_time + (INITIAL_RTT * 9 / 8);
         assert_eq!(lr_state.callback_time, Some(pn1_lost_time));
         match lr_state.mode {
             LossRecoveryMode::LostPackets => {
                 let packets = lr.detect_lost_packets(PNSpace::ApplicationData, pn1_lost_time);
 
                 assert_eq!(packets.len(), 1)
             }
--- a/third_party/rust/neqo-transport/src/recv_stream.rs
+++ b/third_party/rust/neqo-transport/src/recv_stream.rs
@@ -16,17 +16,17 @@ use std::ops::Bound::{Included, Unbounde
 use std::rc::Rc;
 
 use smallvec::SmallVec;
 
 use crate::events::ConnectionEvents;
 use crate::flow_mgr::FlowMgr;
 use crate::stream_id::StreamId;
 use crate::{AppError, Error, Res};
-use neqo_common::qtrace;
+use neqo_common::{matches, qtrace};
 
 pub const RX_STREAM_DATA_WINDOW: u64 = 0xFFFF; // 64 KiB
 
 pub(crate) type RecvStreams = BTreeMap<StreamId, RecvStream>;
 
 /// Holds data not yet read by application. Orders and dedupes data ranges
 /// from incoming STREAM frames.
 #[derive(Debug, Default, PartialEq)]
@@ -459,28 +459,25 @@ impl RecvStream {
                         .borrow_mut()
                         .max_stream_data(self.stream_id, maybe_new_max)
                 }
             }
         }
     }
 
     pub fn is_terminal(&self) -> bool {
-        match self.state {
-            RecvStreamState::ResetRecvd | RecvStreamState::DataRead => true,
-            _ => false,
-        }
+        matches!(
+            self.state,
+            RecvStreamState::ResetRecvd | RecvStreamState::DataRead
+        )
     }
 
     // App got all data but did not get the fin signal.
     fn needs_to_inform_app_about_fin(&self) -> bool {
-        match self.state {
-            RecvStreamState::DataRecvd { .. } => true,
-            _ => false,
-        }
+        matches!(self.state, RecvStreamState::DataRecvd { .. })
     }
 
     fn data_ready(&self) -> bool {
         self.state
             .recv_buf()
             .map_or(false, RxStreamOrderer::data_ready)
     }
 
@@ -746,10 +743,9 @@ mod tests {
         assert_eq!(rx_ord.buffered(), 15);
         assert_eq!(rx_ord.retired(), 2);
         // an old frame
         rx_ord.inbound_frame(0, vec![4; 2]).unwrap();
         assert_eq!(rx_ord.bytes_ready(), 9);
         assert_eq!(rx_ord.buffered(), 15);
         assert_eq!(rx_ord.retired(), 2);
     }
-
 }
--- a/third_party/rust/neqo-transport/src/send_stream.rs
+++ b/third_party/rust/neqo-transport/src/send_stream.rs
@@ -11,17 +11,17 @@ use std::cmp::{max, min};
 use std::collections::{hash_map::IterMut, BTreeMap, HashMap};
 use std::convert::{TryFrom, TryInto};
 use std::mem;
 use std::rc::Rc;
 
 use slice_deque::SliceDeque;
 use smallvec::SmallVec;
 
-use neqo_common::{matches, qerror, qinfo, qtrace, qwarn, Encoder};
+use neqo_common::{matches, qdebug, qerror, qinfo, qtrace, qwarn};
 
 use crate::events::ConnectionEvents;
 use crate::flow_mgr::FlowMgr;
 use crate::frame::{Frame, TxMode};
 use crate::recovery::RecoveryToken;
 use crate::stream_id::StreamId;
 use crate::{AppError, Error, Res};
 
@@ -294,30 +294,41 @@ impl TxBuffer {
         let can_buffer = min(TxBuffer::BUFFER_SIZE - self.buffered(), buf.len());
         if can_buffer > 0 {
             self.send_buf.extend(&buf[..can_buffer]);
             assert!(self.send_buf.len() <= TxBuffer::BUFFER_SIZE);
         }
         can_buffer
     }
 
-    pub fn next_bytes(&self, _mode: TxMode) -> Option<(u64, &[u8])> {
-        let (start, maybe_len) = self.ranges.first_unmarked_range();
+    pub fn next_bytes(&self, mode: TxMode) -> Option<(u64, &[u8])> {
+        match mode {
+            TxMode::Normal => {
+                let (start, maybe_len) = self.ranges.first_unmarked_range();
 
-        if start == self.retired + u64::try_from(self.buffered()).unwrap() {
-            return None;
-        }
+                if start == self.retired + u64::try_from(self.buffered()).unwrap() {
+                    return None;
+                }
 
-        let buff_off = usize::try_from(start - self.retired).unwrap();
-        match maybe_len {
-            Some(len) => Some((
-                start,
-                &self.send_buf[buff_off..buff_off + usize::try_from(len).unwrap()],
-            )),
-            None => Some((start, &self.send_buf[buff_off..])),
+                let buff_off = usize::try_from(start - self.retired).unwrap();
+                match maybe_len {
+                    Some(len) => Some((
+                        start,
+                        &self.send_buf[buff_off..buff_off + usize::try_from(len).unwrap()],
+                    )),
+                    None => Some((start, &self.send_buf[buff_off..])),
+                }
+            }
+            TxMode::Pto => {
+                if self.buffered() == 0 {
+                    None
+                } else {
+                    Some((self.retired, &self.send_buf))
+                }
+            }
         }
     }
 
     pub fn mark_as_sent(&mut self, offset: u64, len: usize) {
         self.ranges.mark_range(offset, len, RangeState::Sent)
     }
 
     pub fn mark_as_acked(&mut self, offset: u64, len: usize) {
@@ -601,20 +612,17 @@ impl SendStream {
                 qtrace!("Reset acked while in {} state?", self.state.name())
             }
             SendStreamState::ResetSent => self.state.transition(SendStreamState::ResetRecvd),
             SendStreamState::ResetRecvd => qtrace!("already in ResetRecvd state"),
         };
     }
 
     pub fn is_terminal(&self) -> bool {
-        match self.state {
-            SendStreamState::DataRecvd { .. } | SendStreamState::ResetRecvd => true,
-            _ => false,
-        }
+        matches!(self.state, SendStreamState::DataRecvd { .. } | SendStreamState::ResetRecvd)
     }
 
     pub fn send(&mut self, buf: &[u8]) -> Res<usize> {
         if buf.is_empty() {
             qerror!("zero-length send on stream {}", self.stream_id.as_u64());
             return Err(Error::InvalidInput);
         }
 
@@ -754,40 +762,32 @@ impl SendStreams {
         mode: TxMode,
         remaining: usize,
     ) -> Option<(Frame, Option<RecoveryToken>)> {
         if epoch != 3 && epoch != 1 {
             return None;
         }
 
         for (stream_id, stream) in self {
-            let fin = stream.final_size();
+            let complete = stream.final_size().is_some();
             if let Some((offset, data)) = stream.next_bytes(mode) {
-                qtrace!(
-                    "Stream {} sending bytes {}-{}, epoch {}, mode {:?}, remaining {}",
+                let (frame, length) =
+                    Frame::new_stream(stream_id.as_u64(), offset, data, complete, remaining);
+                qdebug!(
+                    "Stream {} sending bytes {}-{}, epoch {}, mode {:?}",
                     stream_id.as_u64(),
                     offset,
-                    offset + data.len() as u64,
+                    offset + length as u64,
                     epoch,
                     mode,
-                    remaining
                 );
-                let frame_hdr_len = stream_frame_hdr_len(*stream_id, offset, remaining);
-                let length = min(data.len(), remaining - frame_hdr_len);
-                let fin = match fin {
-                    None => false,
-                    Some(fin) => fin == offset + length as u64,
-                };
-                let frame = Frame::Stream {
-                    fin,
-                    stream_id: stream_id.as_u64(),
-                    offset,
-                    data: data[..length].to_vec(),
-                };
+                let fin = complete && length == data.len();
+                debug_assert!(!fin || matches!(frame, Frame::Stream{fin: true, .. }));
                 stream.mark_as_sent(offset, length, fin);
+
                 return Some((
                     frame,
                     Some(RecoveryToken::Stream(StreamRecoveryToken {
                         id: *stream_id,
                         offset,
                         length,
                         fin,
                     })),
@@ -802,28 +802,16 @@ impl<'a> IntoIterator for &'a mut SendSt
     type Item = (&'a StreamId, &'a mut SendStream);
     type IntoIter = IterMut<'a, StreamId, SendStream>;
 
     fn into_iter(self) -> IterMut<'a, StreamId, SendStream> {
         self.0.iter_mut()
     }
 }
 
-/// Calculate the frame header size so we know how much data we can fit
-fn stream_frame_hdr_len(stream_id: StreamId, offset: u64, remaining: usize) -> usize {
-    let mut hdr_len = 1; // for frame type
-    hdr_len += Encoder::varint_len(stream_id.as_u64());
-    if offset > 0 {
-        hdr_len += Encoder::varint_len(offset);
-    }
-
-    // We always include a length field.
-    hdr_len + Encoder::varint_len(remaining as u64)
-}
-
 #[derive(Debug, Clone)]
 pub struct StreamRecoveryToken {
     pub(crate) id: StreamId,
     offset: u64,
     length: usize,
     fin: bool,
 }
 
@@ -877,16 +865,25 @@ mod tests {
         rt.mark_range(5, 5, RangeState::Acked);
         rt.mark_range(10, 5, RangeState::Sent);
 
         // Should unmark sent but not acked range
         rt.unmark_range(7, 6);
 
         let res = rt.first_unmarked_range();
         assert_eq!(res, (0, Some(5)));
+        assert_eq!(
+            rt.used.iter().nth(0).unwrap(),
+            (&5, &(5, RangeState::Acked))
+        );
+        assert_eq!(
+            rt.used.iter().nth(1).unwrap(),
+            (&13, &(2, RangeState::Sent))
+        );
+        assert!(rt.used.iter().nth(2).is_none());
         rt.mark_range(0, 5, RangeState::Sent);
 
         let res = rt.first_unmarked_range();
         assert_eq!(res, (10, Some(3)));
         rt.mark_range(10, 3, RangeState::Sent);
 
         let res = rt.first_unmarked_range();
         assert_eq!(res, (15, None));
--- a/third_party/rust/neqo-transport/src/server.rs
+++ b/third_party/rust/neqo-transport/src/server.rs
@@ -43,17 +43,17 @@ const MIN_INITIAL_PACKET_SIZE: usize = 1
 const TIMER_GRANULARITY: Duration = Duration::from_millis(10);
 const TIMER_CAPACITY: usize = 16384;
 
 type StateRef = Rc<RefCell<ServerConnectionState>>;
 type CidMgr = Rc<RefCell<dyn ConnectionIdManager>>;
 type ConnectionTableRef = Rc<RefCell<HashMap<ConnectionId, StateRef>>>;
 
 #[derive(Debug)]
-struct ServerConnectionState {
+pub struct ServerConnectionState {
     c: Connection,
     last_timer: Instant,
 }
 
 impl Deref for ServerConnectionState {
     type Target = Connection;
     fn deref(&self) -> &Self::Target {
         &self.c
@@ -259,38 +259,38 @@ impl Server {
     }
 
     fn process_connection(
         &mut self,
         c: StateRef,
         dgram: Option<Datagram>,
         now: Instant,
     ) -> Option<Datagram> {
-        qtrace!([self] "Process connection {:?}", c);
+        qtrace!([self], "Process connection {:?}", c);
         let out = c.borrow_mut().process(dgram, now);
         match out {
             Output::Datagram(_) => {
-                qtrace!([self] "Sending packet, added to waiting connections");
+                qtrace!([self], "Sending packet, added to waiting connections");
                 self.waiting.push_back(c.clone());
             }
             Output::Callback(delay) => {
                 let next = now + delay;
                 if next != c.borrow().last_timer {
-                    qtrace!([self] "Change timer to {:?}", next);
+                    qtrace!([self], "Change timer to {:?}", next);
                     self.remove_timer(&c);
                     c.borrow_mut().last_timer = next;
                     self.timers.add(next, c.clone());
                 }
             }
             _ => {
                 self.remove_timer(&c);
             }
         }
         if c.borrow().has_events() {
-            qtrace!([self] "Connection active: {:?}", c);
+            qtrace!([self], "Connection active: {:?}", c);
             self.active.insert(ActiveConnectionRef { c: c.clone() });
         }
         if matches!(c.borrow().state(), State::Closed(_)) {
             self.connections
                 .borrow_mut()
                 .retain(|_, v| !Rc::ptr_eq(v, &c));
         }
         out.dgram()
@@ -310,17 +310,17 @@ impl Server {
         dgram: Datagram,
         now: Instant,
     ) -> Option<Datagram> {
         match self.retry.validate(&hdr, dgram.source(), now) {
             RetryTokenResult::Invalid => None,
             RetryTokenResult::Pass => self.accept_connection(None, dgram, now),
             RetryTokenResult::Valid(dcid) => self.accept_connection(Some(dcid), dgram, now),
             RetryTokenResult::Validate => {
-                qinfo!([self] "Send retry for {:?}", hdr.dcid);
+                qinfo!([self], "Send retry for {:?}", hdr.dcid);
 
                 let res = self.retry.generate_token(&hdr.dcid, dgram.source(), now);
                 let token = if let Ok(t) = res {
                     t
                 } else {
                     qerror!([self], "unable to generate token, dropping packet");
                     return None;
                 };
@@ -343,17 +343,17 @@ impl Server {
     }
 
     fn accept_connection(
         &mut self,
         odcid: Option<ConnectionId>,
         dgram: Datagram,
         now: Instant,
     ) -> Option<Datagram> {
-        qinfo!([self] "Accept connection");
+        qinfo!([self], "Accept connection");
         // The internal connection ID manager that we use is not used directly.
         // Instead, wrap it so that we can save connection IDs.
         let cid_mgr = Rc::new(RefCell::new(ServerConnectionIdManager {
             c: None,
             cid_manager: self.cid_manager.clone(),
             connections: self.connections.clone(),
         }));
         let sconn = Connection::new_server(
@@ -365,68 +365,68 @@ impl Server {
         if let Ok(mut c) = sconn {
             if let Some(odcid) = odcid {
                 c.original_connection_id(&odcid);
             }
             let c = Rc::new(RefCell::new(ServerConnectionState { c, last_timer: now }));
             cid_mgr.borrow_mut().c = Some(c.clone());
             self.process_connection(c, Some(dgram), now)
         } else {
-            qwarn!([self] "Unable to create connection");
+            qwarn!([self], "Unable to create connection");
             None
         }
     }
 
     fn process_input(&mut self, dgram: Datagram, now: Instant) -> Option<Datagram> {
         qtrace!("Process datagram: {}", hex(&dgram[..]));
 
         // This is only looking at the first packet header in the datagram.
         // All packets in the datagram are routed to the same connection.
         let res = decode_packet_hdr(self.cid_manager.borrow().as_decoder(), &dgram[..]);
         let hdr = match res {
             Ok(h) => h,
             _ => {
-                qtrace!([self] "Discarding {:?}", dgram);
+                qtrace!([self], "Discarding {:?}", dgram);
                 return None;
             }
         };
 
         // Finding an existing connection. Should be the most common case.
         if let Some(c) = self.connection(&hdr.dcid) {
             return self.process_connection(c, Some(dgram), now);
         }
 
         if hdr.tipe == PacketType::Short {
             // TODO send a stateless reset here.
-            qtrace!([self] "Short header packet for an unknown connection");
+            qtrace!([self], "Short header packet for an unknown connection");
             return None;
         }
 
         if dgram.len() < MIN_INITIAL_PACKET_SIZE {
-            qtrace!([self] "Bogus packet: too short");
+            qtrace!([self], "Bogus packet: too short");
             return None;
         }
 
         if hdr.version != Some(self.version) {
             return Some(self.create_vn(&hdr, dgram));
         }
 
         self.handle_initial(hdr, dgram, now)
     }
 
     /// Iterate through the pending connections looking for any that might want
     /// to send a datagram.  Stop at the first one that does.
     fn process_next_output(&mut self, now: Instant) -> Option<Datagram> {
-        qtrace!([self] "No packet to send, look at waiting connections");
+        qtrace!([self], "No packet to send, look at waiting connections");
         while let Some(c) = self.waiting.pop_front() {
             if let Some(d) = self.process_connection(c, None, now) {
                 return Some(d);
             }
         }
-        qtrace!([self] "No packet to send still, run timers");
+        qtrace!([self], "No packet to send still, run timers");
         while let Some(c) = self.timers.take_next(now) {
             if let Some(d) = self.process_connection(c, None, now) {
                 return Some(d);
             }
         }
         None
     }
 
@@ -442,68 +442,77 @@ impl Server {
         let out = if let Some(d) = dgram {
             self.process_input(d, now)
         } else {
             None
         };
         let out = out.or_else(|| self.process_next_output(now));
         match out {
             Some(d) => {
-                qtrace!([self] "Send packet: {:?}", d);
+                qtrace!([self], "Send packet: {:?}", d);
                 Output::Datagram(d)
             }
             _ => match self.next_time(now) {
                 Some(delay) => {
-                    qtrace!([self] "Wait: {:?}", delay);
+                    qtrace!([self], "Wait: {:?}", delay);
                     Output::Callback(delay)
                 }
                 _ => {
-                    qtrace!([self] "Go dormant");
+                    qtrace!([self], "Go dormant");
                     Output::None
                 }
             },
         }
     }
 
     /// This lists the connections that have received new events
     /// as a result of calling `process()`.
     pub fn active_connections(&mut self) -> Vec<ActiveConnectionRef> {
         mem::replace(&mut self.active, Default::default())
             .into_iter()
             .collect()
     }
+
+    pub fn add_to_waiting(&mut self, c: ActiveConnectionRef) {
+        self.waiting.push_back(c.connection());
+    }
 }
 
 #[derive(Clone, Debug)]
 pub struct ActiveConnectionRef {
     c: StateRef,
 }
 
 impl ActiveConnectionRef {
     pub fn borrow<'a>(&'a self) -> impl Deref<Target = Connection> + 'a {
         std::cell::Ref::map(self.c.borrow(), |c| &c.c)
     }
 
     pub fn borrow_mut<'a>(&'a mut self) -> impl DerefMut<Target = Connection> + 'a {
         std::cell::RefMut::map(self.c.borrow_mut(), |c| &mut c.c)
     }
+
+    pub fn connection(&self) -> StateRef {
+        self.c.clone()
+    }
 }
 
 impl std::hash::Hash for ActiveConnectionRef {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         let ptr: *const _ = self.c.as_ref();
         ptr.hash(state)
     }
 }
 
 impl PartialEq for ActiveConnectionRef {
     fn eq(&self, other: &Self) -> bool {
         Rc::ptr_eq(&self.c, &other.c)
     }
 }
+
 impl Eq for ActiveConnectionRef {}
 
 struct ServerConnectionIdManager {
     c: Option<StateRef>,
     connections: ConnectionTableRef,
     cid_manager: CidMgr,
 }
 
--- a/third_party/rust/neqo-transport/src/tracking.rs
+++ b/third_party/rust/neqo-transport/src/tracking.rs
@@ -79,46 +79,46 @@ impl PacketRange {
         (pn >= self.smallest) && (pn <= self.largest)
     }
 
     /// Maybe add a packet number to the range.  Returns true if it was added.
     pub fn add(&mut self, pn: u64) -> bool {
         assert!(!self.contains(pn));
         // Only insert if this is adjacent the current range.
         if (self.largest + 1) == pn {
-            qtrace!([self] "Adding largest {}", pn);
+            qtrace!([self], "Adding largest {}", pn);
             self.largest += 1;
             self.ack_needed = true;
             true
         } else if self.smallest == (pn + 1) {
-            qtrace!([self] "Adding smallest {}", pn);
+            qtrace!([self], "Adding smallest {}", pn);
             self.smallest -= 1;
             self.ack_needed = true;
             true
         } else {
             false
         }
     }
 
     /// Maybe merge a lower-numbered range into this.
     pub fn merge_smaller(&mut self, other: &Self) {
-        qinfo!([self] "Merging {}", other);
+        qinfo!([self], "Merging {}", other);
         // This only works if they are immediately adjacent.
         assert_eq!(self.smallest - 1, other.largest);
 
         self.smallest = other.smallest;
         self.ack_needed = self.ack_needed || other.ack_needed;
     }
 
     /// When a packet containing the range `other` is acknowledged,
     /// clear the ack_needed attribute on this.
     /// Requires that other is equal to this, or a larger range.
     pub fn acknowledged(&mut self, other: &Self) {
         if (other.smallest <= self.smallest) && (other.largest >= self.largest) {
-            qinfo!([self] "Acknowledged");
+            qinfo!([self], "Acknowledged");
             self.ack_needed = false;
         }
     }
 }
 
 impl ::std::fmt::Display for PacketRange {
     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(f, "{}->{}", self.largest, self.smallest)
@@ -196,39 +196,44 @@ impl RecvdPackets {
             }
         }
         self.ranges.push_back(PacketRange::new(pn));
         self.ranges.len() - 1
     }
 
     /// Add the packet to the tracked set.
     pub fn set_received(&mut self, now: Instant, pn: u64, ack_eliciting: bool) {
+        let next_in_order_pn = self.ranges.get(0).map(|pr| pr.largest + 1).unwrap_or(0);
+        qdebug!("next in order pn: {}", next_in_order_pn);
         let i = self.add(pn);
 
         // The new addition was the largest, so update the time we use for calculating ACK delay.
         if i == 0 && pn == self.ranges[0].largest {
             self.largest_pn_time = Some(now);
         }
 
         // Limit the number of ranges that are tracked to MAX_TRACKED_RANGES.
         if self.ranges.len() > MAX_TRACKED_RANGES {
             let oldest = self.ranges.pop_back().unwrap();
             if oldest.ack_needed {
-                qwarn!([self] "Dropping unacknowledged ACK range: {}", oldest);
+                qwarn!([self], "Dropping unacknowledged ACK range: {}", oldest);
             // TODO(mt) Record some statistics about this so we can tune MAX_TRACKED_RANGES.
             } else {
-                qdebug!([self] "Drop ACK range: {}", oldest);
+                qdebug!([self], "Drop ACK range: {}", oldest);
             }
             self.min_tracked = oldest.largest + 1;
         }
 
         if ack_eliciting {
-            // On the first ack-eliciting packet since sending an ACK, set a delay.
-            // On the second, remove that delay.
-            if self.ack_time.is_none() && self.space == PNSpace::ApplicationData {
+            // Send ACK right away if out-of-order
+            // On the first in-order ack-eliciting packet since sending an ACK,
+            // set a delay. On the second, remove that delay.
+            if pn != next_in_order_pn {
+                self.ack_time = Some(now);
+            } else if self.ack_time.is_none() && self.space == PNSpace::ApplicationData {
                 self.ack_time = Some(now + ACK_DELAY);
             } else {
                 self.ack_time = Some(now);
             }
         }
     }
 
     /// Check if the packet is a duplicate.
@@ -503,16 +508,34 @@ mod tests {
             // Any packet will be acknowledged straight away.
             rp.set_received(now(), 0, true);
             assert_eq!(Some(now()), rp.ack_time());
             assert!(rp.ack_now(now()));
         }
     }
 
     #[test]
+    fn ooo_no_ack_delay() {
+        for space in &[
+            PNSpace::Initial,
+            PNSpace::Handshake,
+            PNSpace::ApplicationData,
+        ] {
+            let mut rp = RecvdPackets::new(*space);
+            assert!(rp.ack_time().is_none());
+            assert!(!rp.ack_now(now()));
+
+            // Any OoO packet will be acknowledged straight away.
+            rp.set_received(now(), 3, true);
+            assert_eq!(Some(now()), rp.ack_time());
+            assert!(rp.ack_now(now()));
+        }
+    }
+
+    #[test]
     fn aggregate_ack_time() {
         let mut tracker = AckTracker::default();
         // This packet won't trigger an ACK.
         tracker[PNSpace::Handshake].set_received(now(), 0, false);
         assert_eq!(None, tracker.ack_time());
 
         // This should be delayed.
         tracker[PNSpace::ApplicationData].set_received(now(), 0, true);
--- a/toolkit/components/reader/test/browser.ini
+++ b/toolkit/components/reader/test/browser.ini
@@ -1,34 +1,29 @@
 [DEFAULT]
 support-files = head.js
 [browser_readerMode.js]
 support-files =
   readerModeNonArticle.html
   readerModeArticle.html
   readerModeArticleHiddenNodes.html
-skip-if = fission
+skip-if = fission && os == 'win' # Bug 1586139
 [browser_readerMode_hidden_nodes.js]
 support-files =
   readerModeArticleHiddenNodes.html
-skip-if = fission
 [browser_readerMode_with_anchor.js]
 support-files =
   readerModeArticle.html
 uses-unsafe-cpows = true
-skip-if = fission
 [browser_bug1124271_readerModePinnedTab.js]
 support-files =
   readerModeArticle.html
-skip-if = fission
 [browser_bug1453818_samesite_cookie.js]
 support-files =
   getCookies.html
   linkToGetCookies.html
   setSameSiteCookie.html
   setSameSiteCookie.html^headers^
-skip-if = fission
 [browser_readerMode_readingTime.js]
 support-files =
   readerModeArticle.html
   readerModeArticleShort.html
   readerModeArticleMedium.html
-skip-if = fission
--- a/toolkit/components/reader/test/browser_readerMode.js
+++ b/toolkit/components/reader/test/browser_readerMode.js
@@ -109,17 +109,19 @@ add_task(async function test_reader_butt
     );
   });
 
   info("Got correct URL when copying");
 
   // Switch page back out of reader mode.
   let promisePageShow = BrowserTestUtils.waitForContentEvent(
     tab.linkedBrowser,
-    "pageshow"
+    "pageshow",
+    false,
+    e => e.target.location.href != "about:blank"
   );
   readerButton.click();
   await promisePageShow;
   is(
     gBrowser.selectedBrowser.currentURI.spec,
     url,
     "Back to the original page after clicking active reader mode button"
   );
@@ -159,17 +161,19 @@ add_task(async function test_reader_butt
   is_element_visible(
     readerButton,
     "Reader mode button is present on about:reader even in error state"
   );
 
   // Switch page back out of reader mode.
   promisePageShow = BrowserTestUtils.waitForContentEvent(
     newTab.linkedBrowser,
-    "pageshow"
+    "pageshow",
+    false,
+    e => e.target.location.href != "about:blank"
   );
   readerButton.click();
   await promisePageShow;
   is(
     gBrowser.selectedBrowser.currentURI.spec,
     nonReadableUrl,
     "Back to the original non-reader-able page after clicking active reader mode button"
   );
@@ -222,19 +226,20 @@ add_task(async function test_reader_view
     }
   });
 
   function observeAttribute(element, attribute, triggerFn, checkFn) {
     return new Promise(resolve => {
       let observer = new MutationObserver(mutations => {
         mutations.forEach(mu => {
           if (element.getAttribute(attribute) !== mu.oldValue) {
-            checkFn();
-            resolve();
-            observer.disconnect();
+            if (checkFn()) {
+              resolve();
+              observer.disconnect();
+            }
           }
         });
       });
 
       observer.observe(element, {
         attributes: true,
         attributeOldValue: true,
         attributeFilter: [attribute],
@@ -248,137 +253,120 @@ add_task(async function test_reader_view
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
   is(
     menuitem.hidden,
     true,
     "menuitem element should have the hidden attribute"
   );
 
   info("Navigate a reader-able page");
-  let waitForPageshow = BrowserTestUtils.waitForContentEvent(
-    tab.linkedBrowser,
-    "pageshow"
-  );
+  function waitForNonBlankPage() {
+    return BrowserTestUtils.waitForContentEvent(
+      tab.linkedBrowser,
+      "pageshow",
+      false,
+      e => e.target.location.href != "about:blank"
+    );
+  }
+  let waitForPageshow = waitForNonBlankPage();
   await observeAttribute(
     menuitem,
     "hidden",
     () => {
       let url = TEST_PATH + "readerModeArticle.html";
       BrowserTestUtils.loadURI(tab.linkedBrowser, url);
     },
-    () => {
-      is(
-        menuitem.hidden,
-        false,
-        "menuitem's hidden attribute should be false on a reader-able page"
-      );
-    }
+    () => !menuitem.hidden
+  );
+  is(
+    menuitem.hidden,
+    false,
+    "menuitem's hidden attribute should be false on a reader-able page"
   );
   await waitForPageshow;
 
   info("Navigate a non-reader-able page");
-  waitForPageshow = BrowserTestUtils.waitForContentEvent(
-    tab.linkedBrowser,
-    "pageshow"
-  );
+  waitForPageshow = waitForNonBlankPage();
   await observeAttribute(
     menuitem,
     "hidden",
     () => {
       let url = TEST_PATH + "readerModeArticleHiddenNodes.html";
       BrowserTestUtils.loadURI(tab.linkedBrowser, url);
     },
-    () => {
-      is(
-        menuitem.hidden,
-        true,
-        "menuitem's hidden attribute should be true on a non-reader-able page"
-      );
-    }
+    () => menuitem.hidden
+  );
+  is(
+    menuitem.hidden,
+    true,
+    "menuitem's hidden attribute should be true on a non-reader-able page"
   );
   await waitForPageshow;
 
   info("Navigate a reader-able page");
-  waitForPageshow = BrowserTestUtils.waitForContentEvent(
-    tab.linkedBrowser,
-    "pageshow"
-  );
+  waitForPageshow = waitForNonBlankPage();
   await observeAttribute(
     menuitem,
     "hidden",
     () => {
       let url = TEST_PATH + "readerModeArticle.html";
       BrowserTestUtils.loadURI(tab.linkedBrowser, url);
     },
-    () => {
-      is(
-        menuitem.hidden,
-        false,
-        "menuitem's hidden attribute should be false on a reader-able page"
-      );
-    }
+    () => !menuitem.hidden
+  );
+  is(
+    menuitem.hidden,
+    false,
+    "menuitem's hidden attribute should be false on a reader-able page"
   );
   await waitForPageshow;
 
   info("Enter Reader Mode");
-  waitForPageshow = BrowserTestUtils.waitForContentEvent(
-    tab.linkedBrowser,
-    "pageshow"
-  );
+  waitForPageshow = waitForNonBlankPage();
   await observeAttribute(
     readerButton,
     "readeractive",
     () => {
       readerButton.click();
     },
-    () => {
-      is(
-        readerButton.getAttribute("readeractive"),
-        "true",
-        "readerButton's readeractive attribute should be true when entering reader mode"
-      );
-    }
+    () => readerButton.getAttribute("readeractive") == "true"
+  );
+  is(
+    readerButton.getAttribute("readeractive"),
+    "true",
+    "readerButton's readeractive attribute should be true when entering reader mode"
   );
   await waitForPageshow;
 
   info("Exit Reader Mode");
-  waitForPageshow = BrowserTestUtils.waitForContentEvent(
-    tab.linkedBrowser,
-    "pageshow"
-  );
+  waitForPageshow = waitForNonBlankPage();
   await observeAttribute(
     readerButton,
     "readeractive",
     () => {
       readerButton.click();
     },
-    () => {
-      is(
-        readerButton.getAttribute("readeractive"),
-        "",
-        "readerButton's readeractive attribute should be empty when reader mode is exited"
-      );
-    }
+    () => !readerButton.getAttribute("readeractive")
+  );
+  ok(
+    !readerButton.getAttribute("readeractive"),
+    "readerButton's readeractive attribute should be empty when reader mode is exited"
   );
   await waitForPageshow;
 
   info("Navigate a non-reader-able page");
-  waitForPageshow = BrowserTestUtils.waitForContentEvent(
-    tab.linkedBrowser,
-    "pageshow"
-  );
+  waitForPageshow = waitForNonBlankPage();
   await observeAttribute(
     menuitem,
     "hidden",
     () => {
       let url = TEST_PATH + "readerModeArticleHiddenNodes.html";
       BrowserTestUtils.loadURI(tab.linkedBrowser, url);
     },
-    () => {
-      is(
-        menuitem.hidden,
-        true,
-        "menuitem's hidden attribute should be true on a non-reader-able page"
-      );
-    }
+    () => menuitem.hidden
+  );
+  is(
+    menuitem.hidden,
+    true,
+    "menuitem's hidden attribute should be true on a non-reader-able page"
   );
   await waitForPageshow;
 });
--- a/toolkit/components/reader/test/browser_readerMode_hidden_nodes.js
+++ b/toolkit/components/reader/test/browser_readerMode_hidden_nodes.js
@@ -33,27 +33,24 @@ add_task(async function test_reader_butt
 
   let tab = (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser));
   is_element_hidden(
     readerButton,
     "Reader mode button is not present on a new tab"
   );
   // Point tab to a test page that is not reader-able due to hidden nodes.
   let url = TEST_PATH + "readerModeArticleHiddenNodes.html";
-  let paintPromise = ContentTask.spawn(tab.linkedBrowser, "", function() {
-    return new Promise(resolve => {
-      addEventListener("DOMContentLoaded", function onDCL() {
-        removeEventListener("DOMContentLoaded", onDCL);
-        addEventListener("MozAfterPaint", function onPaint() {
-          removeEventListener("MozAfterPaint", onPaint);
-          resolve();
-        });
-      });
-    });
-  });
+  let paintPromise = BrowserTestUtils.waitForContentEvent(
+    tab.linkedBrowser,
+    "MozAfterPaint",
+    false,
+    e =>
+      e.originalTarget.location.href.endsWith("HiddenNodes.html") &&
+      e.originalTarget.document.readyState == "complete"
+  );
   BrowserTestUtils.loadURI(tab.linkedBrowser, url);
   await paintPromise;
 
   is_element_hidden(
     readerButton,
     "Reader mode button is still not present on tab with unreadable content."
   );
 });