xref: /openbmc/bmcweb/http/http_response.hpp (revision 9d424669)
1 #pragma once
2 #include "logging.hpp"
3 #include "nlohmann/json.hpp"
4 
5 #include <boost/beast/http/message.hpp>
6 #include <boost/beast/http/string_body.hpp>
7 
8 #include <optional>
9 #include <string>
10 #include <string_view>
11 
12 namespace crow
13 {
14 
15 template <typename Adaptor, typename Handler>
16 class Connection;
17 
18 struct Response
19 {
20     template <typename Adaptor, typename Handler>
21     friend class crow::Connection;
22     using response_type =
23         boost::beast::http::response<boost::beast::http::string_body>;
24 
25     std::optional<response_type> stringResponse;
26 
27     nlohmann::json jsonValue;
28 
29     void addHeader(const std::string_view key, const std::string_view value)
30     {
31         stringResponse->set(key, value);
32     }
33 
34     void addHeader(boost::beast::http::field key, std::string_view value)
35     {
36         stringResponse->set(key, value);
37     }
38 
39     Response() : stringResponse(response_type{})
40     {}
41 
42     Response& operator=(const Response& r) = delete;
43 
44     Response& operator=(Response&& r) noexcept
45     {
46         BMCWEB_LOG_DEBUG << "Moving response containers";
47         stringResponse = std::move(r.stringResponse);
48         r.stringResponse.emplace(response_type{});
49         jsonValue = std::move(r.jsonValue);
50         completed = r.completed;
51         return *this;
52     }
53 
54     void result(boost::beast::http::status v)
55     {
56         stringResponse->result(v);
57     }
58 
59     boost::beast::http::status result()
60     {
61         return stringResponse->result();
62     }
63 
64     unsigned resultInt()
65     {
66         return stringResponse->result_int();
67     }
68 
69     std::string_view reason()
70     {
71         return stringResponse->reason();
72     }
73 
74     bool isCompleted() const noexcept
75     {
76         return completed;
77     }
78 
79     std::string& body()
80     {
81         return stringResponse->body();
82     }
83 
84     void keepAlive(bool k)
85     {
86         stringResponse->keep_alive(k);
87     }
88 
89     bool keepAlive()
90     {
91         return stringResponse->keep_alive();
92     }
93 
94     void preparePayload()
95     {
96         stringResponse->prepare_payload();
97     }
98 
99     void clear()
100     {
101         BMCWEB_LOG_DEBUG << this << " Clearing response containers";
102         stringResponse.emplace(response_type{});
103         jsonValue.clear();
104         completed = false;
105     }
106 
107     void write(std::string_view bodyPart)
108     {
109         stringResponse->body() += std::string(bodyPart);
110     }
111 
112     void end()
113     {
114         if (completed)
115         {
116             BMCWEB_LOG_ERROR << "Response was ended twice";
117             return;
118         }
119         completed = true;
120         BMCWEB_LOG_DEBUG << "calling completion handler";
121         if (completeRequestHandler)
122         {
123             BMCWEB_LOG_DEBUG << "completion handler was valid";
124             completeRequestHandler();
125         }
126     }
127 
128     void end(std::string_view bodyPart)
129     {
130         write(bodyPart);
131         end();
132     }
133 
134     bool isAlive()
135     {
136         return isAliveHelper && isAliveHelper();
137     }
138 
139     void setCompleteRequestHandler(std::function<void()> newHandler)
140     {
141         completeRequestHandler = std::move(newHandler);
142     }
143 
144   private:
145     bool completed{};
146     std::function<void()> completeRequestHandler;
147     std::function<bool()> isAliveHelper;
148 
149     // In case of a JSON object, set the Content-Type header
150     void jsonMode()
151     {
152         addHeader("Content-Type", "application/json");
153     }
154 };
155 } // namespace crow
156