blob: 5ca337ff7d86e175c7a7d5c550f37c7f844e7286 [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"
Borawski.Lukaszb6df6dc2018-01-24 10:20:45 +010021#include "crow.h"
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010022
23namespace redfish {
24
25/**
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020026 * AsyncResp
27 * Gathers data needed for response processing after async calls are done
28 */
29class AsyncResp {
30 public:
31 AsyncResp(crow::response& response) : res(response) {}
32
33 ~AsyncResp() { res.end(); }
34
35 crow::response& res;
36};
37
38/**
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010039 * @brief Abstract class used for implementing Redfish nodes.
40 *
41 */
42class Node {
43 public:
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010044 template <typename... Params>
Ed Tanous3ebd75f2018-03-05 18:20:01 -080045 Node(CrowApp& app, std::string&& entityUrl, Params... params) {
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010046 app.route_dynamic(entityUrl.c_str())
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010047 .methods("GET"_method, "PATCH"_method, "POST"_method,
48 "DELETE"_method)([&](const crow::request& req,
49 crow::response& res, Params... params) {
50 std::vector<std::string> paramVec = {params...};
51 dispatchRequest(app, req, res, paramVec);
52 });
53 }
54
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010055 virtual ~Node() = default;
56
Ed Tanouscbbfa962018-03-13 16:46:28 -070057 const std::string* getUrl() const {
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010058 auto odataId = json.find("@odata.id");
Ed Tanouscbbfa962018-03-13 16:46:28 -070059 if (odataId == json.end()) {
60 return nullptr;
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010061 }
Ed Tanouscbbfa962018-03-13 16:46:28 -070062
63 return odataId->get_ptr<const std::string*>();
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010064 }
65
66 /**
67 * @brief Inserts subroute fields into for the node's json in the form:
68 * "subroute_name" : { "odata.id": "node_url/subroute_name/" }
69 * Excludes metadata urls starting with "$" and child urls having
70 * more than one level.
71 *
72 * @return None
73 */
74 void getSubRoutes(const std::vector<std::unique_ptr<Node>>& allNodes) {
Ed Tanouscbbfa962018-03-13 16:46:28 -070075 const std::string* url = getUrl();
76 if (url == nullptr) {
77 CROW_LOG_CRITICAL << "Unable to get url for route";
78 return;
79 }
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010080
81 for (const auto& node : allNodes) {
Ed Tanouscbbfa962018-03-13 16:46:28 -070082 const std::string* route = node->getUrl();
83 if (route == nullptr) {
84 CROW_LOG_CRITICAL << "Unable to get url for route";
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010085 continue;
Ed Tanouscbbfa962018-03-13 16:46:28 -070086 }
87 if (boost::starts_with(*route, *url)) {
88 std::string subRoute = route->substr(url->size());
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010089 if (subRoute.empty()) {
90 continue;
91 }
92
Ed Tanouscbbfa962018-03-13 16:46:28 -070093 if (boost::starts_with(subRoute, "/")) {
94 subRoute.erase(0, 1);
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010095 }
96
Ed Tanouscbbfa962018-03-13 16:46:28 -070097 if (boost::ends_with(subRoute, "/")) {
98 subRoute.pop_back();
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010099 }
100
Ed Tanouscbbfa962018-03-13 16:46:28 -0700101 if (!boost::starts_with(subRoute, "$") &&
102 subRoute.find('/') == std::string::npos) {
103 json[subRoute] = nlohmann::json{{"@odata.id", *route}};
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100104 }
105 }
106 }
107 }
108
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800109 OperationMap entityPrivileges;
110
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100111 protected:
112 // Node is designed to be an abstract class, so doGet is pure virtual
113 virtual void doGet(crow::response& res, const crow::request& req,
114 const std::vector<std::string>& params) = 0;
115
116 virtual void doPatch(crow::response& res, const crow::request& req,
117 const std::vector<std::string>& params) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700118 res.result(boost::beast::http::status::method_not_allowed);
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100119 res.end();
120 }
121
122 virtual void doPost(crow::response& res, const crow::request& req,
123 const std::vector<std::string>& params) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700124 res.result(boost::beast::http::status::method_not_allowed);
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100125 res.end();
126 }
127
128 virtual void doDelete(crow::response& res, const crow::request& req,
129 const std::vector<std::string>& params) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700130 res.result(boost::beast::http::status::method_not_allowed);
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100131 res.end();
132 }
133
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100134 nlohmann::json json;
135
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100136 private:
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100137 void dispatchRequest(CrowApp& app, const crow::request& req,
138 crow::response& res,
139 const std::vector<std::string>& params) {
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100140 auto ctx =
141 app.template get_context<crow::TokenAuthorization::Middleware>(req);
142
Ed Tanouse0d918b2018-03-27 17:41:04 -0700143 if (!isMethodAllowedForUser(req.method(), entityPrivileges,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800144 ctx.session->username)) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700145 res.result(boost::beast::http::status::method_not_allowed);
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100146 res.end();
147 return;
148 }
149
Ed Tanouse0d918b2018-03-27 17:41:04 -0700150 switch (req.method()) {
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100151 case "GET"_method:
152 doGet(res, req, params);
153 break;
154
155 case "PATCH"_method:
156 doPatch(res, req, params);
157 break;
158
159 case "POST"_method:
160 doPost(res, req, params);
161 break;
162
163 case "DELETE"_method:
164 doDelete(res, req, params);
165 break;
166
167 default:
Ed Tanouse0d918b2018-03-27 17:41:04 -0700168 res.result(boost::beast::http::status::not_found);
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100169 res.end();
170 }
171 return;
172 }
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100173};
174
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100175} // namespace redfish