blob: 80e0744f3cc0ee15e9c38a47d852b4381aa3452d [file] [log] [blame]
Borawski.Lukasz86e1b662018-01-19 14:22:14 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010018#include "privileges.hpp"
19#include "token_authorization_middleware.hpp"
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010020#include "webserver_common.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070021
Ed Tanousa0803ef2018-08-29 13:29:23 -070022#include <error_messages.hpp>
23
Borawski.Lukaszb6df6dc2018-01-24 10:20:45 +010024#include "crow.h"
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace redfish
27{
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010028
29/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020030 * AsyncResp
31 * Gathers data needed for response processing after async calls are done
32 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070033class AsyncResp
34{
35 public:
36 AsyncResp(crow::Response& response) : res(response)
37 {
38 }
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020039
Ed Tanous1abe55e2018-09-05 08:30:59 -070040 ~AsyncResp()
41 {
Ed Tanousa0803ef2018-08-29 13:29:23 -070042 if (res.result() != boost::beast::http::status::ok)
43 {
44 nlohmann::json::iterator error = res.jsonValue.find("error");
45
46 if (error == res.jsonValue.end())
47 {
48 // If an error value hasn't yet been set, assume that whatever
49 // content we have is garbage, and provide a worthless internal
50 // server error
51 res.jsonValue = {};
52 }
53 // Reset the json object to clear out any data that made it in
54 // before the error happened todo(ed) handle error condition with
55 // proper code
56 messages::addMessageToErrorJson(res.jsonValue,
57 messages::internalError());
58 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 res.end();
60 }
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020061
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 crow::Response& res;
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020063};
64
65/**
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010066 * @brief Abstract class used for implementing Redfish nodes.
67 *
68 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070069class Node
70{
71 public:
72 template <typename... Params>
73 Node(CrowApp& app, std::string&& entityUrl, Params... params)
74 {
75 app.routeDynamic(entityUrl.c_str())
76 .methods("GET"_method, "PATCH"_method, "POST"_method,
77 "DELETE"_method)([&](const crow::Request& req,
78 crow::Response& res,
79 Params... params) {
80 std::vector<std::string> paramVec = {params...};
81 dispatchRequest(app, req, res, paramVec);
82 });
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010083 }
Ed Tanouscbbfa962018-03-13 16:46:28 -070084
Ed Tanous1abe55e2018-09-05 08:30:59 -070085 virtual ~Node() = default;
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010086
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 const std::string* getUrl() const
88 {
89 auto odataId = json.find("@odata.id");
90 if (odataId == json.end())
91 {
92 return nullptr;
93 }
94
95 return odataId->get_ptr<const std::string*>();
Ed Tanouscbbfa962018-03-13 16:46:28 -070096 }
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010097
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 /**
99 * @brief Inserts subroute fields into for the node's json in the form:
100 * "subroute_name" : { "odata.id": "node_url/subroute_name/" }
101 * Excludes metadata urls starting with "$" and child urls having
102 * more than one level.
103 *
104 * @return None
105 */
106 void getSubRoutes(const std::vector<std::unique_ptr<Node>>& allNodes)
107 {
108 const std::string* url = getUrl();
109 if (url == nullptr)
110 {
111 // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
112 return;
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100113 }
114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 for (const auto& node : allNodes)
116 {
117 const std::string* route = node->getUrl();
118 if (route == nullptr)
119 {
120 // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
121 continue;
122 }
123 if (boost::starts_with(*route, *url))
124 {
125 std::string subRoute = route->substr(url->size());
126 if (subRoute.empty())
127 {
128 continue;
129 }
130
131 if (boost::starts_with(subRoute, "/"))
132 {
133 subRoute.erase(0, 1);
134 }
135
136 if (boost::ends_with(subRoute, "/"))
137 {
138 subRoute.pop_back();
139 }
140
141 if (!boost::starts_with(subRoute, "$") &&
142 subRoute.find('/') == std::string::npos)
143 {
144 json[subRoute] = nlohmann::json{{"@odata.id", *route}};
145 }
146 }
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100147 }
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100148 }
149
Ed Tanous1abe55e2018-09-05 08:30:59 -0700150 OperationMap entityPrivileges;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100151
Ed Tanous1abe55e2018-09-05 08:30:59 -0700152 protected:
153 // Node is designed to be an abstract class, so doGet is pure virtual
154 virtual void doGet(crow::Response& res, const crow::Request& req,
155 const std::vector<std::string>& params)
156 {
157 res.result(boost::beast::http::status::method_not_allowed);
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100158 res.end();
159 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160
161 virtual void doPatch(crow::Response& res, const crow::Request& req,
162 const std::vector<std::string>& params)
163 {
164 res.result(boost::beast::http::status::method_not_allowed);
165 res.end();
166 }
167
168 virtual void doPost(crow::Response& res, const crow::Request& req,
169 const std::vector<std::string>& params)
170 {
171 res.result(boost::beast::http::status::method_not_allowed);
172 res.end();
173 }
174
175 virtual void doDelete(crow::Response& res, const crow::Request& req,
176 const std::vector<std::string>& params)
177 {
178 res.result(boost::beast::http::status::method_not_allowed);
179 res.end();
180 }
181
182 nlohmann::json json;
183
184 private:
185 void dispatchRequest(CrowApp& app, const crow::Request& req,
186 crow::Response& res,
187 const std::vector<std::string>& params)
188 {
189 auto ctx =
190 app.template getContext<crow::token_authorization::Middleware>(req);
191
192 if (!isMethodAllowedForUser(req.method(), entityPrivileges,
193 ctx.session->username))
194 {
195 res.result(boost::beast::http::status::method_not_allowed);
196 res.end();
197 return;
198 }
199
200 switch (req.method())
201 {
202 case "GET"_method:
203 doGet(res, req, params);
204 break;
205
206 case "PATCH"_method:
207 doPatch(res, req, params);
208 break;
209
210 case "POST"_method:
211 doPost(res, req, params);
212 break;
213
214 case "DELETE"_method:
215 doDelete(res, req, params);
216 break;
217
218 default:
219 res.result(boost::beast::http::status::not_found);
220 res.end();
221 }
222 return;
223 }
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100224};
225
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226} // namespace redfish