This is an automated email from the ASF dual-hosted git repository.

duke8253 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 39dac9fd7b enforce SETTINGS frame rules (#9864)
39dac9fd7b is described below

commit 39dac9fd7b19d0f0d431c33690cc0c604fa1b0b5
Author: Fei Deng <[email protected]>
AuthorDate: Wed Jun 21 10:38:11 2023 -0400

    enforce SETTINGS frame rules (#9864)
---
 proxy/http3/Http3App.cc                            |   8 +-
 proxy/http3/Http3App.h                             |   4 +-
 proxy/http3/Http3FrameDispatcher.cc                |   6 +-
 proxy/http3/Http3FrameDispatcher.h                 |   2 +-
 proxy/http3/Http3FrameHandler.h                    |   5 +-
 proxy/http3/Http3HeaderVIOAdaptor.cc               |   2 +-
 proxy/http3/Http3HeaderVIOAdaptor.h                |   3 +-
 proxy/http3/Http3ProtocolEnforcer.cc               |  51 ++++++++++
 .../http3/{test/Mock.h => Http3ProtocolEnforcer.h} |  23 ++---
 proxy/http3/Http3StreamDataVIOAdaptor.cc           |   3 +-
 proxy/http3/Http3StreamDataVIOAdaptor.h            |   3 +-
 proxy/http3/Http3Transaction.cc                    |   3 +-
 proxy/http3/Http3Types.h                           |   2 +-
 proxy/http3/Makefile.am                            |   5 +
 proxy/http3/test/Mock.h                            |   4 +-
 proxy/http3/test/test_Http3FrameDispatcher.cc      | 104 ++++++++++++++++++++-
 16 files changed, 192 insertions(+), 36 deletions(-)

diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc
index 99c812b7fd..91cb43a5d9 100644
--- a/proxy/http3/Http3App.cc
+++ b/proxy/http3/Http3App.cc
@@ -37,6 +37,7 @@
 #include "Http3DebugNames.h"
 #include "Http3Session.h"
 #include "Http3Transaction.h"
+#include "Http3ProtocolEnforcer.h"
 
 static constexpr char debug_tag[]   = "http3";
 static constexpr char debug_tag_v[] = "v_http3";
@@ -51,6 +52,9 @@ Http3App::Http3App(QUICNetVConnection *client_vc, 
IpAllow::ACL &&session_acl, co
 
   this->_qc->stream_manager()->set_default_application(this);
 
+  this->_protocol_enforcer = new Http3ProtocolEnforcer();
+  this->_control_stream_dispatcher.add_handler(this->_protocol_enforcer);
+
   this->_settings_handler = new Http3SettingsHandler(this->_ssn);
   this->_control_stream_dispatcher.add_handler(this->_settings_handler);
 
@@ -212,7 +216,7 @@ Http3App::_handle_uni_stream_on_read_ready(int /* event */, 
VIO *vio)
   case Http3StreamType::CONTROL:
   case Http3StreamType::PUSH: {
     uint64_t nread = 0;
-    this->_control_stream_dispatcher.on_read_ready(adapter->stream().id(), 
*vio->get_reader(), nread);
+    this->_control_stream_dispatcher.on_read_ready(adapter->stream().id(), 
type, *vio->get_reader(), nread);
     // TODO: when PUSH comes from client, send stream error with 
HTTP_WRONG_STREAM_DIRECTION
     break;
   }
@@ -365,7 +369,7 @@ Http3SettingsHandler::interests()
 }
 
 Http3ErrorUPtr
-Http3SettingsHandler::handle_frame(std::shared_ptr<const Http3Frame> frame)
+Http3SettingsHandler::handle_frame(std::shared_ptr<const Http3Frame> frame, 
int32_t /* frame_seq */, Http3StreamType /* s_type */)
 {
   ink_assert(frame->type() == Http3FrameType::SETTINGS);
 
diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h
index 6cc8bee49f..4ae5a7f27d 100644
--- a/proxy/http3/Http3App.h
+++ b/proxy/http3/Http3App.h
@@ -77,6 +77,7 @@ private:
 
   void _set_qpack_stream(Http3StreamType type, QUICStreamVCAdapter *adapter);
 
+  Http3FrameHandler *_protocol_enforcer = nullptr;
   Http3FrameHandler *_settings_handler  = nullptr;
   Http3FrameGenerator *_settings_framer = nullptr;
 
@@ -96,7 +97,8 @@ public:
 
   // Http3FrameHandler
   std::vector<Http3FrameType> interests() override;
-  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) 
override;
+  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame, int32_t 
frame_seq = -1,
+                              Http3StreamType s_type = 
Http3StreamType::UNKNOWN) override;
 
 private:
   // TODO: clarify Http3Session I/F for Http3SettingsHandler and Http3App
diff --git a/proxy/http3/Http3FrameDispatcher.cc 
b/proxy/http3/Http3FrameDispatcher.cc
index 5a578c2eac..039bc60174 100644
--- a/proxy/http3/Http3FrameDispatcher.cc
+++ b/proxy/http3/Http3FrameDispatcher.cc
@@ -41,11 +41,12 @@ Http3FrameDispatcher::add_handler(Http3FrameHandler 
*handler)
 }
 
 Http3ErrorUPtr
-Http3FrameDispatcher::on_read_ready(QUICStreamId stream_id, IOBufferReader 
&reader, uint64_t &nread)
+Http3FrameDispatcher::on_read_ready(QUICStreamId stream_id, Http3StreamType 
stream_type, IOBufferReader &reader, uint64_t &nread)
 {
   std::shared_ptr<const Http3Frame> frame(nullptr);
   Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError());
   nread                = 0;
+  uint32_t frame_count = 0;
 
   while (true) {
     // Read a length of Type field and hopefully a length of Length field too
@@ -95,6 +96,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamId stream_id, 
IOBufferReader &read
       if (frame == nullptr) {
         break;
       }
+      ++frame_count;
 
       // Consume buffer if frame is created
       nread += frame_len;
@@ -105,7 +107,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamId stream_id, 
IOBufferReader &read
       Debug("http3", "[RX] [%" PRIu64 "] | %s size=%zu", stream_id, 
Http3DebugNames::frame_type(type), frame_len);
       std::vector<Http3FrameHandler *> handlers = 
this->_handlers[static_cast<uint8_t>(type)];
       for (auto h : handlers) {
-        error = h->handle_frame(frame);
+        error = h->handle_frame(frame, frame_count - 1, stream_type);
         if (error->cls != Http3ErrorClass::NONE) {
           return error;
         }
diff --git a/proxy/http3/Http3FrameDispatcher.h 
b/proxy/http3/Http3FrameDispatcher.h
index 315a5b0b6e..d3f2118adb 100644
--- a/proxy/http3/Http3FrameDispatcher.h
+++ b/proxy/http3/Http3FrameDispatcher.h
@@ -33,7 +33,7 @@ class QUICStreamVCAdapter;
 class Http3FrameDispatcher
 {
 public:
-  Http3ErrorUPtr on_read_ready(QUICStreamId stream_id, IOBufferReader &reader, 
uint64_t &nread);
+  Http3ErrorUPtr on_read_ready(QUICStreamId stream_id, Http3StreamType 
stream_type, IOBufferReader &reader, uint64_t &nread);
 
   void add_handler(Http3FrameHandler *handler);
 
diff --git a/proxy/http3/Http3FrameHandler.h b/proxy/http3/Http3FrameHandler.h
index e3c1f97bf1..79b1bd5fa9 100644
--- a/proxy/http3/Http3FrameHandler.h
+++ b/proxy/http3/Http3FrameHandler.h
@@ -31,6 +31,7 @@ class Http3FrameHandler
 {
 public:
   virtual ~Http3FrameHandler(){};
-  virtual std::vector<Http3FrameType> interests()                              
= 0;
-  virtual Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) 
= 0;
+  virtual std::vector<Http3FrameType> interests()                              
          = 0;
+  virtual Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame, 
int32_t frame_seq = -1,
+                                      Http3StreamType s_type = 
Http3StreamType::UNKNOWN) = 0;
 };
diff --git a/proxy/http3/Http3HeaderVIOAdaptor.cc 
b/proxy/http3/Http3HeaderVIOAdaptor.cc
index 47aea205a6..4d449af0b3 100644
--- a/proxy/http3/Http3HeaderVIOAdaptor.cc
+++ b/proxy/http3/Http3HeaderVIOAdaptor.cc
@@ -46,7 +46,7 @@ Http3HeaderVIOAdaptor::interests()
 }
 
 Http3ErrorUPtr
-Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr<const Http3Frame> frame)
+Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr<const Http3Frame> frame, 
int32_t /* frame_seq */, Http3StreamType /* s_type */)
 {
   ink_assert(frame->type() == Http3FrameType::HEADERS);
   const Http3HeadersFrame *hframe = dynamic_cast<const Http3HeadersFrame 
*>(frame.get());
diff --git a/proxy/http3/Http3HeaderVIOAdaptor.h 
b/proxy/http3/Http3HeaderVIOAdaptor.h
index 3419811802..f3a4de481d 100644
--- a/proxy/http3/Http3HeaderVIOAdaptor.h
+++ b/proxy/http3/Http3HeaderVIOAdaptor.h
@@ -35,7 +35,8 @@ public:
 
   // Http3FrameHandler
   std::vector<Http3FrameType> interests() override;
-  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) 
override;
+  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame, int32_t 
frame_seq = -1,
+                              Http3StreamType s_type = 
Http3StreamType::UNKNOWN) override;
 
   bool is_complete();
   int event_handler(int event, Event *data);
diff --git a/proxy/http3/Http3ProtocolEnforcer.cc 
b/proxy/http3/Http3ProtocolEnforcer.cc
new file mode 100644
index 0000000000..cd19fbdaa9
--- /dev/null
+++ b/proxy/http3/Http3ProtocolEnforcer.cc
@@ -0,0 +1,51 @@
+/** @file
+ *
+ *  A brief file description
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "Http3ProtocolEnforcer.h"
+
+std::vector<Http3FrameType>
+Http3ProtocolEnforcer::interests()
+{
+  return {Http3FrameType::DATA,          Http3FrameType::HEADERS,     
Http3FrameType::PRIORITY,
+          Http3FrameType::CANCEL_PUSH,   Http3FrameType::SETTINGS,    
Http3FrameType::PUSH_PROMISE,
+          Http3FrameType::X_RESERVED_1,  Http3FrameType::GOAWAY,      
Http3FrameType::X_RESERVED_2,
+          Http3FrameType::X_RESERVED_3,  Http3FrameType::MAX_PUSH_ID, 
Http3FrameType::DUPLICATE_PUSH_ID,
+          Http3FrameType::X_MAX_DEFINED, Http3FrameType::UNKNOWN};
+}
+
+Http3ErrorUPtr
+Http3ProtocolEnforcer::handle_frame(std::shared_ptr<const Http3Frame> frame, 
int32_t frame_seq, Http3StreamType s_type)
+{
+  Http3ErrorUPtr error  = Http3ErrorUPtr(new Http3NoError());
+  Http3FrameType f_type = frame->type();
+  if (s_type == Http3StreamType::CONTROL) {
+    if (frame_seq == 0 && f_type != Http3FrameType::SETTINGS) {
+      error = 
std::make_unique<Http3ConnectionError>(Http3ErrorCode::H3_MISSING_SETTINGS,
+                                                     "first frame of the 
control stream must be SETTINGS frame");
+    } else if (frame_seq != 0 && f_type == Http3FrameType::SETTINGS) {
+      error = 
std::make_unique<Http3ConnectionError>(Http3ErrorCode::H3_FRAME_UNEXPECTED,
+                                                     "only one SETTINGS frame 
is allowed per the control stream");
+    }
+  }
+  return error;
+}
diff --git a/proxy/http3/test/Mock.h b/proxy/http3/Http3ProtocolEnforcer.h
similarity index 71%
copy from proxy/http3/test/Mock.h
copy to proxy/http3/Http3ProtocolEnforcer.h
index 2b02ed014c..a62d239c2f 100644
--- a/proxy/http3/test/Mock.h
+++ b/proxy/http3/Http3ProtocolEnforcer.h
@@ -21,27 +21,18 @@
  *  limitations under the License.
  */
 
-#include "catch.hpp"
+#pragma once
 
+#include "Http3Types.h"
 #include "Http3FrameHandler.h"
 
-class Http3MockFrameHandler : public Http3FrameHandler
+class Http3ProtocolEnforcer : public Http3FrameHandler
 {
 public:
-  int total_frame_received = 0;
+  Http3ProtocolEnforcer(){};
 
   // Http3FrameHandler
-
-  std::vector<Http3FrameType>
-  interests() override
-  {
-    return {Http3FrameType::DATA};
-  }
-
-  Http3ErrorUPtr
-  handle_frame(std::shared_ptr<const Http3Frame> frame) override
-  {
-    this->total_frame_received++;
-    return Http3ErrorUPtr(new Http3NoError());
-  }
+  std::vector<Http3FrameType> interests() override;
+  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame, int32_t 
frame_seq = -1,
+                              Http3StreamType s_type = 
Http3StreamType::UNKNOWN) override;
 };
diff --git a/proxy/http3/Http3StreamDataVIOAdaptor.cc 
b/proxy/http3/Http3StreamDataVIOAdaptor.cc
index cb154d8ab8..a711a629df 100644
--- a/proxy/http3/Http3StreamDataVIOAdaptor.cc
+++ b/proxy/http3/Http3StreamDataVIOAdaptor.cc
@@ -38,7 +38,8 @@ Http3StreamDataVIOAdaptor::interests()
 }
 
 Http3ErrorUPtr
-Http3StreamDataVIOAdaptor::handle_frame(std::shared_ptr<const Http3Frame> 
frame)
+Http3StreamDataVIOAdaptor::handle_frame(std::shared_ptr<const Http3Frame> 
frame, int32_t /* frame_seq */,
+                                        Http3StreamType /* s_type */)
 {
   ink_assert(frame->type() == Http3FrameType::DATA);
   const Http3DataFrame *dframe = dynamic_cast<const Http3DataFrame 
*>(frame.get());
diff --git a/proxy/http3/Http3StreamDataVIOAdaptor.h 
b/proxy/http3/Http3StreamDataVIOAdaptor.h
index 5114979cd3..c14218b83c 100644
--- a/proxy/http3/Http3StreamDataVIOAdaptor.h
+++ b/proxy/http3/Http3StreamDataVIOAdaptor.h
@@ -35,7 +35,8 @@ public:
 
   // Http3FrameHandler
   std::vector<Http3FrameType> interests() override;
-  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) 
override;
+  Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame, int32_t 
frame_seq = -1,
+                              Http3StreamType s_type = 
Http3StreamType::UNKNOWN) override;
 
   // Http3StreamDataVIOAdaptor
   void finalize();
diff --git a/proxy/http3/Http3Transaction.cc b/proxy/http3/Http3Transaction.cc
index 841ace6600..789936c856 100644
--- a/proxy/http3/Http3Transaction.cc
+++ b/proxy/http3/Http3Transaction.cc
@@ -563,7 +563,8 @@ Http3Transaction::_process_read_vio()
   SCOPED_MUTEX_LOCK(lock, this->_info.read_vio->mutex, this_ethread());
 
   uint64_t nread = 0;
-  this->_frame_dispatcher.on_read_ready(this->_info.adapter.stream().id(), 
*this->_info.read_vio->get_reader(), nread);
+  this->_frame_dispatcher.on_read_ready(this->_info.adapter.stream().id(), 
Http3StreamType::UNKNOWN,
+                                        *this->_info.read_vio->get_reader(), 
nread);
   this->_info.read_vio->ndone += nread;
   return nread;
 }
diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h
index 6fb846b6d1..2336959ea0 100644
--- a/proxy/http3/Http3Types.h
+++ b/proxy/http3/Http3Types.h
@@ -108,7 +108,7 @@ public:
   const char *msg = nullptr;
 
 protected:
-  Http3Error(){};
+  Http3Error() : app_error_code(Http3ErrorCode::H3_NO_ERROR){};
   Http3Error(const Http3ErrorCode error_code, const char *error_msg = nullptr)
     : cls(Http3ErrorClass::APPLICATION), app_error_code(error_code), 
msg(error_msg){};
 };
diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am
index 41781dbcf3..5f60f70abb 100644
--- a/proxy/http3/Makefile.am
+++ b/proxy/http3/Makefile.am
@@ -52,6 +52,7 @@ libhttp3_a_SOURCES = \
   Http3DataFramer.cc \
   Http3HeaderVIOAdaptor.cc \
   Http3StreamDataVIOAdaptor.cc \
+  Http3ProtocolEnforcer.cc \
   QPACK.cc
 
 #
@@ -86,6 +87,10 @@ test_libhttp3_LDADD = $(test_LDADD)
 test_libhttp3_SOURCES = \
   ./test/main.cc \
   ./test/test_Http3Frame.cc \
+  ./test/test_Http3FrameDispatcher.cc \
+  ./Http3ProtocolEnforcer.cc \
+  ./Http3FrameDispatcher.cc \
+  ./Http3DebugNames.cc \
   ./Http3Config.cc \
   ./Http3Frame.cc
 
diff --git a/proxy/http3/test/Mock.h b/proxy/http3/test/Mock.h
index 2b02ed014c..f3b923d09e 100644
--- a/proxy/http3/test/Mock.h
+++ b/proxy/http3/test/Mock.h
@@ -35,11 +35,11 @@ public:
   std::vector<Http3FrameType>
   interests() override
   {
-    return {Http3FrameType::DATA};
+    return {Http3FrameType::DATA, Http3FrameType::SETTINGS};
   }
 
   Http3ErrorUPtr
-  handle_frame(std::shared_ptr<const Http3Frame> frame) override
+  handle_frame(std::shared_ptr<const Http3Frame> frame, int32_t /* frame_seq 
*/, Http3StreamType /* s_type */) override
   {
     this->total_frame_received++;
     return Http3ErrorUPtr(new Http3NoError());
diff --git a/proxy/http3/test/test_Http3FrameDispatcher.cc 
b/proxy/http3/test/test_Http3FrameDispatcher.cc
index 3e8a1ae496..dd796cd9ad 100644
--- a/proxy/http3/test/test_Http3FrameDispatcher.cc
+++ b/proxy/http3/test/test_Http3FrameDispatcher.cc
@@ -24,27 +24,123 @@
 #include "catch.hpp"
 
 #include "Http3FrameDispatcher.h"
+#include "Http3ProtocolEnforcer.h"
 #include "Mock.h"
 
 TEST_CASE("Http3FrameHandler dispatch", "[http3]")
 {
   uint8_t input[] = {// 1st frame (HEADERS)
-                     0x02, 0x01, 0x00, 0x01, 0x23,
+                     0x01, 0x04, 0x11, 0x22, 0x33, 0x44,
                      // 2nd frame (DATA)
-                     0x04, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44,
+                     0x00, 0x04, 0xaa, 0xbb, 0xcc, 0xdd,
                      // 3rd frame (incomplete)
                      0xff};
 
   Http3FrameDispatcher http3FrameDispatcher;
   Http3MockFrameHandler handler;
   http3FrameDispatcher.add_handler(&handler);
-  uint16_t nread = 0;
+
+  MIOBuffer *buf         = new_MIOBuffer(BUFFER_SIZE_INDEX_512);
+  IOBufferReader *reader = buf->alloc_reader();
+  uint64_t nread         = 0;
+  Http3ErrorUPtr error   = Http3ErrorUPtr(new Http3NoError());
+
+  buf->write(input, sizeof(input));
 
   // Initial state
   CHECK(handler.total_frame_received == 0);
   CHECK(nread == 0);
 
-  http3FrameDispatcher.on_read_ready(input, sizeof(input), nread);
+  error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::UNKNOWN, 
*reader, nread);
+  CHECK(error->app_error_code == Http3ErrorCode::H3_NO_ERROR);
   CHECK(handler.total_frame_received == 1);
   CHECK(nread == 12);
 }
+
+TEST_CASE("dispatch SETTINGS frame", "[http3]")
+{
+  SECTION("Only one SETTINGS frame is allowed per the control stream")
+  {
+    uint8_t input[] = {
+      0x04,       // Type
+      0x08,       // Length
+      0x06,       // Identifier
+      0x44, 0x00, // Value
+      0x09,       // Identifier
+      0x0f,       // Value
+      0x4a, 0x0a, // Identifier
+      0x00,       // Value
+      0x04,       // Type
+      0x08,       // Length
+      0x06,       // Identifier
+      0x44, 0x00, // Value
+      0x09,       // Identifier
+      0x0f,       // Value
+      0x4a, 0x0a, // Identifier
+      0x00,       // Value
+    };
+
+    Http3FrameDispatcher http3FrameDispatcher;
+    Http3ProtocolEnforcer enforcer;
+    Http3MockFrameHandler handler;
+
+    http3FrameDispatcher.add_handler(&enforcer);
+    http3FrameDispatcher.add_handler(&handler);
+
+    MIOBuffer *buf         = new_MIOBuffer(BUFFER_SIZE_INDEX_512);
+    IOBufferReader *reader = buf->alloc_reader();
+    uint64_t nread         = 0;
+    Http3ErrorUPtr error   = Http3ErrorUPtr(new Http3NoError());
+
+    buf->write(input, sizeof(input));
+
+    // Initial state
+    CHECK(handler.total_frame_received == 0);
+    CHECK(nread == 0);
+
+    error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::CONTROL, 
*reader, nread);
+    CHECK(error->app_error_code == Http3ErrorCode::H3_FRAME_UNEXPECTED);
+    CHECK(handler.total_frame_received == 1);
+    CHECK(nread == sizeof(input));
+  }
+
+  SECTION("first frame of the control stream must be SETTINGS frame")
+  {
+    uint8_t input[] = {
+      0x0d,       // Type
+      0x01,       // Length
+      0x01,       // Push ID
+      0x04,       // Type
+      0x08,       // Length
+      0x06,       // Identifier
+      0x44, 0x00, // Value
+      0x09,       // Identifier
+      0x0f,       // Value
+      0x4a, 0x0a, // Identifier
+      0x00,       // Value
+    };
+
+    Http3FrameDispatcher http3FrameDispatcher;
+    Http3ProtocolEnforcer enforcer;
+    Http3MockFrameHandler handler;
+
+    http3FrameDispatcher.add_handler(&enforcer);
+    http3FrameDispatcher.add_handler(&handler);
+
+    MIOBuffer *buf         = new_MIOBuffer(BUFFER_SIZE_INDEX_512);
+    IOBufferReader *reader = buf->alloc_reader();
+    uint64_t nread         = 0;
+    Http3ErrorUPtr error   = Http3ErrorUPtr(new Http3NoError());
+
+    buf->write(input, sizeof(input));
+
+    // Initial state
+    CHECK(handler.total_frame_received == 0);
+    CHECK(nread == 0);
+
+    error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::CONTROL, 
*reader, nread);
+    CHECK(error->app_error_code == Http3ErrorCode::H3_MISSING_SETTINGS);
+    CHECK(handler.total_frame_received == 0);
+    CHECK(nread == 3);
+  }
+}

Reply via email to