xref: /openbmc/bmcweb/http/http_response.hpp (revision 141d9431)
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() = default;
43 
44     Response(const Response&) = delete;
45     Response(Response&&) = delete;
46     Response& operator=(const Response& r) = delete;
47 
48     Response& operator=(Response&& r) noexcept
49     {
50         BMCWEB_LOG_DEBUG << "Moving response containers";
51         stringResponse = std::move(r.stringResponse);
52         r.stringResponse.emplace(response_type{});
53         jsonValue = std::move(r.jsonValue);
54         completed = r.completed;
55         return *this;
56     }
57 
58     void result(boost::beast::http::status v)
59     {
60         stringResponse->result(v);
61     }
62 
63     boost::beast::http::status result()
64     {
65         return stringResponse->result();
66     }
67 
68     unsigned resultInt()
69     {
70         return stringResponse->result_int();
71     }
72 
73     std::string_view reason()
74     {
75         return stringResponse->reason();
76     }
77 
78     bool isCompleted() const noexcept
79     {
80         return completed;
81     }
82 
83     std::string& body()
84     {
85         return stringResponse->body();
86     }
87 
88     void keepAlive(bool k)
89     {
90         stringResponse->keep_alive(k);
91     }
92 
93     bool keepAlive()
94     {
95         return stringResponse->keep_alive();
96     }
97 
98     void preparePayload()
99     {
100         stringResponse->prepare_payload();
101     }
102 
103     void clear()
104     {
105         BMCWEB_LOG_DEBUG << this << " Clearing response containers";
106         stringResponse.emplace(response_type{});
107         jsonValue.clear();
108         completed = false;
109     }
110 
111     void write(std::string_view bodyPart)
112     {
113         stringResponse->body() += std::string(bodyPart);
114     }
115 
116     void end()
117     {
118         if (completed)
119         {
120             BMCWEB_LOG_ERROR << "Response was ended twice";
121             return;
122         }
123         completed = true;
124         BMCWEB_LOG_DEBUG << "calling completion handler";
125         if (completeRequestHandler)
126         {
127             BMCWEB_LOG_DEBUG << "completion handler was valid";
128             completeRequestHandler();
129         }
130     }
131 
132     void end(std::string_view bodyPart)
133     {
134         write(bodyPart);
135         end();
136     }
137 
138     bool isAlive()
139     {
140         return isAliveHelper && isAliveHelper();
141     }
142 
143     void setCompleteRequestHandler(std::function<void()> newHandler)
144     {
145         completeRequestHandler = std::move(newHandler);
146     }
147 
148   private:
149     bool completed{};
150     std::function<void()> completeRequestHandler;
151     std::function<bool()> isAliveHelper;
152 
153     // In case of a JSON object, set the Content-Type header
154     void jsonMode()
155     {
156         addHeader("Content-Type", "application/json");
157     }
158 };
159 } // namespace crow
160