xref: /openbmc/bmcweb/features/redfish/include/utils/query_param.hpp (revision f4c99e70dad320abf84fd25a32ad5fce2bf16f4a)
1*f4c99e70SEd Tanous #pragma once
2*f4c99e70SEd Tanous #include "app.hpp"
3*f4c99e70SEd Tanous #include "async_resp.hpp"
4*f4c99e70SEd Tanous #include "error_messages.hpp"
5*f4c99e70SEd Tanous #include "http_request.hpp"
6*f4c99e70SEd Tanous #include "routing.hpp"
7*f4c99e70SEd Tanous 
8*f4c99e70SEd Tanous #include <string>
9*f4c99e70SEd Tanous #include <string_view>
10*f4c99e70SEd Tanous #include <vector>
11*f4c99e70SEd Tanous 
12*f4c99e70SEd Tanous namespace redfish
13*f4c99e70SEd Tanous {
14*f4c99e70SEd Tanous namespace query_param
15*f4c99e70SEd Tanous {
16*f4c99e70SEd Tanous 
17*f4c99e70SEd Tanous struct Query
18*f4c99e70SEd Tanous {
19*f4c99e70SEd Tanous     bool isOnly = false;
20*f4c99e70SEd Tanous };
21*f4c99e70SEd Tanous 
22*f4c99e70SEd Tanous inline std::optional<Query>
23*f4c99e70SEd Tanous     parseParameters(const boost::urls::params_view& urlParams,
24*f4c99e70SEd Tanous                     crow::Response& res)
25*f4c99e70SEd Tanous {
26*f4c99e70SEd Tanous     Query ret;
27*f4c99e70SEd Tanous     for (const boost::urls::params_view::value_type& it : urlParams)
28*f4c99e70SEd Tanous     {
29*f4c99e70SEd Tanous         std::string_view key(it.key.data(), it.key.size());
30*f4c99e70SEd Tanous         std::string_view value(it.value.data(), it.value.size());
31*f4c99e70SEd Tanous         if (key == "only")
32*f4c99e70SEd Tanous         {
33*f4c99e70SEd Tanous             if (!it.value.empty())
34*f4c99e70SEd Tanous             {
35*f4c99e70SEd Tanous                 messages::queryParameterValueFormatError(res, value, key);
36*f4c99e70SEd Tanous                 return std::nullopt;
37*f4c99e70SEd Tanous             }
38*f4c99e70SEd Tanous             ret.isOnly = true;
39*f4c99e70SEd Tanous         }
40*f4c99e70SEd Tanous     }
41*f4c99e70SEd Tanous     return ret;
42*f4c99e70SEd Tanous }
43*f4c99e70SEd Tanous 
44*f4c99e70SEd Tanous inline bool processOnly(crow::App& app, crow::Response& res,
45*f4c99e70SEd Tanous                         std::function<void(crow::Response&)>& completionHandler)
46*f4c99e70SEd Tanous {
47*f4c99e70SEd Tanous     BMCWEB_LOG_DEBUG << "Processing only query param";
48*f4c99e70SEd Tanous     auto itMembers = res.jsonValue.find("Members");
49*f4c99e70SEd Tanous     if (itMembers == res.jsonValue.end())
50*f4c99e70SEd Tanous     {
51*f4c99e70SEd Tanous         messages::queryNotSupportedOnResource(res);
52*f4c99e70SEd Tanous         completionHandler(res);
53*f4c99e70SEd Tanous         return false;
54*f4c99e70SEd Tanous     }
55*f4c99e70SEd Tanous     auto itMemBegin = itMembers->begin();
56*f4c99e70SEd Tanous     if (itMemBegin == itMembers->end() || itMembers->size() != 1)
57*f4c99e70SEd Tanous     {
58*f4c99e70SEd Tanous         BMCWEB_LOG_DEBUG << "Members contains " << itMembers->size()
59*f4c99e70SEd Tanous                          << " element, returning full collection.";
60*f4c99e70SEd Tanous         completionHandler(res);
61*f4c99e70SEd Tanous         return false;
62*f4c99e70SEd Tanous     }
63*f4c99e70SEd Tanous 
64*f4c99e70SEd Tanous     auto itUrl = itMemBegin->find("@odata.id");
65*f4c99e70SEd Tanous     if (itUrl == itMemBegin->end())
66*f4c99e70SEd Tanous     {
67*f4c99e70SEd Tanous         BMCWEB_LOG_DEBUG << "No found odata.id";
68*f4c99e70SEd Tanous         messages::internalError(res);
69*f4c99e70SEd Tanous         completionHandler(res);
70*f4c99e70SEd Tanous         return false;
71*f4c99e70SEd Tanous     }
72*f4c99e70SEd Tanous     const std::string* url = itUrl->get_ptr<const std::string*>();
73*f4c99e70SEd Tanous     if (url == nullptr)
74*f4c99e70SEd Tanous     {
75*f4c99e70SEd Tanous         BMCWEB_LOG_DEBUG << "@odata.id wasn't a string????";
76*f4c99e70SEd Tanous         messages::internalError(res);
77*f4c99e70SEd Tanous         completionHandler(res);
78*f4c99e70SEd Tanous         return false;
79*f4c99e70SEd Tanous     }
80*f4c99e70SEd Tanous     // TODO(Ed) copy request headers?
81*f4c99e70SEd Tanous     // newReq.session = req.session;
82*f4c99e70SEd Tanous     std::error_code ec;
83*f4c99e70SEd Tanous     crow::Request newReq({boost::beast::http::verb::get, *url, 11}, ec);
84*f4c99e70SEd Tanous     if (ec)
85*f4c99e70SEd Tanous     {
86*f4c99e70SEd Tanous         messages::internalError(res);
87*f4c99e70SEd Tanous         completionHandler(res);
88*f4c99e70SEd Tanous         return false;
89*f4c99e70SEd Tanous     }
90*f4c99e70SEd Tanous 
91*f4c99e70SEd Tanous     auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
92*f4c99e70SEd Tanous     BMCWEB_LOG_DEBUG << "setting completion handler on " << &asyncResp->res;
93*f4c99e70SEd Tanous     asyncResp->res.setCompleteRequestHandler(std::move(completionHandler));
94*f4c99e70SEd Tanous     asyncResp->res.setIsAliveHelper(res.releaseIsAliveHelper());
95*f4c99e70SEd Tanous     app.handle(newReq, asyncResp);
96*f4c99e70SEd Tanous     return true;
97*f4c99e70SEd Tanous }
98*f4c99e70SEd Tanous 
99*f4c99e70SEd Tanous void processAllParams(crow::App& app, Query query,
100*f4c99e70SEd Tanous                       crow::Response& intermediateResponse,
101*f4c99e70SEd Tanous                       std::function<void(crow::Response&)>& completionHandler)
102*f4c99e70SEd Tanous {
103*f4c99e70SEd Tanous     if (!completionHandler)
104*f4c99e70SEd Tanous     {
105*f4c99e70SEd Tanous         BMCWEB_LOG_DEBUG << "Function was invalid?";
106*f4c99e70SEd Tanous         return;
107*f4c99e70SEd Tanous     }
108*f4c99e70SEd Tanous 
109*f4c99e70SEd Tanous     BMCWEB_LOG_DEBUG << "Processing query params";
110*f4c99e70SEd Tanous     // If the request failed, there's no reason to even try to run query
111*f4c99e70SEd Tanous     // params.
112*f4c99e70SEd Tanous     if (intermediateResponse.resultInt() < 200 ||
113*f4c99e70SEd Tanous         intermediateResponse.resultInt() >= 400)
114*f4c99e70SEd Tanous     {
115*f4c99e70SEd Tanous         completionHandler(intermediateResponse);
116*f4c99e70SEd Tanous         return;
117*f4c99e70SEd Tanous     }
118*f4c99e70SEd Tanous     if (query.isOnly)
119*f4c99e70SEd Tanous     {
120*f4c99e70SEd Tanous         processOnly(app, intermediateResponse, completionHandler);
121*f4c99e70SEd Tanous         return;
122*f4c99e70SEd Tanous     }
123*f4c99e70SEd Tanous     completionHandler(intermediateResponse);
124*f4c99e70SEd Tanous }
125*f4c99e70SEd Tanous 
126*f4c99e70SEd Tanous } // namespace query_param
127*f4c99e70SEd Tanous } // namespace redfish
128