Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
http2_server_stream.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6
8{
10 http2_request request,
11 std::shared_ptr<hpack_encoder> encoder,
12 frame_sender_t frame_sender,
13 uint32_t max_frame_size)
14 : stream_id_(stream_id)
15 , request_(std::move(request))
16 , encoder_(std::move(encoder))
17 , frame_sender_(std::move(frame_sender))
18 , max_frame_size_(max_frame_size)
19 {
20 }
21
23 const std::vector<http_header>& headers,
24 bool end_stream) -> VoidResult
25 {
26 std::lock_guard<std::mutex> lock(mutex_);
27
28 if (state_ == stream_state::closed ||
30 return error_void(
32 "Stream is closed for sending",
33 "http2_server_stream");
34 }
35
36 if (headers_sent_) {
37 return error_void(
39 "Headers already sent",
40 "http2_server_stream");
41 }
42
43 // Build response headers
44 auto response_headers = build_response_headers(status_code, headers);
45
46 // Encode headers using HPACK
47 auto encoded = encoder_->encode(response_headers);
48
49 // Create HEADERS frame
50 headers_frame frame(stream_id_, std::move(encoded), end_stream, true);
51 auto result = frame_sender_(frame);
52
53 if (result.is_err()) {
54 return result;
55 }
56
57 headers_sent_ = true;
58
59 if (end_stream) {
61 }
62
63 return ok();
64 }
65
66 auto http2_server_stream::send_data(const std::vector<uint8_t>& data,
67 bool end_stream) -> VoidResult
68 {
69 std::lock_guard<std::mutex> lock(mutex_);
70
71 if (state_ == stream_state::closed ||
73 return error_void(
75 "Stream is closed for sending",
76 "http2_server_stream");
77 }
78
79 if (!headers_sent_) {
80 return error_void(
82 "Headers must be sent before data",
83 "http2_server_stream");
84 }
85
86 // Split data into frames respecting max_frame_size
87 size_t offset = 0;
88 while (offset < data.size()) {
89 size_t chunk_size = std::min(
90 static_cast<size_t>(max_frame_size_),
91 data.size() - offset);
92
93 std::vector<uint8_t> chunk(data.begin() + static_cast<std::ptrdiff_t>(offset),
94 data.begin() + static_cast<std::ptrdiff_t>(offset + chunk_size));
95
96 bool is_last = (offset + chunk_size >= data.size());
97 bool frame_end_stream = end_stream && is_last;
98
99 data_frame frame(stream_id_, std::move(chunk), frame_end_stream);
100 auto result = frame_sender_(frame);
101
102 if (result.is_err()) {
103 return result;
104 }
105
106 offset += chunk_size;
107 }
108
109 // Handle empty data case with end_stream
110 if (data.empty() && end_stream) {
111 data_frame frame(stream_id_, std::vector<uint8_t>{}, true);
112 auto result = frame_sender_(frame);
113 if (result.is_err()) {
114 return result;
115 }
116 }
117
118 if (end_stream) {
120 }
121
122 return ok();
123 }
124
125 auto http2_server_stream::send_data(std::string_view data, bool end_stream) -> VoidResult
126 {
127 std::vector<uint8_t> bytes(data.begin(), data.end());
128 return send_data(bytes, end_stream);
129 }
130
132 const std::vector<http_header>& headers) -> VoidResult
133 {
134 return send_headers(status_code, headers, false);
135 }
136
137 auto http2_server_stream::write(const std::vector<uint8_t>& chunk) -> VoidResult
138 {
139 return send_data(chunk, false);
140 }
141
143 {
144 return send_data(std::vector<uint8_t>{}, true);
145 }
146
147 auto http2_server_stream::reset(uint32_t err_code) -> VoidResult
148 {
149 std::lock_guard<std::mutex> lock(mutex_);
150
151 if (state_ == stream_state::closed) {
152 return ok();
153 }
154
155 rst_stream_frame frame(stream_id_, err_code);
156 auto result = frame_sender_(frame);
157
158 state_ = stream_state::closed;
159
160 return result;
161 }
162
163 auto http2_server_stream::stream_id() const -> uint32_t
164 {
165 return stream_id_;
166 }
167
168 auto http2_server_stream::method() const -> std::string_view
169 {
170 return request_.method;
171 }
172
173 auto http2_server_stream::path() const -> std::string_view
174 {
175 return request_.path;
176 }
177
178 auto http2_server_stream::headers() const -> const std::vector<http_header>&
179 {
180 return request_.headers;
181 }
182
184 {
185 return request_;
186 }
187
188 auto http2_server_stream::is_open() const -> bool
189 {
190 std::lock_guard<std::mutex> lock(mutex_);
191 return state_ == stream_state::open ||
193 }
194
196 {
197 std::lock_guard<std::mutex> lock(mutex_);
198 return headers_sent_;
199 }
200
202 {
203 std::lock_guard<std::mutex> lock(mutex_);
204 return state_;
205 }
206
207 auto http2_server_stream::update_window(int32_t increment) -> void
208 {
209 std::lock_guard<std::mutex> lock(mutex_);
210 window_size_ += increment;
211 }
212
213 auto http2_server_stream::window_size() const -> int32_t
214 {
215 std::lock_guard<std::mutex> lock(mutex_);
216 return window_size_;
217 }
218
220 const std::vector<http_header>& additional)
221 -> std::vector<http_header>
222 {
223 std::vector<http_header> headers;
224 headers.reserve(additional.size() + 1);
225
226 // :status pseudo-header must be first
227 headers.emplace_back(":status", std::to_string(status_code));
228
229 // Add additional headers
230 for (const auto& header : additional) {
231 headers.push_back(header);
232 }
233
234 return headers;
235 }
236
237} // namespace kcenon::network::protocols::http2
DATA frame (RFC 7540 Section 6.1)
Definition frame.h:139
Base class for HTTP/2 frames.
Definition frame.h:82
HEADERS frame (RFC 7540 Section 6.2)
Definition frame.h:189
auto headers_sent() const -> bool
Check if headers have been sent.
auto state() const -> stream_state
Get current stream state.
std::function< VoidResult(const frame &)> frame_sender_t
Function type for sending frames.
auto method() const -> std::string_view
Get request method.
auto send_headers(int status_code, const std::vector< http_header > &headers, bool end_stream=false) -> VoidResult
Send response headers.
auto is_open() const -> bool
Check if stream is open for sending.
auto start_response(int status_code, const std::vector< http_header > &headers) -> VoidResult
Start a streaming response.
auto path() const -> std::string_view
Get request path.
auto reset(uint32_t err_code=static_cast< uint32_t >(error_code::cancel)) -> VoidResult
Reset the stream with an error code.
auto build_response_headers(int status_code, const std::vector< http_header > &additional) -> std::vector< http_header >
Build response headers with :status pseudo-header.
auto send_data(const std::vector< uint8_t > &data, bool end_stream=false) -> VoidResult
Send response data.
auto end_response() -> VoidResult
End the streaming response.
auto headers() const -> const std::vector< http_header > &
Get request headers.
http2_server_stream(uint32_t stream_id, http2_request request, std::shared_ptr< hpack_encoder > encoder, frame_sender_t frame_sender, uint32_t max_frame_size=16384)
Construct server stream.
auto request() const -> const http2_request &
Get the full request.
auto stream_id() const -> uint32_t
Get stream identifier.
auto write(const std::vector< uint8_t > &chunk) -> VoidResult
Write data chunk for streaming response.
auto update_window(int32_t increment) -> void
Update flow control window.
auto window_size() const -> int32_t
Get available window size.
RST_STREAM frame (RFC 7540 Section 6.4)
Definition frame.h:307
stream_state
HTTP/2 stream state (RFC 7540 Section 5.1)
@ half_closed_remote
Remote end closed, local can send.
@ half_closed_local
Local end closed, remote can send.
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
VoidResult ok()
std::string path
Request path (:path pseudo-header)
std::vector< http_header > headers
Regular headers (non-pseudo)
std::string method
HTTP method (:method pseudo-header)
HTTP header name-value pair.
Definition hpack.h:24