Implement zstd decompression

Given the size of Redfish schemas these days, it would be nice to be
able to store them on disk in a zstd format.  Unfortunately, not all
clients support zstd at this time.

This commit implements reading of zstd files from disk, as well as
decompressing zstd in the case where the client does not support zstd as
a return type.

Tested:
Implanted an artificial zstd file into the system, and observed correct
decompression both with an allow-encoding header of empty string and
zstd.

Change-Id: I8b631bb943de99002fdd6745340aec010ee591ff
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/http/complete_response_fields.hpp b/http/complete_response_fields.hpp
index 486b699..41314b8 100644
--- a/http/complete_response_fields.hpp
+++ b/http/complete_response_fields.hpp
@@ -3,6 +3,7 @@
 #pragma once
 
 #include "boost_formatters.hpp"
+#include "http_body.hpp"
 #include "http_response.hpp"
 #include "http_utility.hpp"
 #include "json_html_serializer.hpp"
@@ -20,7 +21,48 @@
 namespace crow
 {
 
-inline void completeResponseFields(std::string_view accepts, Response& res)
+inline void handleEncoding(std::string_view acceptEncoding, Response& res)
+{
+    using bmcweb::CompressionType;
+    using enum bmcweb::CompressionType;
+    using http_helpers::Encoding;
+    using enum http_helpers::Encoding;
+    // If the payload is currently compressed, see if we can avoid
+    // decompressing it by sending it to the client directly
+    switch (res.response.body().compressionType)
+    {
+        case Zstd:
+        {
+            std::array<Encoding, 1> allowedEnc{ZSTD};
+            Encoding encoding =
+                http_helpers::getPreferredEncoding(acceptEncoding, allowedEnc);
+
+            if (encoding == ZSTD)
+            {
+                // If the client supports returning zstd directly, allow that.
+                res.response.body().clientCompressionType = Zstd;
+            }
+        }
+        break;
+        case Gzip:
+        {
+            std::array<Encoding, 1> allowedEnc{GZIP};
+            Encoding encoding =
+                http_helpers::getPreferredEncoding(acceptEncoding, allowedEnc);
+            if (encoding != GZIP)
+            {
+                BMCWEB_LOG_WARNING(
+                    "Unimplemented: Returning gzip payload to client that did not explicitly allow it.");
+            }
+        }
+        break;
+        default:
+            break;
+    }
+}
+
+inline void completeResponseFields(
+    std::string_view accepts, std::string_view acceptEncoding, Response& res)
 {
     BMCWEB_LOG_INFO("Response: {}", res.resultInt());
     addSecurityHeaders(res);
@@ -56,5 +98,7 @@
                 2, ' ', true, nlohmann::json::error_handler_t::replace));
         }
     }
+
+    handleEncoding(acceptEncoding, res);
 }
 } // namespace crow