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