xref: /openbmc/bmcweb/features/redfish/lib/redfish_v1.hpp (revision 51f65b0caa10aa785bd0050d31cf0c01ed17ac8e)
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