Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2025 Mohammad Nejati | ||
3 | // | ||
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
6 | // | ||
7 | // Official repository: https://github.com/cppalliance/http_proto | ||
8 | // | ||
9 | |||
10 | #ifndef BOOST_HTTP_PROTO_STATIC_RESPONSE_HPP | ||
11 | #define BOOST_HTTP_PROTO_STATIC_RESPONSE_HPP | ||
12 | |||
13 | #include <boost/http_proto/response_base.hpp> | ||
14 | |||
15 | namespace boost { | ||
16 | namespace http_proto { | ||
17 | |||
18 | /** A modifiable static container for HTTP responses. | ||
19 | |||
20 | This container owns a response, represented | ||
21 | by an inline buffer with fixed capacity. | ||
22 | The contents may be inspected and modified, | ||
23 | and the implementation maintains a useful | ||
24 | invariant: changes to the response always | ||
25 | leave it in a valid state. | ||
26 | |||
27 | @par Example | ||
28 | @code | ||
29 | static_response<1024> res(status::not_found); | ||
30 | |||
31 | res.set(field::server, "Boost.HttpProto"); | ||
32 | res.set(field::content_type, "text/plain"); | ||
33 | res.set_content_length(80); | ||
34 | |||
35 | assert(res.buffer() == | ||
36 | "HTTP/1.1 404 Not Found\r\n" | ||
37 | "Server: Boost.HttpProto\r\n" | ||
38 | "Content-Type: text/plain\r\n" | ||
39 | "Content-Length: 80\r\n" | ||
40 | "\r\n"); | ||
41 | @endcode | ||
42 | |||
43 | @par Invariants | ||
44 | @code | ||
45 | this->capacity_in_bytes() == Capacity && this->max_capacity_in_bytes() == Capacity | ||
46 | @endcode | ||
47 | |||
48 | @tparam Capacity The maximum capacity in bytes. | ||
49 | |||
50 | @see | ||
51 | @ref response, | ||
52 | @ref response_view. | ||
53 | */ | ||
54 | template<std::size_t Capacity> | ||
55 | class static_response | ||
56 | : public response_base | ||
57 | { | ||
58 | alignas(entry) | ||
59 | char buf_[Capacity]; | ||
60 | |||
61 | public: | ||
62 | |||
63 | //-------------------------------------------- | ||
64 | // | ||
65 | // Special Members | ||
66 | // | ||
67 | //-------------------------------------------- | ||
68 | |||
69 | /** Constructor. | ||
70 | |||
71 | A default-constructed response contains | ||
72 | a valid HTTP 200 OK response with no headers. | ||
73 | |||
74 | @par Example | ||
75 | @code | ||
76 | static_response<1024> res; | ||
77 | @endcode | ||
78 | |||
79 | @par Postconditions | ||
80 | @code | ||
81 | this->buffer() == "HTTP/1.1 200 OK\r\n\r\n" | ||
82 | @endcode | ||
83 | |||
84 | @par Complexity | ||
85 | Constant. | ||
86 | */ | ||
87 | 40 | static_response() noexcept | |
88 | 40 | : fields_view_base(&this->fields_base::h_) | |
89 | 40 | , response_base(buf_, Capacity) | |
90 | { | ||
91 | 40 | } | |
92 | |||
93 | /** Constructor. | ||
94 | |||
95 | Constructs a response from the string `s`, | ||
96 | which must contain valid HTTP response | ||
97 | or else an exception is thrown. | ||
98 | The new response retains ownership by | ||
99 | making a copy of the passed string. | ||
100 | |||
101 | @par Example | ||
102 | @code | ||
103 | static_response<1024> res( | ||
104 | "HTTP/1.1 404 Not Found\r\n" | ||
105 | "Server: Boost.HttpProto\r\n" | ||
106 | "Content-Type: text/plain\r\n" | ||
107 | "\r\n"); | ||
108 | @endcode | ||
109 | |||
110 | @par Postconditions | ||
111 | @code | ||
112 | this->buffer.data() != s.data() | ||
113 | @endcode | ||
114 | |||
115 | @par Complexity | ||
116 | Linear in `s.size()`. | ||
117 | |||
118 | @par Exception Safety | ||
119 | Exception thrown on invalid input. | ||
120 | Exception thrown if max capacity exceeded. | ||
121 | |||
122 | @throw system_error | ||
123 | The input does not contain a valid response. | ||
124 | |||
125 | @throw std::length_error | ||
126 | Max capacity would be exceeded. | ||
127 | |||
128 | @param s The string to parse. | ||
129 | */ | ||
130 | explicit | ||
131 | 6 | static_response( | |
132 | core::string_view s) | ||
133 | 6 | : fields_view_base(&this->fields_base::h_) | |
134 | 6 | , response_base(s, buf_, Capacity) | |
135 | { | ||
136 | 6 | } | |
137 | |||
138 | /** Constructor. | ||
139 | |||
140 | The start-line of the response will | ||
141 | contain the standard text for the | ||
142 | supplied status code and HTTP version. | ||
143 | |||
144 | @par Example | ||
145 | @code | ||
146 | static_response<1024> res(status::not_found, version::http_1_0); | ||
147 | @endcode | ||
148 | |||
149 | @par Complexity | ||
150 | Linear in `obsolete_reason(s).size()`. | ||
151 | |||
152 | @par Exception Safety | ||
153 | Exception thrown if max capacity exceeded. | ||
154 | |||
155 | @throw std::length_error | ||
156 | Max capacity would be exceeded. | ||
157 | |||
158 | @param sc The status code. | ||
159 | |||
160 | @param v The HTTP version. | ||
161 | */ | ||
162 | 20 | static_response( | |
163 | http_proto::status sc, | ||
164 | http_proto::version v) | ||
165 | 20 | : static_response() | |
166 | { | ||
167 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
20 | set_start_line(sc, v); |
168 | 20 | } | |
169 | |||
170 | /** Constructor. | ||
171 | |||
172 | The start-line of the response will | ||
173 | contain the standard text for the | ||
174 | supplied status code with the HTTP version | ||
175 | defaulted to `HTTP/1.1`. | ||
176 | |||
177 | @par Example | ||
178 | @code | ||
179 | static_response<1024> res(status::not_found); | ||
180 | @endcode | ||
181 | |||
182 | @par Complexity | ||
183 | Linear in `obsolete_reason(s).size()`. | ||
184 | |||
185 | @par Exception Safety | ||
186 | Exception thrown if max capacity exceeded. | ||
187 | |||
188 | @throw std::length_error | ||
189 | Max capacity would be exceeded. | ||
190 | |||
191 | @param sc The status code. | ||
192 | */ | ||
193 | explicit | ||
194 | 8 | static_response( | |
195 | http_proto::status sc) | ||
196 | : static_response( | ||
197 | 8 | sc, http_proto::version::http_1_1) | |
198 | { | ||
199 | 8 | } | |
200 | |||
201 | /** Constructor. | ||
202 | |||
203 | The newly constructed object contains | ||
204 | a copy of `r`. | ||
205 | |||
206 | @par Postconditions | ||
207 | @code | ||
208 | this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data() | ||
209 | @endcode | ||
210 | |||
211 | @par Complexity | ||
212 | Linear in `r.size()`. | ||
213 | |||
214 | @param r The response to copy. | ||
215 | */ | ||
216 | 2 | static_response( | |
217 | static_response const& r) noexcept | ||
218 | 2 | : fields_view_base(&this->fields_base::h_) | |
219 | 2 | , response_base(*r.ph_, buf_, Capacity) | |
220 | { | ||
221 | 2 | } | |
222 | |||
223 | /** Constructor. | ||
224 | |||
225 | The newly constructed object contains | ||
226 | a copy of `r`. | ||
227 | |||
228 | @par Postconditions | ||
229 | @code | ||
230 | this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data() | ||
231 | @endcode | ||
232 | |||
233 | @par Complexity | ||
234 | Linear in `r.size()`. | ||
235 | |||
236 | @par Exception Safety | ||
237 | Exception thrown if max capacity exceeded. | ||
238 | |||
239 | @throw std::length_error | ||
240 | Max capacity would be exceeded. | ||
241 | |||
242 | @param r The response to copy. | ||
243 | */ | ||
244 | 4 | static_response( | |
245 | response_view const& r) | ||
246 | 4 | : fields_view_base(&this->fields_base::h_) | |
247 | 4 | , response_base(*r.ph_, buf_, Capacity) | |
248 | { | ||
249 | 4 | } | |
250 | |||
251 | /** Assignment. | ||
252 | |||
253 | The contents of `r` are copied and | ||
254 | the previous contents of `this` are | ||
255 | discarded. | ||
256 | |||
257 | @par Postconditions | ||
258 | @code | ||
259 | this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() | ||
260 | @endcode | ||
261 | |||
262 | @par Complexity | ||
263 | Linear in `r.size()`. | ||
264 | |||
265 | @param r The response to copy. | ||
266 | |||
267 | @return A reference to this object. | ||
268 | */ | ||
269 | static_response& | ||
270 | 1 | operator=( | |
271 | static_response const& r) noexcept | ||
272 | { | ||
273 | 1 | copy_impl(*r.ph_); | |
274 | 1 | return *this; | |
275 | } | ||
276 | |||
277 | /** Assignment. | ||
278 | |||
279 | The contents of `r` are copied and | ||
280 | the previous contents of `this` are | ||
281 | discarded. | ||
282 | |||
283 | @par Postconditions | ||
284 | @code | ||
285 | this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() | ||
286 | @endcode | ||
287 | |||
288 | @par Complexity | ||
289 | Linear in `r.size()`. | ||
290 | |||
291 | @par Exception Safety | ||
292 | Strong guarantee. | ||
293 | Exception thrown if max capacity exceeded. | ||
294 | |||
295 | @throw std::length_error | ||
296 | Max capacity would be exceeded. | ||
297 | |||
298 | @param r The response to copy. | ||
299 | |||
300 | @return A reference to this object. | ||
301 | */ | ||
302 | static_response& | ||
303 | 1 | operator=( | |
304 | response_view const& r) | ||
305 | { | ||
306 | 1 | copy_impl(*r.ph_); | |
307 | 1 | return *this; | |
308 | } | ||
309 | }; | ||
310 | |||
311 | } // http_proto | ||
312 | } // boost | ||
313 | |||
314 | #endif | ||
315 |