From eb652d4fbd09a333332d4e2fb28aede6543d456b Mon Sep 17 00:00:00 2001
From: garciay <yann.garcia@fscom.fr>
Date: Tue, 12 Dec 2023 17:28:56 +0100
Subject: [PATCH] Add support of unzip BFK AT download

---
 ccsrc/Protocols/Http/http_codec.cc | 65 +++++++++++++++++++++++++-----
 ccsrc/Protocols/Http/http_codec.hh |  6 ++-
 ccsrc/Protocols/Http/http_layer.cc |  7 +++-
 ccsrc/Protocols/Tcp/tcp_layer.cc   |  4 ++
 4 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/ccsrc/Protocols/Http/http_codec.cc b/ccsrc/Protocols/Http/http_codec.cc
index 270c6c1..cdf4ab7 100644
--- a/ccsrc/Protocols/Http/http_codec.cc
+++ b/ccsrc/Protocols/Http/http_codec.cc
@@ -41,20 +41,47 @@ int http_codec::encode(const LibHttp__TypesAndValues::HttpMessage &msg, OCTETSTR
 int http_codec::decode(const OCTETSTRING &data, LibHttp__TypesAndValues::HttpMessage &msg, params *params) {
   loggers::get_instance().log_msg(">>> http_codec::decode: data=", data);
 
-  // Sanity checks
-  if ((data[0].get_octet() & 0x80) == 0x80) {
-    loggers::get_instance().warning("http_codec::decode: Unicode format not supported");
-    return -1;
-  }
-
   TTCN_EncDec::clear_error();
-  TTCN_Buffer decoding_buffer(data);
-  loggers::get_instance().log_to_hexa("http_codec::decode: decoding_buffer=", decoding_buffer);
+  TTCN_Buffer decoding_buffer;
+
+  if (_initial_content_length != 0) { // Check if the data is a new fragment of the response 
+    loggers::get_instance().warning("http_codec::decode: Need to bufferize and wait for all fragments received");
+    _bufferized_buffers.push_back(data);
+    _current_content_length += data.lengthof(); // FIXME Need to calculate the size of the header buffer, do not assume th first fragmwnt is the header buffer
+    loggers::get_instance().log("http_codec::decode: _bufferized_buffers size: %d - _current_content_length: %d - _initial_content_length: %d", _bufferized_buffers.size(), _current_content_length, _initial_content_length);
+    if (_current_content_length < _initial_content_length) { // Wait for the next fragment
+      loggers::get_instance().warning("http_codec::decode: Wait for the next fragment");
+      return -2;
+    } else { // Rebuild the wall message and continue the decoding
+      loggers::get_instance().log("http_codec::decode: All the fragments were received, rebuild message");
+      // Concatenate the fragments
+      loggers::get_instance().log("http_codec::decode: Concatenate bufferized datas");
+      for (size_t i = 0; i < _bufferized_buffers.size(); i++) {
+        decoding_buffer.put_string(_bufferized_buffers[i]);
+      } // End of 'for' statement
+      _bufferized_buffers.clear();
+      loggers::get_instance().log("http_codec::decode: _bufferized_buffers cleared: %d", _bufferized_buffers.size());
+      // Reset counters
+      loggers::get_instance().log("http_codec::decode: Reset bufferization counters");
+      _initial_content_length = 0;
+      _current_content_length = 0;
+      // Continue the decoding
+    }
+  } else { // It can be a full HTTP response or the first gragment of the HTTP response
+    decoding_buffer.put_string(data);
+  }
+  loggers::get_instance().log("http_codec::decode: decoding_buffer size: %d", decoding_buffer.get_len());
+  loggers::get_instance().log_to_hexa("http_codec::decode: Before decoding_buffer Body: ", decoding_buffer);
 
   _dc.reset();
 
   _params = params;
 
+  if ((*decoding_buffer.get_data() & 0x80) == 0x80) {
+    loggers::get_instance().warning("http_codec::decode: Unicode format not supported");
+    return -1;
+  }
+
   // Get the first line (e.g. HTTP/1.1 302 Found or POST / HTTP/1.1)
   CHARSTRING message_id;
   if (get_line(decoding_buffer, message_id) == -1) {
@@ -84,10 +111,30 @@ int http_codec::decode(const OCTETSTRING &data, LibHttp__TypesAndValues::HttpMes
       response.statuscode()     = std::stoi(m[3].str().c_str());
       response.statustext()     = CHARSTRING(m[4].str().c_str());
       LibHttp__TypesAndValues::Headers headers;
-      std::string                         content_type;
+      std::string                      content_type;
       decode_headers(decoding_buffer, headers, content_type);
+      if (_dc.length > decoding_buffer.get_len()) { // HTTP response is fragmented
+        // Need to bufferize the first packet and wait for the other fragments tp be received
+        loggers::get_instance().warning("http_codec::decode: Need to bufferize the first packet and wait for the other fragments tp be received");
+        // Set counters
+        loggers::get_instance().log("http_codec::decode: Set bufferization counters");
+        _initial_content_length = _dc.length;
+        _current_content_length = 0;
+        _bufferized_buffers.push_back(data);
+        _current_content_length += data.lengthof();
+        loggers::get_instance().log("http_codec::decode: _bufferized_buffers size: %d - _current_content_length: %d", _bufferized_buffers.size(), _current_content_length);
+        return -2;
+      } else {
+        // Force reset counters
+        loggers::get_instance().log("http_codec::decode: Force reset bufferization counters");
+        _initial_content_length = 0;
+        _current_content_length = 0;
+      }
+
       response.header() = headers;
       loggers::get_instance().log_to_hexa("Before decoding Body: ", decoding_buffer);
+      loggers::get_instance().log("http_codec::decode: _initial_content_length = %d", _initial_content_length);
+      loggers::get_instance().log("http_codec::decode: headers().content_length (_dc.length) = %d - decoding_buffer.get_len() = %d", _dc.length, decoding_buffer.get_len());
       LibHttp__MessageBodyTypes::HttpMessageBody body;
       if (decode_body(decoding_buffer, body, content_type) == -1) {
         response.body().set_to_omit();
diff --git a/ccsrc/Protocols/Http/http_codec.hh b/ccsrc/Protocols/Http/http_codec.hh
index 04079e6..37f313c 100644
--- a/ccsrc/Protocols/Http/http_codec.hh
+++ b/ccsrc/Protocols/Http/http_codec.hh
@@ -9,6 +9,7 @@ class Base_Type;
 class Record_Type;
 class TTCN_Typedescriptor_t;
 class TTCN_Buffer;
+class OCTETSTRING;
 
 namespace LibHttp__TypesAndValues {
   class HttpMessage;
@@ -60,9 +61,12 @@ class http_codec : public codec_gen<LibHttp__TypesAndValues::HttpMessage, LibHtt
 
 protected:
   std::map<std::string, std::unique_ptr<codec_gen<Record_Type, Record_Type>>> _codecs;
+  std::vector<OCTETSTRING> _bufferized_buffers;
+  unsigned int             _initial_content_length;
+  unsigned int             _current_content_length;
 
 public:
-  explicit http_codec() : codec_gen<LibHttp__TypesAndValues::HttpMessage, LibHttp__TypesAndValues::HttpMessage>(), _ec(), _dc(), _codecs(){};
+  explicit http_codec() : codec_gen<LibHttp__TypesAndValues::HttpMessage, LibHttp__TypesAndValues::HttpMessage>(), _ec(), _dc(), _codecs(), _bufferized_buffers(), _initial_content_length{0}, _current_content_length{0} {};
   virtual ~http_codec(){};
 
   virtual int encode(const LibHttp__TypesAndValues::HttpMessage &, OCTETSTRING &data);
diff --git a/ccsrc/Protocols/Http/http_layer.cc b/ccsrc/Protocols/Http/http_layer.cc
index bf4da9f..8d83cbc 100644
--- a/ccsrc/Protocols/Http/http_layer.cc
+++ b/ccsrc/Protocols/Http/http_layer.cc
@@ -95,9 +95,14 @@ void http_layer::receive_data(OCTETSTRING &data, params &params) {
 
   // Decode HTTP message
   LibHttp__TypesAndValues::HttpMessage http_message;
-  if (_codec->decode(data, http_message, &params) == -1) {
+  int ret_code = _codec->decode(data, http_message, &params);
+  if (ret_code == -1) {
     loggers::get_instance().warning("http_layer::receive_data: Failed to decode data");
     return;
+  } else if (ret_code == -2) { // Need to wait for next data
+    loggers::get_instance().log("http_layer::receive_data: Set Buffurizing to 1");
+    params.insert(std::make_pair<std::string, std::string>("Buffurizing", "1"));
+    return;
   }
   if (_device_mode) {
     OCTETSTRING os;
diff --git a/ccsrc/Protocols/Tcp/tcp_layer.cc b/ccsrc/Protocols/Tcp/tcp_layer.cc
index 2c49ef9..632ec3b 100644
--- a/ccsrc/Protocols/Tcp/tcp_layer.cc
+++ b/ccsrc/Protocols/Tcp/tcp_layer.cc
@@ -210,6 +210,10 @@ void tcp_layer::message_incoming(const unsigned char* message_buffer, int length
     std::string("timestamp"),
     std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())));
   this->receive_data(data, params); // TODO Check execution time for decoding operation
+  params::const_iterator it = params.find(std::string("Buffurizing"));
+  if (it != params.end()) {
+    loggers::get_instance().log("tcp_layer::message_incoming: Buffurizing requested");
+  }
   loggers::get_instance().set_stop_time(_time_key, duration);
 }
 
-- 
GitLab