You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2019/02/05 05:16:00 UTC

[trafficserver] branch quic-latest updated: Check decoded header list size on QPACK

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

masaori pushed a commit to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/quic-latest by this push:
     new 90e1bca  Check decoded header list size on QPACK
90e1bca is described below

commit 90e1bca570574ef1d2179b8669e5fe90ce29a777
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Tue Feb 5 14:13:47 2019 +0900

    Check decoded header list size on QPACK
---
 proxy/http3/Http3.cc              |  6 ++++
 proxy/http3/Http3.h               |  5 +++
 proxy/http3/Http3App.cc           | 31 +++++++++++++------
 proxy/http3/Http3App.h            |  6 +++-
 proxy/http3/Http3ClientSession.cc |  4 +--
 proxy/http3/QPACK.cc              | 65 ++++++++++++++++++++++++++++++---------
 proxy/http3/QPACK.h               | 29 ++++++++++-------
 7 files changed, 109 insertions(+), 37 deletions(-)

diff --git a/proxy/http3/Http3.cc b/proxy/http3/Http3.cc
index 74f811b..ce88558 100644
--- a/proxy/http3/Http3.cc
+++ b/proxy/http3/Http3.cc
@@ -23,6 +23,12 @@
 
 #include "Http3.h"
 
+// Default values of settings defined by specs (draft-17)
+const uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE     = 0;
+const uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE  = UINT32_MAX;
+const uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS = 0;
+const uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS      = 0;
+
 RecRawStatBlock *http3_rsb;
 
 void
diff --git a/proxy/http3/Http3.h b/proxy/http3/Http3.h
index b3da732..f390e06 100644
--- a/proxy/http3/Http3.h
+++ b/proxy/http3/Http3.h
@@ -27,6 +27,11 @@
 #include "records/I_RecDefs.h"
 #include "records/I_RecProcess.h"
 
+extern const uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE;
+extern const uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE;
+extern const uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS;
+extern const uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS;
+
 extern RecRawStatBlock *http3_rsb; // Container for statistics.
 
 class Http3
diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc
index 7369908..e4bde93 100644
--- a/proxy/http3/Http3App.cc
+++ b/proxy/http3/Http3App.cc
@@ -34,12 +34,6 @@
 static constexpr char tag[]   = "http3";
 static constexpr char tag_v[] = "v_http3";
 
-// Default values of settings defined by specs.
-static constexpr uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE     = 0;
-static constexpr uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE  = UINT32_MAX;
-static constexpr uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS = 0;
-static constexpr uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS      = 0;
-
 Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc)
 {
   this->_client_session      = new Http3ClientSession(client_vc);
@@ -48,7 +42,7 @@ Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QU
 
   this->_qc->stream_manager()->set_default_application(this);
 
-  this->_settings_handler = new Http3SettingsHandler();
+  this->_settings_handler = new Http3SettingsHandler(this->_client_session);
   this->_control_stream_dispatcher.add_handler(this->_settings_handler);
 
   this->_settings_framer = new Http3SettingsFramer();
@@ -294,13 +288,32 @@ Http3SettingsHandler::handle_frame(std::shared_ptr<const Http3Frame> frame)
     return Http3ErrorUPtr(new Http3NoError());
   }
 
+  // TODO: Add length check: the maximum number of values are 2^62 - 1, but some fields have shorter maximum than it.
+  if (settings_frame->contains(Http3SettingsId::HEADER_TABLE_SIZE)) {
+    uint64_t header_table_size = settings_frame->get(Http3SettingsId::HEADER_TABLE_SIZE);
+    this->_session->remote_qpack()->update_max_table_size(header_table_size);
+
+    Debug("http3", "SETTINGS_HEADER_TABLE_SIZE: %" PRId64, header_table_size);
+  }
+
   if (settings_frame->contains(Http3SettingsId::MAX_HEADER_LIST_SIZE)) {
-    uint64_t header_list_size = settings_frame->get(Http3SettingsId::MAX_HEADER_LIST_SIZE);
-    Debug("http3", "SETTINGS_MAX_HEADER_LIST_SIZE: %" PRId64, header_list_size);
+    uint64_t max_header_list_size = settings_frame->get(Http3SettingsId::MAX_HEADER_LIST_SIZE);
+    this->_session->remote_qpack()->update_max_header_list_size(max_header_list_size);
+
+    Debug("http3", "SETTINGS_MAX_HEADER_LIST_SIZE: %" PRId64, max_header_list_size);
+  }
+
+  if (settings_frame->contains(Http3SettingsId::QPACK_BLOCKED_STREAMS)) {
+    uint64_t qpack_blocked_streams = settings_frame->get(Http3SettingsId::QPACK_BLOCKED_STREAMS);
+    this->_session->remote_qpack()->update_max_blocking_streams(qpack_blocked_streams);
+
+    Debug("http3", "SETTINGS_QPACK_BLOCKED_STREAMS: %" PRId64, qpack_blocked_streams);
   }
 
   if (settings_frame->contains(Http3SettingsId::NUM_PLACEHOLDERS)) {
     uint64_t num_placeholders = settings_frame->get(Http3SettingsId::NUM_PLACEHOLDERS);
+    // TODO: update settings for priority tree
+
     Debug("http3", "SETTINGS_NUM_PLACEHOLDERS: %" PRId64, num_placeholders);
   }
 
diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h
index 49e0e07..959ad2e 100644
--- a/proxy/http3/Http3App.h
+++ b/proxy/http3/Http3App.h
@@ -77,11 +77,15 @@ private:
 class Http3SettingsHandler : public Http3FrameHandler
 {
 public:
-  Http3SettingsHandler(){};
+  Http3SettingsHandler(Http3ClientSession *session) : _session(session){};
 
   // Http3FrameHandler
   std::vector<Http3FrameType> interests() override;
   Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) override;
+
+private:
+  // TODO: clarify Http3ClientSession I/F for Http3SettingsHandler and Http3App
+  Http3ClientSession *_session = nullptr;
 };
 
 class Http3SettingsFramer : public Http3FrameGenerator
diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc
index c5c04b2..0b8e294 100644
--- a/proxy/http3/Http3ClientSession.cc
+++ b/proxy/http3/Http3ClientSession.cc
@@ -25,8 +25,8 @@
 
 Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc)
 {
-  this->_local_qpack  = new QPACK(static_cast<QUICNetVConnection *>(vc), 0, 0);
-  this->_remote_qpack = new QPACK(static_cast<QUICNetVConnection *>(vc), 0, 0);
+  this->_local_qpack  = new QPACK(static_cast<QUICNetVConnection *>(vc));
+  this->_remote_qpack = new QPACK(static_cast<QUICNetVConnection *>(vc));
 }
 
 Http3ClientSession::~Http3ClientSession()
diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc
index 8193dcb..bd8f51d 100644
--- a/proxy/http3/QPACK.cc
+++ b/proxy/http3/QPACK.cc
@@ -132,9 +132,10 @@ const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = {
   {"x-frame-options", "deny"},
   {"x-frame-options", "sameorigin"}};
 
-QPACK::QPACK(QUICConnection *qc, uint16_t max_table_size, uint16_t max_blocking_streams)
+QPACK::QPACK(QUICConnection *qc, uint32_t max_header_list_size, uint16_t max_table_size, uint16_t max_blocking_streams)
   : QUICApplication(qc),
     _dynamic_table(max_table_size),
+    _max_header_list_size(max_header_list_size),
     _max_table_size(max_table_size),
     _max_blocking_streams(max_blocking_streams)
 {
@@ -267,6 +268,24 @@ QPACK::set_decoder_stream(QUICStreamIO *stream_io)
   this->set_stream(stream_io);
 }
 
+void
+QPACK::update_max_header_list_size(uint32_t max_header_list_size)
+{
+  this->_max_header_list_size = max_header_list_size;
+}
+
+void
+QPACK::update_max_table_size(uint16_t max_table_size)
+{
+  this->_max_table_size = max_table_size;
+}
+
+void
+QPACK::update_max_blocking_streams(uint16_t max_blocking_streams)
+{
+  this->_max_blocking_streams = max_blocking_streams;
+}
+
 int
 QPACK::_encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferBlock *prefix)
 {
@@ -615,7 +634,7 @@ QPACK::_encode_literal_header_field_with_postbase_name_ref(uint16_t index, uint1
 }
 
 int
-QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr)
+QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len)
 {
   // Read index field
   int len = 0;
@@ -644,9 +663,8 @@ QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size
   }
 
   // Create and attach a header
-  MIMEField *new_field = hdr.field_create(name, name_len);
-  new_field->value_set(hdr.m_heap, hdr.m_mime, value, value_len);
-  hdr.field_attach(new_field);
+  this->_attach_header(hdr, name, name_len, value, value_len, false);
+  header_len = name_len + value_len;
 
   QPACKDebug("Decoded Indexed Header Field: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len,
              name, value_len, value);
@@ -655,7 +673,8 @@ QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size
 }
 
 int
-QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr)
+QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr,
+                                                  uint32_t &header_len)
 {
   int read_len = 0;
 
@@ -701,6 +720,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint
 
   // Create and attach a header
   this->_attach_header(hdr, name, name_len, value, value_len, never_index);
+  header_len = name_len + value_len;
 
   QPACKDebug("Decoded Literal Header Field With Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index,
              result.index, name_len, name, static_cast<int>(value_len), value);
@@ -709,7 +729,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint
 }
 
 int
-QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr)
+QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len)
 {
   int read_len = 0;
 
@@ -738,6 +758,7 @@ QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t
 
   // Create and attach a header
   this->_attach_header(hdr, name, name_len, value, value_len, never_index);
+  header_len = name_len + value_len;
 
   QPACKDebug("Decoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s", static_cast<uint16_t>(name_len), name,
              static_cast<uint16_t>(value_len), value);
@@ -746,7 +767,8 @@ QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t
 }
 
 int
-QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr)
+QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr,
+                                                        uint32_t &header_len)
 {
   // Read index field
   int len = 0;
@@ -772,6 +794,7 @@ QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, cons
 
   // Create and attach a header
   this->_attach_header(hdr, name, name_len, value, value_len, false);
+  header_len = name_len + value_len;
 
   QPACKDebug("Decoded Indexed Header Field With Postbase Index: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index,
              result.index, name_len, name, value_len, value);
@@ -780,7 +803,8 @@ QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, cons
 }
 
 int
-QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr)
+QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr,
+                                                           uint32_t &header_len)
 {
   int read_len = 0;
 
@@ -822,6 +846,7 @@ QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, c
 
   // Create and attach a header
   this->_attach_header(hdr, name, name_len, value, value_len, never_index);
+  header_len = name_len + value_len;
 
   QPACKDebug("Decoded Literal Header Field With Postbase Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index,
              static_cast<uint16_t>(index), name_len, name, static_cast<int>(value_len), value);
@@ -859,22 +884,34 @@ QPACK::_decode_header(const uint8_t *header_block, size_t header_block_len, HTTP
   }
   pos += ret;
 
+  uint32_t decoded_header_list_size = 0;
+
   // Decode Instructions
   while (pos < header_block + header_block_len) {
+    uint32_t header_len = 0;
+
     if (pos[0] & 0x80) { // Index Header Field
-      ret = this->_decode_indexed_header_field(base_index, pos, remain_len, hdr);
+      ret = this->_decode_indexed_header_field(base_index, pos, remain_len, hdr, header_len);
     } else if (pos[0] & 0x40) { // Literal Header Field With Name Reference
-      ret = this->_decode_literal_header_field_with_name_ref(base_index, pos, remain_len, hdr);
+      ret = this->_decode_literal_header_field_with_name_ref(base_index, pos, remain_len, hdr, header_len);
     } else if (pos[0] & 0x20) { // Literal Header Field Without Name Reference
-      ret = this->_decode_literal_header_field_without_name_ref(pos, remain_len, hdr);
+      ret = this->_decode_literal_header_field_without_name_ref(pos, remain_len, hdr, header_len);
     } else if (pos[0] & 0x10) { // Indexed Header Field With Post-Base Index
-      ret = this->_decode_indexed_header_field_with_postbase_index(base_index, pos, remain_len, hdr);
+      ret = this->_decode_indexed_header_field_with_postbase_index(base_index, pos, remain_len, hdr, header_len);
     } else { // Literal Header Field With Post-Base Name Reference
-      ret = this->_decode_literal_header_field_with_postbase_name_ref(base_index, pos, remain_len, hdr);
+      ret = this->_decode_literal_header_field_with_postbase_name_ref(base_index, pos, remain_len, hdr, header_len);
     }
+
     if (ret < 0) {
       break;
     }
+
+    decoded_header_list_size += header_len;
+    if (decoded_header_list_size > this->_max_header_list_size) {
+      ret = -2;
+      break;
+    }
+
     pos += ret;
   }
 
diff --git a/proxy/http3/QPACK.h b/proxy/http3/QPACK.h
index 68c67ac..54c3c2b 100644
--- a/proxy/http3/QPACK.h
+++ b/proxy/http3/QPACK.h
@@ -29,6 +29,8 @@
 #include "MIME.h"
 #include "QUICApplication.h"
 
+#include "Http3.h"
+
 class HTTPHdr;
 
 enum {
@@ -36,15 +38,12 @@ enum {
   QPACK_EVENT_DECODE_FAILED,
 };
 
-// FIXME This setting should be passed by HTTP/3
-constexpr int SETTINGS_HEADER_TABLE_SIZE     = 0;
-constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 0;
-
 class QPACK : public QUICApplication
 {
 public:
-  QPACK(QUICConnection *qc, uint16_t max_table_size = SETTINGS_HEADER_TABLE_SIZE,
-        uint16_t max_blocking_streams = SETTINGS_QPACK_BLOCKED_STREAMS);
+  QPACK(QUICConnection *qc, uint32_t max_header_list_size = HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE,
+        uint16_t max_table_size       = HTTP3_DEFAULT_HEADER_TABLE_SIZE,
+        uint16_t max_blocking_streams = HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS);
   virtual ~QPACK();
 
   int event_handler(int event, Event *data);
@@ -68,6 +67,10 @@ public:
   void set_encoder_stream(QUICStreamIO *stream_io);
   void set_decoder_stream(QUICStreamIO *stream_io);
 
+  void update_max_header_list_size(uint32_t max_header_list_size);
+  void update_max_table_size(uint16_t max_table_size);
+  void update_max_blocking_streams(uint16_t max_blocking_streams);
+
   static size_t estimate_header_block_size(const HTTPHdr &header_set);
 
 private:
@@ -241,6 +244,7 @@ private:
 
   DynamicTable _dynamic_table;
   std::map<uint64_t, struct EntryReference> _references;
+  uint32_t _max_header_list_size = 0;
   uint16_t _max_table_size       = 0;
   uint16_t _max_blocking_streams = 0;
 
@@ -295,11 +299,14 @@ private:
   void _decode(EThread *ethread, Continuation *cont, uint64_t stream_id, const uint8_t *header_block, size_t header_block_len,
                HTTPHdr &hdr);
   int _decode_header(const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr);
-  int _decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr);
-  int _decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr);
-  int _decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr);
-  int _decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr);
-  int _decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr);
+  int _decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len);
+  int _decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr,
+                                                       uint32_t &header_len);
+  int _decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr,
+                                                 uint32_t &header_len);
+  int _decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len);
+  int _decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr,
+                                                          uint32_t &header_len);
 
   // Utilities
   uint16_t _calc_absolute_index_from_relative_index(uint16_t base_index, uint16_t relative_index);