1 #pragma once 2 3 #include "error_messages.hpp" 4 #include "utility.hpp" 5 6 #include <app.hpp> 7 #include <http_request.hpp> 8 #include <http_response.hpp> 9 #include <schemas.hpp> 10 11 #include <string> 12 13 namespace redfish 14 { 15 16 inline void redfishGet(App& app, const crow::Request& req, 17 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 18 { 19 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 20 { 21 return; 22 } 23 asyncResp->res.jsonValue["v1"] = "/redfish/v1/"; 24 } 25 26 inline void redfish404(App& app, const crow::Request& req, 27 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 28 const std::string& path) 29 { 30 asyncResp->res.addHeader(boost::beast::http::field::allow, ""); 31 32 // If we fall to this route, we didn't have a more specific route, so return 33 // 404 34 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 35 { 36 return; 37 } 38 39 BMCWEB_LOG_ERROR << "404 on path " << path; 40 41 std::string name = req.urlView.segments().back(); 42 // Note, if we hit the wildcard route, we don't know the "type" the user was 43 // actually requesting, but giving them a return with an empty string is 44 // still better than nothing. 45 messages::resourceNotFound(asyncResp->res, "", name); 46 } 47 48 inline void redfish405(App& app, const crow::Request& req, 49 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 50 const std::string& path) 51 { 52 // If we fall to this route, we didn't have a more specific route, so return 53 // 405 54 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 55 { 56 return; 57 } 58 59 BMCWEB_LOG_ERROR << "405 on path " << path; 60 asyncResp->res.result(boost::beast::http::status::method_not_allowed); 61 if (req.method() == boost::beast::http::verb::delete_) 62 { 63 messages::resourceCannotBeDeleted(asyncResp->res); 64 } 65 else 66 { 67 messages::operationNotAllowed(asyncResp->res); 68 } 69 } 70 71 inline void 72 jsonSchemaIndexGet(App& app, const crow::Request& req, 73 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 74 { 75 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 76 { 77 return; 78 } 79 nlohmann::json& json = asyncResp->res.jsonValue; 80 json["@odata.id"] = "/redfish/v1/JsonSchemas"; 81 json["@odata.type"] = "#JsonSchemaFileCollection.JsonSchemaFileCollection"; 82 json["Name"] = "JsonSchemaFile Collection"; 83 json["Description"] = "Collection of JsonSchemaFiles"; 84 nlohmann::json::array_t members; 85 for (const std::string_view schema : schemas) 86 { 87 nlohmann::json::object_t member; 88 member["@odata.id"] = crow::utility::urlFromPieces( 89 "redfish", "v1", "JsonSchemas", schema); 90 members.push_back(std::move(member)); 91 } 92 json["Members"] = std::move(members); 93 json["Members@odata.count"] = schemas.size(); 94 } 95 96 inline void jsonSchemaGet(App& app, const crow::Request& req, 97 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 98 const std::string& schema) 99 { 100 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101 { 102 return; 103 } 104 105 if (std::find(schemas.begin(), schemas.end(), schema) == schemas.end()) 106 { 107 messages::resourceNotFound(asyncResp->res, "JsonSchemaFile", schema); 108 return; 109 } 110 111 nlohmann::json& json = asyncResp->res.jsonValue; 112 json["@odata.id"] = 113 crow::utility::urlFromPieces("redfish", "v1", "JsonSchemas", schema); 114 json["@odata.type"] = "#JsonSchemaFile.v1_0_2.JsonSchemaFile"; 115 json["Name"] = schema + " Schema File"; 116 json["Description"] = schema + " Schema File Location"; 117 json["Id"] = schema; 118 std::string schemaName = "#"; 119 schemaName += schema; 120 schemaName += "."; 121 schemaName += schema; 122 json["Schema"] = std::move(schemaName); 123 constexpr std::array<std::string_view, 1> languages{"en"}; 124 json["Languages"] = languages; 125 json["Languages@odata.count"] = languages.size(); 126 127 nlohmann::json::array_t locationArray; 128 nlohmann::json::object_t locationEntry; 129 locationEntry["Language"] = "en"; 130 locationEntry["PublicationUri"] = 131 "http://redfish.dmtf.org/schemas/v1/" + schema + ".json"; 132 locationEntry["Uri"] = crow::utility::urlFromPieces( 133 "redfish", "v1", "JsonSchemas", schema, std::string(schema) + ".json"); 134 135 locationArray.emplace_back(locationEntry); 136 137 json["Location"] = std::move(locationArray); 138 json["Location@odata.count"] = 1; 139 } 140 141 inline void requestRoutesRedfish(App& app) 142 { 143 BMCWEB_ROUTE(app, "/redfish/") 144 .methods(boost::beast::http::verb::get)( 145 std::bind_front(redfishGet, std::ref(app))); 146 147 BMCWEB_ROUTE(app, "/redfish/v1/JsonSchemas/<str>/") 148 .privileges(redfish::privileges::getJsonSchemaFileCollection) 149 .methods(boost::beast::http::verb::get)( 150 std::bind_front(jsonSchemaGet, std::ref(app))); 151 152 BMCWEB_ROUTE(app, "/redfish/v1/JsonSchemas/") 153 .privileges(redfish::privileges::getJsonSchemaFile) 154 .methods(boost::beast::http::verb::get)( 155 std::bind_front(jsonSchemaIndexGet, std::ref(app))); 156 157 // Note, this route must always be registered last 158 BMCWEB_ROUTE(app, "/redfish/<path>") 159 .notFound() 160 .privileges(redfish::privileges::privilegeSetLogin)( 161 std::bind_front(redfish404, std::ref(app))); 162 163 BMCWEB_ROUTE(app, "/redfish/<path>") 164 .methodNotAllowed() 165 .privileges(redfish::privileges::privilegeSetLogin)( 166 std::bind_front(redfish405, std::ref(app))); 167 } 168 169 } // namespace redfish 170