userver: userver/server/request/response_base.hpp Source File
Loading...
Searching...
No Matches
response_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/request/response_base.hpp
4/// @brief @copybrief server::request::ResponseBase
5
6#include <atomic>
7#include <chrono>
8#include <functional>
9#include <limits>
10#include <memory>
11#include <optional>
12#include <string>
13#include <string_view>
14#include <variant>
15
16#include <userver/concurrent/queue.hpp>
17#include <userver/concurrent/striped_counter.hpp>
18#include <userver/engine/single_consumer_event.hpp>
19#include <userver/utils/fast_pimpl.hpp>
20
21USERVER_NAMESPACE_BEGIN
22
23/// @cond
24// TODO: server internals. remove from a public interface
25namespace server::http::impl {
26
27struct Http2StreamEvent {
28 std::int32_t stream_id{-1};
29 std::string body_part{};
30 bool is_end{false};
31};
32
33// The order is fifo in the context of a single producer. So we are tolerant to
34// reordering between producers
35using Http2StreamEventQueue = concurrent::NonFifoMpscQueue<Http2StreamEvent>;
36
37class Http2StreamEventProducer final {
38public:
39 Http2StreamEventProducer(Http2StreamEventQueue& queue, engine::SingleConsumerEvent& event);
40
41 void PushEvent(Http2StreamEvent event, engine::Deadline deadline = {});
42
43 void CloseStream(std::int32_t id);
44
45private:
46 Http2StreamEventQueue::Producer producer_;
47 engine::SingleConsumerEvent& event_;
48};
49
50} // namespace server::http::impl
51/// @endcond
52
53namespace engine::io {
54class RwBase;
55} // namespace engine::io
56
57namespace server::request {
58
59namespace impl {
60
61class ChunkStorage final {
62public:
63 ChunkStorage() = default;
64 explicit ChunkStorage(std::string data);
65 explicit ChunkStorage(std::shared_ptr<const std::string> data);
66
67 ChunkStorage(const ChunkStorage&) = delete;
68 ChunkStorage(ChunkStorage&&) noexcept = default;
69 ChunkStorage& operator=(const ChunkStorage&) = delete;
70 ChunkStorage& operator=(ChunkStorage&&) noexcept = default;
71
72 bool Empty() const noexcept;
73 std::size_t Size() const noexcept;
74 std::string_view View() const noexcept;
75 const std::string& AsString() const;
76
77private:
78 std::variant<std::string, std::shared_ptr<const std::string>> storage_{};
79};
80
81} // namespace impl
82
83class ResponseDataAccounter final {
84public:
85 void StartRequest(std::chrono::steady_clock::time_point create_time);
86
87 void StopRequest(std::size_t size, std::chrono::steady_clock::time_point create_time);
88
89 void ReaccountRequest(
90 std::size_t old_size,
91 std::chrono::steady_clock::time_point old_create_time,
92 std::size_t new_size,
93 std::chrono::steady_clock::time_point new_create_time
94 );
95
96 std::size_t GetPendingResponsesSizeInBytes() const { return pending_responses_size_in_bytes_; }
97
98 std::size_t GetPendingResponsesCount() const { return pending_responses_count_.NonNegativeRead(); }
99
100 std::size_t GetMaxPendingResponsesSizeInBytes() const { return max_pending_responses_size_in_bytes_; }
101
102 void SetMaxPendingResponsesSizeInBytes(size_t size) { max_pending_responses_size_in_bytes_ = size; }
103
104 std::chrono::milliseconds GetAvgRequestTime() const;
105
106private:
107 std::atomic<std::size_t> pending_responses_size_in_bytes_{0};
108 std::atomic<std::size_t> max_pending_responses_size_in_bytes_{std::numeric_limits<std::size_t>::max()};
109 concurrent::StripedCounter pending_responses_count_{};
110 concurrent::StripedCounter time_sum_{};
111};
112
113// TODO: merge with HttpResponse
114
115/// @brief Base class for all the server responses.
117public:
118 explicit ResponseBase(ResponseDataAccounter& data_accounter);
119 ResponseBase(const ResponseBase&) = delete;
120 ResponseBase(ResponseBase&&) = delete;
121 virtual ~ResponseBase() noexcept;
122
123 void SetData(std::string data);
124 /// @brief Sets response body without copying, keeping @a data alive.
125 /// Useful for serving cached static content.
126 void SetSharedData(std::shared_ptr<const std::string> data);
127 const std::string& GetData() const;
128 /// @cond
129 // For internal use only.
130 impl::ChunkStorage ExtractData();
131 /// @endcond
132
133 virtual bool IsBodyStreamed() const = 0;
134 virtual bool WaitForHeadersEnd() = 0;
135 virtual void SetHeadersEnd() = 0;
136
137 /// @cond
138 // TODO: server internals. remove from a public interface
139 void SetReady();
140 void SetReady(std::chrono::steady_clock::time_point now);
141 bool IsLimitReached() const;
142
143 bool IsReady() const noexcept { return ready_time_ != kUnset; }
144 bool IsSent() const noexcept { return is_sent_; }
145 std::size_t GetBytesSent() const noexcept { return bytes_sent_; }
146 std::chrono::steady_clock::time_point GetReadyTime() const noexcept { return ready_time_; }
147 virtual void SendResponse(engine::io::RwBase& socket) = 0;
148
149 virtual void SetStatusServiceUnavailable() = 0;
150 virtual void SetStatusOk() = 0;
151 virtual void SetStatusNotFound() = 0;
152
153 // HTTP/2.0 only
154 void SetStreamId(std::int32_t stream_id);
155 std::optional<std::int32_t> GetStreamId() const { return stream_id_; }
156 void SetStreamProdicer(http::impl::Http2StreamEventProducer&& producer);
157 http::impl::Http2StreamEventProducer GetStreamProducer();
158 /// @endcond
159
160protected:
161 ResponseBase(ResponseDataAccounter& data_account, std::chrono::steady_clock::time_point now);
162
163 void SetSendFailed();
164 void SetSent(std::size_t bytes_sent);
165
166private:
167 void StoreData(impl::ChunkStorage data);
168
169 static constexpr auto kUnset = std::chrono::steady_clock::time_point::min();
170
171 ResponseDataAccounter& accounter_;
172 impl::ChunkStorage data_;
173 std::chrono::steady_clock::time_point create_time_;
174 std::chrono::steady_clock::time_point ready_time_{kUnset};
175 std::size_t accounted_size_ = 0;
176 std::size_t bytes_sent_ = 0;
177 bool is_sent_ = false;
178 std::optional<std::int32_t> stream_id_;
179 std::optional<http::impl::Http2StreamEventProducer> producer_{};
180};
181
182} // namespace server::request
183
184USERVER_NAMESPACE_END