blob: 3c2a3f98b962b976741f028e658c90dd2da5f8cf [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 Tanous7045c8d2017-04-03 10:04:37 -07007
Ed Tanous8a9a25c2021-05-11 14:50:58 -07008#include <optional>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05009#include <string>
Ed Tanous8a9a25c2021-05-11 14:50:58 -070010#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070011
Ed Tanous1abe55e2018-09-05 08:30:59 -070012namespace crow
13{
Ed Tanouse0d918b2018-03-27 17:41:04 -070014
Ed Tanous52cc1122020-07-18 13:51:21 -070015template <typename Adaptor, typename Handler>
Ed Tanous7045c8d2017-04-03 10:04:37 -070016class Connection;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010017
Ed Tanous1abe55e2018-09-05 08:30:59 -070018struct Response
19{
Ed Tanous52cc1122020-07-18 13:51:21 -070020 template <typename Adaptor, typename Handler>
Ed Tanous1abe55e2018-09-05 08:30:59 -070021 friend class crow::Connection;
22 using response_type =
23 boost::beast::http::response<boost::beast::http::string_body>;
Ed Tanous7045c8d2017-04-03 10:04:37 -070024
Ed Tanousa24526d2018-12-10 15:17:59 -080025 std::optional<response_type> stringResponse;
Ed Tanouse0d918b2018-03-27 17:41:04 -070026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027 nlohmann::json jsonValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -070028
Ed Tanous39e77502019-03-04 17:35:53 -080029 void addHeader(const std::string_view key, const std::string_view value)
Ed Tanous1abe55e2018-09-05 08:30:59 -070030 {
31 stringResponse->set(key, value);
Ed Tanous7045c8d2017-04-03 10:04:37 -070032 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070033
Ed Tanous39e77502019-03-04 17:35:53 -080034 void addHeader(boost::beast::http::field key, std::string_view value)
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 {
36 stringResponse->set(key, value);
Ed Tanous2cd4cc12018-07-25 10:51:19 -070037 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070038
Ed Tanous1abe55e2018-09-05 08:30:59 -070039 Response() : stringResponse(response_type{})
Gunnar Mills1214b7e2020-06-04 10:11:30 -050040 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070041
Ed Tanousecd6a3a2022-01-07 09:18:40 -080042 ~Response() = default;
43
44 Response(const Response&) = delete;
45 Response(Response&&) = delete;
Nan Zhou72374eb2022-01-27 17:06:51 -080046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 Response& operator=(const Response& r) = delete;
48
49 Response& operator=(Response&& r) noexcept
50 {
Nan Zhou72374eb2022-01-27 17:06:51 -080051 BMCWEB_LOG_DEBUG << "Moving response containers; this: " << this
52 << "; other: " << &r;
53 if (this == &r)
54 {
55 return *this;
56 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 stringResponse = std::move(r.stringResponse);
58 r.stringResponse.emplace(response_type{});
59 jsonValue = std::move(r.jsonValue);
60 completed = r.completed;
Nan Zhou72374eb2022-01-27 17:06:51 -080061 completeRequestHandler = std::move(r.completeRequestHandler);
62 isAliveHelper = std::move(r.isAliveHelper);
63 r.completeRequestHandler = nullptr;
64 r.isAliveHelper = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 return *this;
66 }
67
68 void result(boost::beast::http::status v)
69 {
70 stringResponse->result(v);
71 }
72
73 boost::beast::http::status result()
74 {
75 return stringResponse->result();
76 }
77
78 unsigned resultInt()
79 {
80 return stringResponse->result_int();
81 }
82
Ed Tanous39e77502019-03-04 17:35:53 -080083 std::string_view reason()
Ed Tanous1abe55e2018-09-05 08:30:59 -070084 {
85 return stringResponse->reason();
86 }
87
88 bool isCompleted() const noexcept
89 {
90 return completed;
91 }
92
93 std::string& body()
94 {
95 return stringResponse->body();
96 }
97
98 void keepAlive(bool k)
99 {
100 stringResponse->keep_alive(k);
101 }
102
Ed Tanousceac6f72018-12-02 11:58:47 -0800103 bool keepAlive()
104 {
105 return stringResponse->keep_alive();
106 }
107
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108 void preparePayload()
109 {
110 stringResponse->prepare_payload();
Ed Tanous23a21a12020-07-25 04:45:05 +0000111 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112
113 void clear()
114 {
115 BMCWEB_LOG_DEBUG << this << " Clearing response containers";
116 stringResponse.emplace(response_type{});
117 jsonValue.clear();
118 completed = false;
119 }
120
Ed Tanous81ce6092020-12-17 16:54:55 +0000121 void write(std::string_view bodyPart)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000123 stringResponse->body() += std::string(bodyPart);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124 }
125
126 void end()
127 {
128 if (completed)
129 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800130 BMCWEB_LOG_ERROR << this << " Response was ended twice";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 return;
132 }
133 completed = true;
Nan Zhou72374eb2022-01-27 17:06:51 -0800134 BMCWEB_LOG_DEBUG << this << " calling completion handler";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700135 if (completeRequestHandler)
136 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800137 BMCWEB_LOG_DEBUG << this << " completion handler was valid";
138 completeRequestHandler(*this);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700139 }
140 }
141
Ed Tanous1abe55e2018-09-05 08:30:59 -0700142 bool isAlive()
143 {
144 return isAliveHelper && isAliveHelper();
145 }
146
Nan Zhou72374eb2022-01-27 17:06:51 -0800147 void setCompleteRequestHandler(std::function<void(Response&)>&& handler)
John Edward Broadbent4147b8a2021-07-19 16:52:24 -0700148 {
Nan Zhou72374eb2022-01-27 17:06:51 -0800149 BMCWEB_LOG_DEBUG << this << " setting completion handler";
150 completeRequestHandler = std::move(handler);
151 }
152
153 std::function<void(Response&)> releaseCompleteRequestHandler()
154 {
155 BMCWEB_LOG_DEBUG << this << " releasing completion handler"
156 << static_cast<bool>(completeRequestHandler);
157 std::function<void(Response&)> ret = completeRequestHandler;
158 completeRequestHandler = nullptr;
159 return ret;
160 }
161
162 void setIsAliveHelper(std::function<bool()>&& handler)
163 {
164 isAliveHelper = std::move(handler);
165 }
166
167 std::function<bool()> releaseIsAliveHelper()
168 {
169 std::function<bool()> ret = std::move(isAliveHelper);
170 isAliveHelper = nullptr;
171 return ret;
John Edward Broadbent4147b8a2021-07-19 16:52:24 -0700172 }
173
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 private:
Nan Zhou72374eb2022-01-27 17:06:51 -0800175 bool completed = false;
176 std::function<void(Response&)> completeRequestHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 std::function<bool()> isAliveHelper;
178
179 // In case of a JSON object, set the Content-Type header
180 void jsonMode()
181 {
182 addHeader("Content-Type", "application/json");
183 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700184};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700185} // namespace crow