blob: dd1f37aea2da385becfc124b9357c384d6ecb5ea [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Ed Tanous04e438c2020-10-03 08:06:26 -07002#include "logging.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -07003#include "nlohmann/json.hpp"
4
Ed Tanousd43cd0c2020-09-30 20:46:53 -07005#include <boost/beast/http/message.hpp>
Ed Tanousd4b6c662021-03-10 13:29:30 -08006#include <boost/beast/http/string_body.hpp>
Ed Tanous89f18002022-03-24 18:38:24 -07007#include <utils/hex_utils.hpp>
Ed Tanous7045c8d2017-04-03 10:04:37 -07008
Ed Tanous8a9a25c2021-05-11 14:50:58 -07009#include <optional>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050010#include <string>
Ed Tanous8a9a25c2021-05-11 14:50:58 -070011#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070012
Ed Tanous1abe55e2018-09-05 08:30:59 -070013namespace crow
14{
Ed Tanouse0d918b2018-03-27 17:41:04 -070015
Ed Tanous52cc1122020-07-18 13:51:21 -070016template <typename Adaptor, typename Handler>
Ed Tanous7045c8d2017-04-03 10:04:37 -070017class Connection;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010018
Ed Tanous1abe55e2018-09-05 08:30:59 -070019struct Response
20{
Ed Tanous52cc1122020-07-18 13:51:21 -070021 template <typename Adaptor, typename Handler>
Ed Tanous1abe55e2018-09-05 08:30:59 -070022 friend class crow::Connection;
23 using response_type =
24 boost::beast::http::response<boost::beast::http::string_body>;
Ed Tanous7045c8d2017-04-03 10:04:37 -070025
Ed Tanousa24526d2018-12-10 15:17:59 -080026 std::optional<response_type> stringResponse;
Ed Tanouse0d918b2018-03-27 17:41:04 -070027
Ed Tanous1abe55e2018-09-05 08:30:59 -070028 nlohmann::json jsonValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -070029
Ed Tanous39e77502019-03-04 17:35:53 -080030 void addHeader(const std::string_view key, const std::string_view value)
Ed Tanous1abe55e2018-09-05 08:30:59 -070031 {
32 stringResponse->set(key, value);
Ed Tanous7045c8d2017-04-03 10:04:37 -070033 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070034
Ed Tanous39e77502019-03-04 17:35:53 -080035 void addHeader(boost::beast::http::field key, std::string_view value)
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 {
37 stringResponse->set(key, value);
Ed Tanous2cd4cc12018-07-25 10:51:19 -070038 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070039
Ed Tanous1abe55e2018-09-05 08:30:59 -070040 Response() : stringResponse(response_type{})
Gunnar Mills1214b7e2020-06-04 10:11:30 -050041 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070042
Ed Tanous13548d82022-07-22 09:50:44 -070043 Response(Response&& res) noexcept :
44 stringResponse(std::move(res.stringResponse)), completed(res.completed)
45 {
46 jsonValue = std::move(res.jsonValue);
47 // See note in operator= move handler for why this is needed.
48 if (!res.completed)
49 {
50 completeRequestHandler = std::move(res.completeRequestHandler);
51 res.completeRequestHandler = nullptr;
52 }
53 isAliveHelper = res.isAliveHelper;
54 res.isAliveHelper = nullptr;
55 }
56
Ed Tanousecd6a3a2022-01-07 09:18:40 -080057 ~Response() = default;
58
59 Response(const Response&) = delete;
Nan Zhou72374eb2022-01-27 17:06:51 -080060
Ed Tanous1abe55e2018-09-05 08:30:59 -070061 Response& operator=(const Response& r) = delete;
62
63 Response& operator=(Response&& r) noexcept
64 {
Nan Zhou72374eb2022-01-27 17:06:51 -080065 BMCWEB_LOG_DEBUG << "Moving response containers; this: " << this
66 << "; other: " << &r;
67 if (this == &r)
68 {
69 return *this;
70 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070071 stringResponse = std::move(r.stringResponse);
72 r.stringResponse.emplace(response_type{});
73 jsonValue = std::move(r.jsonValue);
Ed Tanous13548d82022-07-22 09:50:44 -070074
75 // Only need to move completion handler if not already completed
76 // Note, there are cases where we might move out of a Response object
77 // while in a completion handler for that response object. This check
78 // is intended to prevent destructing the functor we are currently
79 // executing from in that case.
80 if (!r.completed)
81 {
82 completeRequestHandler = std::move(r.completeRequestHandler);
83 r.completeRequestHandler = nullptr;
84 }
85 else
86 {
87 completeRequestHandler = nullptr;
88 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070089 completed = r.completed;
Nan Zhou72374eb2022-01-27 17:06:51 -080090 isAliveHelper = std::move(r.isAliveHelper);
Nan Zhou72374eb2022-01-27 17:06:51 -080091 r.isAliveHelper = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 return *this;
93 }
94
95 void result(boost::beast::http::status v)
96 {
97 stringResponse->result(v);
98 }
99
Ed Tanousbb60f4d2022-06-27 10:39:09 -0700100 boost::beast::http::status result() const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101 {
102 return stringResponse->result();
103 }
104
Carson Labrado039a47e2022-04-05 16:03:20 +0000105 unsigned resultInt() const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 {
107 return stringResponse->result_int();
108 }
109
Ed Tanousbb60f4d2022-06-27 10:39:09 -0700110 std::string_view reason() const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 {
112 return stringResponse->reason();
113 }
114
115 bool isCompleted() const noexcept
116 {
117 return completed;
118 }
119
120 std::string& body()
121 {
122 return stringResponse->body();
123 }
124
Carson Labrado46a81462022-04-27 21:11:37 +0000125 std::string_view getHeaderValue(std::string_view key) const
126 {
127 return stringResponse->base()[key];
128 }
129
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 void keepAlive(bool k)
131 {
132 stringResponse->keep_alive(k);
133 }
134
Ed Tanousbb60f4d2022-06-27 10:39:09 -0700135 bool keepAlive() const
Ed Tanousceac6f72018-12-02 11:58:47 -0800136 {
137 return stringResponse->keep_alive();
138 }
139
Ed Tanous1abe55e2018-09-05 08:30:59 -0700140 void preparePayload()
141 {
142 stringResponse->prepare_payload();
Ed Tanous23a21a12020-07-25 04:45:05 +0000143 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144
145 void clear()
146 {
147 BMCWEB_LOG_DEBUG << this << " Clearing response containers";
148 stringResponse.emplace(response_type{});
149 jsonValue.clear();
150 completed = false;
151 }
152
Ed Tanous81ce6092020-12-17 16:54:55 +0000153 void write(std::string_view bodyPart)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700154 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000155 stringResponse->body() += std::string(bodyPart);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 }
157
158 void end()
159 {
Ed Tanous89f18002022-03-24 18:38:24 -0700160 // Only set etag if this request succeeded
161 if (result() == boost::beast::http::status::ok)
162 {
163 // and the json response isn't empty
164 if (!jsonValue.empty())
165 {
166 size_t hashval = std::hash<nlohmann::json>{}(jsonValue);
167 std::string hexVal = "\"" + intToHexString(hashval, 8) + "\"";
168 addHeader(boost::beast::http::field::etag, hexVal);
169 }
170 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 if (completed)
172 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800173 BMCWEB_LOG_ERROR << this << " Response was ended twice";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 return;
175 }
176 completed = true;
Nan Zhou72374eb2022-01-27 17:06:51 -0800177 BMCWEB_LOG_DEBUG << this << " calling completion handler";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 if (completeRequestHandler)
179 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800180 BMCWEB_LOG_DEBUG << this << " completion handler was valid";
181 completeRequestHandler(*this);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700182 }
183 }
184
Ed Tanousbb60f4d2022-06-27 10:39:09 -0700185 bool isAlive() const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 {
187 return isAliveHelper && isAliveHelper();
188 }
189
Nan Zhou72374eb2022-01-27 17:06:51 -0800190 void setCompleteRequestHandler(std::function<void(Response&)>&& handler)
John Edward Broadbent4147b8a2021-07-19 16:52:24 -0700191 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800192 BMCWEB_LOG_DEBUG << this << " setting completion handler";
193 completeRequestHandler = std::move(handler);
Ed Tanous13548d82022-07-22 09:50:44 -0700194
195 // Now that we have a new completion handler attached, we're no longer
196 // complete
197 completed = false;
Nan Zhou72374eb2022-01-27 17:06:51 -0800198 }
199
200 std::function<void(Response&)> releaseCompleteRequestHandler()
201 {
202 BMCWEB_LOG_DEBUG << this << " releasing completion handler"
203 << static_cast<bool>(completeRequestHandler);
204 std::function<void(Response&)> ret = completeRequestHandler;
205 completeRequestHandler = nullptr;
Ed Tanous13548d82022-07-22 09:50:44 -0700206 completed = true;
Nan Zhou72374eb2022-01-27 17:06:51 -0800207 return ret;
208 }
209
210 void setIsAliveHelper(std::function<bool()>&& handler)
211 {
212 isAliveHelper = std::move(handler);
213 }
214
215 std::function<bool()> releaseIsAliveHelper()
216 {
217 std::function<bool()> ret = std::move(isAliveHelper);
218 isAliveHelper = nullptr;
219 return ret;
John Edward Broadbent4147b8a2021-07-19 16:52:24 -0700220 }
221
Ed Tanous1abe55e2018-09-05 08:30:59 -0700222 private:
Nan Zhou72374eb2022-01-27 17:06:51 -0800223 bool completed = false;
224 std::function<void(Response&)> completeRequestHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 std::function<bool()> isAliveHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700226};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227} // namespace crow