Add OData-version header

From the redfish specification:
Redfish Services shall process the OData-Version header in the
following table as defined by the HTTP 1.1 specification.

<Table omitted, but shows "yes" for service requirements>

Services shall reject requests that specify an unsupported OData
version.

This code implements compliance with those two statements.

Tested:
curl -vvvv --insecure --user root:0penBmc -H "OData-Version: 4.1" https://<ip>/redfish/v1
Returns 412 Precondition Failed

curl -vvvv --insecure --user root:0penBmc -H "OData-Version: 4.0" https://<ip>/redfish/v1
returns 200

curl -vvvv --insecure --user root:0penBmc https://<ip>/redfish/v1
returns 200

The equivalent Redfish-Protocol-Validator tests now pass

Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I50350b913f17ae35588e2f0606c56164f00dc2a9
diff --git a/redfish-core/include/node.hpp b/redfish-core/include/node.hpp
index 47c5cc6..f91c22b 100644
--- a/redfish-core/include/node.hpp
+++ b/redfish-core/include/node.hpp
@@ -50,6 +50,26 @@
  */
 class Node
 {
+  private:
+    bool redfishPreChecks(const crow::Request& req, crow::Response& res)
+    {
+        std::string_view odataHeader = req.getHeaderValue("OData-Version");
+        if (odataHeader.empty())
+        {
+            // Clients aren't required to provide odata version
+            return true;
+        }
+        if (odataHeader != "4.0")
+        {
+            redfish::messages::preconditionFailed(res);
+            res.end();
+            return false;
+        }
+
+        res.addHeader("OData-Version", "4.0");
+        return true;
+    }
+
   public:
     template <typename... Params>
     Node(App& app, std::string&& entityUrl, [[maybe_unused]] Params... paramsIn)
@@ -59,6 +79,10 @@
         get.methods(boost::beast::http::verb::get)(
             [this](const crow::Request& req, crow::Response& res,
                    Params... params) {
+                if (!redfishPreChecks(req, res))
+                {
+                    return;
+                }
                 std::vector<std::string> paramVec = {params...};
                 doGet(res, req, paramVec);
             });
@@ -68,6 +92,10 @@
         patch.methods(boost::beast::http::verb::patch)(
             [this](const crow::Request& req, crow::Response& res,
                    Params... params) {
+                if (!redfishPreChecks(req, res))
+                {
+                    return;
+                }
                 std::vector<std::string> paramVec = {params...};
                 doPatch(res, req, paramVec);
             });
@@ -77,6 +105,10 @@
         post.methods(boost::beast::http::verb::post)(
             [this](const crow::Request& req, crow::Response& res,
                    Params... params) {
+                if (!redfishPreChecks(req, res))
+                {
+                    return;
+                }
                 std::vector<std::string> paramVec = {params...};
                 doPost(res, req, paramVec);
             });
@@ -86,6 +118,10 @@
         put.methods(boost::beast::http::verb::put)(
             [this](const crow::Request& req, crow::Response& res,
                    Params... params) {
+                if (!redfishPreChecks(req, res))
+                {
+                    return;
+                }
                 std::vector<std::string> paramVec = {params...};
                 doPut(res, req, paramVec);
             });
@@ -95,6 +131,10 @@
         deleteR.methods(boost::beast::http::verb::delete_)(
             [this](const crow::Request& req, crow::Response& res,
                    Params... params) {
+                if (!redfishPreChecks(req, res))
+                {
+                    return;
+                }
                 std::vector<std::string> paramVec = {params...};
                 doDelete(res, req, paramVec);
             });
diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
index cfbc9c2..7059a38 100644
--- a/redfish-core/src/error_messages.cpp
+++ b/redfish-core/src/error_messages.cpp
@@ -972,7 +972,7 @@
 
 void preconditionFailed(crow::Response& res)
 {
-    res.result(boost::beast::http::status::bad_request);
+    res.result(boost::beast::http::status::precondition_failed);
     addMessageToErrorJson(res.jsonValue, preconditionFailed());
 }