blob: 6c842d742c6b1d02aa78be29eb48c9bb8fd67558 [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 Tanousecd6a3a2022-01-07 09:18:40 -080043 ~Response() = default;
44
45 Response(const Response&) = delete;
46 Response(Response&&) = delete;
Nan Zhou72374eb2022-01-27 17:06:51 -080047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 Response& operator=(const Response& r) = delete;
49
50 Response& operator=(Response&& r) noexcept
51 {
Nan Zhou72374eb2022-01-27 17:06:51 -080052 BMCWEB_LOG_DEBUG << "Moving response containers; this: " << this
53 << "; other: " << &r;
54 if (this == &r)
55 {
56 return *this;
57 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 stringResponse = std::move(r.stringResponse);
59 r.stringResponse.emplace(response_type{});
60 jsonValue = std::move(r.jsonValue);
61 completed = r.completed;
Nan Zhou72374eb2022-01-27 17:06:51 -080062 completeRequestHandler = std::move(r.completeRequestHandler);
63 isAliveHelper = std::move(r.isAliveHelper);
64 r.completeRequestHandler = nullptr;
65 r.isAliveHelper = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 return *this;
67 }
68
69 void result(boost::beast::http::status v)
70 {
71 stringResponse->result(v);
72 }
73
74 boost::beast::http::status result()
75 {
76 return stringResponse->result();
77 }
78
Carson Labrado039a47e2022-04-05 16:03:20 +000079 unsigned resultInt() const
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 {
81 return stringResponse->result_int();
82 }
83
Ed Tanous39e77502019-03-04 17:35:53 -080084 std::string_view reason()
Ed Tanous1abe55e2018-09-05 08:30:59 -070085 {
86 return stringResponse->reason();
87 }
88
89 bool isCompleted() const noexcept
90 {
91 return completed;
92 }
93
94 std::string& body()
95 {
96 return stringResponse->body();
97 }
98
99 void keepAlive(bool k)
100 {
101 stringResponse->keep_alive(k);
102 }
103
Ed Tanousceac6f72018-12-02 11:58:47 -0800104 bool keepAlive()
105 {
106 return stringResponse->keep_alive();
107 }
108
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 void preparePayload()
110 {
111 stringResponse->prepare_payload();
Ed Tanous23a21a12020-07-25 04:45:05 +0000112 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113
114 void clear()
115 {
116 BMCWEB_LOG_DEBUG << this << " Clearing response containers";
117 stringResponse.emplace(response_type{});
118 jsonValue.clear();
119 completed = false;
120 }
121
Ed Tanous81ce6092020-12-17 16:54:55 +0000122 void write(std::string_view bodyPart)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000124 stringResponse->body() += std::string(bodyPart);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 }
126
127 void end()
128 {
Ed Tanous89f18002022-03-24 18:38:24 -0700129 // Only set etag if this request succeeded
130 if (result() == boost::beast::http::status::ok)
131 {
132 // and the json response isn't empty
133 if (!jsonValue.empty())
134 {
135 size_t hashval = std::hash<nlohmann::json>{}(jsonValue);
136 std::string hexVal = "\"" + intToHexString(hashval, 8) + "\"";
137 addHeader(boost::beast::http::field::etag, hexVal);
138 }
139 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700140 if (completed)
141 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800142 BMCWEB_LOG_ERROR << this << " Response was ended twice";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700143 return;
144 }
145 completed = true;
Nan Zhou72374eb2022-01-27 17:06:51 -0800146 BMCWEB_LOG_DEBUG << this << " calling completion handler";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700147 if (completeRequestHandler)
148 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800149 BMCWEB_LOG_DEBUG << this << " completion handler was valid";
150 completeRequestHandler(*this);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700151 }
152 }
153
Ed Tanous1abe55e2018-09-05 08:30:59 -0700154 bool isAlive()
155 {
156 return isAliveHelper && isAliveHelper();
157 }
158
Nan Zhou72374eb2022-01-27 17:06:51 -0800159 void setCompleteRequestHandler(std::function<void(Response&)>&& handler)
John Edward Broadbent4147b8a2021-07-19 16:52:24 -0700160 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800161 BMCWEB_LOG_DEBUG << this << " setting completion handler";
162 completeRequestHandler = std::move(handler);
163 }
164
165 std::function<void(Response&)> releaseCompleteRequestHandler()
166 {
167 BMCWEB_LOG_DEBUG << this << " releasing completion handler"
168 << static_cast<bool>(completeRequestHandler);
169 std::function<void(Response&)> ret = completeRequestHandler;
170 completeRequestHandler = nullptr;
171 return ret;
172 }
173
174 void setIsAliveHelper(std::function<bool()>&& handler)
175 {
176 isAliveHelper = std::move(handler);
177 }
178
179 std::function<bool()> releaseIsAliveHelper()
180 {
181 std::function<bool()> ret = std::move(isAliveHelper);
182 isAliveHelper = nullptr;
183 return ret;
John Edward Broadbent4147b8a2021-07-19 16:52:24 -0700184 }
185
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 private:
Nan Zhou72374eb2022-01-27 17:06:51 -0800187 bool completed = false;
188 std::function<void(Response&)> completeRequestHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 std::function<bool()> isAliveHelper;
190
191 // In case of a JSON object, set the Content-Type header
192 void jsonMode()
193 {
194 addHeader("Content-Type", "application/json");
195 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700196};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197} // namespace crow