Input parameter validation for Event Subscription

User input must be validated to avoid the out-of-memory issue. This
commit adds the size check on input parameters such as Context,
Destination and Header field  while create or update the
EventDestination.

Added a generic error message "PropertySizeExceeded" in message registry
which is used as response when size limit is exceeded.

Tested
  - Validated using POST on Event Subscription.
  - When Context, Destination and Headers were too long,
    received a error message denoting the same.

Change-Id: Ibab847ce0c99f445a76e6d3aee8074428bb7d30f
Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
Signed-off-by: Ed Tanous <edtanous@google.com>
diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
index e45ea45..f55a6bb 100644
--- a/redfish-core/include/error_messages.hpp
+++ b/redfish-core/include/error_messages.hpp
@@ -1070,6 +1070,25 @@
 
 void operationNotAllowed(crow::Response& res);
 
+/**
+ * @brief Formats ArraySizeTooLong message into JSON
+ * Message body: "Indicates that a string value passed to the given resource
+ * exceeded its length limit."
+ * @returns Message ArraySizeTooLong formatted to JSON */
+nlohmann::json arraySizeTooLong(std::string_view property, uint64_t length);
+
+void arraySizeTooLong(crow::Response& res, std::string_view property,
+                      uint64_t length);
+/**
+ * @brief Formats StringValueTooLong message into JSON
+ * Message body: "Indicates that a string value passed to the given resource
+ * exceeded its length limit."
+ * @returns Message StringValueTooLong formatted to JSON */
+nlohmann::json stringValueTooLong(std::string_view property, uint64_t length);
+
+void stringValueTooLong(crow::Response& res, std::string_view property,
+                        uint64_t length);
+
 } // namespace messages
 
 } // namespace redfish
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index 5f57ff7..5a66c97 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -252,6 +252,15 @@
             return;
         }
 
+        // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
+        static constexpr const uint16_t maxDestinationSize = 2000;
+        if (destUrl.size() > maxDestinationSize)
+        {
+            messages::stringValueTooLong(asyncResp->res, "Destination",
+                                         maxDestinationSize);
+            return;
+        }
+
         if (regPrefixes && msgIds)
         {
             if (!regPrefixes->empty() && !msgIds->empty())
@@ -329,13 +338,35 @@
 
         if (context)
         {
+            // This value is selected aribitrarily.
+            constexpr const size_t maxContextSize = 256;
+            if (context->size() > maxContextSize)
+            {
+                messages::stringValueTooLong(asyncResp->res, "Context",
+                                             maxContextSize);
+                return;
+            }
             subValue->customText = *context;
         }
 
         if (headers)
         {
+            size_t cumulativeLen = 0;
+
             for (const nlohmann::json& headerChunk : *headers)
             {
+                std::string hdr{headerChunk.dump(
+                    -1, ' ', true, nlohmann::json::error_handler_t::replace)};
+                cumulativeLen += hdr.length();
+
+                // This value is selected to mirror http_connection.hpp
+                constexpr const uint16_t maxHeaderSizeED = 8096;
+                if (cumulativeLen > maxHeaderSizeED)
+                {
+                    messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
+                                               maxHeaderSizeED);
+                    return;
+                }
                 for (const auto& item : headerChunk.items())
                 {
                     const std::string* value =
diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
index e3fb74b..33f5d70 100644
--- a/redfish-core/src/error_messages.cpp
+++ b/redfish-core/src/error_messages.cpp
@@ -1769,6 +1769,48 @@
     addMessageToErrorJson(res.jsonValue, operationNotAllowed());
 }
 
+/**
+ * @internal
+ * @brief Formats ArraySizeTooLong message into JSON
+ *
+ * See header file for more information
+ * @endinternal
+ */
+nlohmann::json arraySizeTooLong(std::string_view property, uint64_t length)
+{
+    std::string valStr = std::to_string(length);
+    return getLog(redfish::registries::base::Index::arraySizeTooLong,
+                  std::to_array<std::string_view>({property, valStr}));
+}
+
+void arraySizeTooLong(crow::Response& res, std::string_view property,
+                      uint64_t length)
+{
+    res.result(boost::beast::http::status::method_not_allowed);
+    addMessageToErrorJson(res.jsonValue, arraySizeTooLong(property, length));
+}
+
+/**
+ * @internal
+ * @brief Formats StringValueTooLong message into JSON
+ *
+ * See header file for more information
+ * @endinternal
+ */
+nlohmann::json stringValueTooLong(std::string_view property, uint64_t length)
+{
+    std::string valStr = std::to_string(length);
+    return getLog(redfish::registries::base::Index::stringValueTooLong,
+                  std::to_array<std::string_view>({property, valStr}));
+}
+
+void stringValueTooLong(crow::Response& res, std::string_view property,
+                        uint64_t length)
+{
+    res.result(boost::beast::http::status::method_not_allowed);
+    addMessageToErrorJson(res.jsonValue, stringValueTooLong(property, length));
+}
+
 void invalidUpload(crow::Response& res, std::string_view arg1,
                    std::string_view arg2)
 {