Line data Source code
1 : //
2 : // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2024 Christian Mazakas
4 : // Copyright (c) 2025 Mohammad Nejati
5 : //
6 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 : //
9 : // Official repository: https://github.com/cppalliance/http_proto
10 : //
11 :
12 : #ifndef BOOST_HTTP_PROTO_RESPONSE_HPP
13 : #define BOOST_HTTP_PROTO_RESPONSE_HPP
14 :
15 : #include <boost/http_proto/response_base.hpp>
16 :
17 : namespace boost {
18 : namespace http_proto {
19 :
20 : /** A modifiable container for HTTP responses.
21 :
22 : This container owns a response, represented by
23 : a buffer which is managed by performing
24 : dynamic memory allocations as needed. The
25 : contents may be inspected and modified, and
26 : the implementation maintains a useful
27 : invariant: changes to the response always
28 : leave it in a valid state.
29 :
30 : @par Example
31 : @code
32 : response res(status::not_found);
33 :
34 : res.set(field::server, "Boost.HttpProto");
35 : res.set(field::content_type, "text/plain");
36 : res.set_content_length(80);
37 :
38 : assert(res.buffer() ==
39 : "HTTP/1.1 404 Not Found\r\n"
40 : "Server: Boost.HttpProto\r\n"
41 : "Content-Type: text/plain\r\n"
42 : "Content-Length: 80\r\n"
43 : "\r\n");
44 : @endcode
45 :
46 : @see
47 : @ref static_response,
48 : @ref response_base.
49 : */
50 : class response
51 : : public response_base
52 : {
53 : public:
54 : //--------------------------------------------
55 : //
56 : // Special Members
57 : //
58 : //--------------------------------------------
59 :
60 : /** Constructor.
61 :
62 : A default-constructed response contains
63 : a valid HTTP 200 OK response with no headers.
64 :
65 : @par Example
66 : @code
67 : response res;
68 : @endcode
69 :
70 : @par Postconditions
71 : @code
72 : this->buffer() == "HTTP/1.1 200 OK\r\n\r\n"
73 : @endcode
74 :
75 : @par Complexity
76 : Constant.
77 : */
78 99 : response() noexcept = default;
79 :
80 : /** Constructor.
81 :
82 : Constructs a response from the string `s`,
83 : which must contain valid HTTP response
84 : or else an exception is thrown.
85 : The new response retains ownership by
86 : making a copy of the passed string.
87 :
88 : @par Example
89 : @code
90 : response res(
91 : "HTTP/1.1 404 Not Found\r\n"
92 : "Server: Boost.HttpProto\r\n"
93 : "Content-Type: text/plain\r\n"
94 : "\r\n");
95 : @endcode
96 :
97 : @par Postconditions
98 : @code
99 : this->buffer.data() != s.data()
100 : @endcode
101 :
102 : @par Complexity
103 : Linear in `s.size()`.
104 :
105 : @par Exception Safety
106 : Calls to allocate may throw.
107 : Exception thrown on invalid input.
108 :
109 : @throw system_error
110 : The input does not contain a valid response.
111 :
112 : @param s The string to parse.
113 : */
114 : explicit
115 100 : response(
116 : core::string_view s)
117 100 : : response_base(s)
118 : {
119 99 : }
120 :
121 : /** Constructor.
122 :
123 : Allocates `cap` bytes initially, with an
124 : upper limit of `max_cap`. Growing beyond
125 : `max_cap` will throw an exception.
126 :
127 : Useful when an estimated initial size is
128 : known, but further growth up to a maximum
129 : is allowed.
130 :
131 : When `max_cap == cap`, the container
132 : guarantees to never allocate.
133 :
134 : @par Preconditions
135 : @code
136 : max_cap >= cap
137 : @endcode
138 :
139 : @par Exception Safety
140 : Calls to allocate may throw.
141 :
142 : @param cap Initial capacity in bytes (may be `0`).
143 :
144 : @param max_cap Maximum allowed capacity in bytes.
145 : */
146 : explicit
147 10 : response(
148 : std::size_t cap,
149 : std::size_t max_cap = std::size_t(-1))
150 10 : : response()
151 : {
152 10 : reserve_bytes(cap);
153 10 : set_max_capacity_in_bytes(max_cap);
154 10 : }
155 :
156 : /** Constructor.
157 :
158 : The start-line of the response will
159 : contain the standard text for the
160 : supplied status code and HTTP version.
161 :
162 : @par Example
163 : @code
164 : response res(status::not_found, version::http_1_0);
165 : @endcode
166 :
167 : @par Complexity
168 : Linear in `obsolete_reason(s).size()`.
169 :
170 : @par Exception Safety
171 : Calls to allocate may throw.
172 :
173 : @param sc The status code.
174 :
175 : @param v The HTTP version.
176 : */
177 11 : response(
178 : http_proto::status sc,
179 : http_proto::version v)
180 11 : : response()
181 : {
182 11 : set_start_line(sc, v);
183 11 : }
184 :
185 : /** Constructor.
186 :
187 : The start-line of the response will
188 : contain the standard text for the
189 : supplied status code with the HTTP version
190 : defaulted to `HTTP/1.1`.
191 :
192 : @par Example
193 : @code
194 : response res(status::not_found);
195 : @endcode
196 :
197 : @par Complexity
198 : Linear in `obsolete_reason(s).size()`.
199 :
200 : @par Exception Safety
201 : Calls to allocate may throw.
202 :
203 : @param sc The status code.
204 : */
205 : explicit
206 2 : response(
207 : http_proto::status sc)
208 2 : : response(
209 2 : sc, http_proto::version::http_1_1)
210 : {
211 2 : }
212 :
213 : /** Constructor.
214 :
215 : The contents of `r` are transferred
216 : to the newly constructed object,
217 : which includes the underlying
218 : character buffer.
219 : After construction, the moved-from
220 : object is as if default-constructed.
221 :
222 : @par Postconditions
223 : @code
224 : r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
225 : @endcode
226 :
227 : @par Complexity
228 : Constant.
229 :
230 : @param r The response to move from.
231 : */
232 3 : response(response&& r) noexcept
233 3 : : response()
234 : {
235 3 : swap(r);
236 3 : }
237 :
238 : /** Constructor.
239 :
240 : The newly constructed object contains
241 : a copy of `r`.
242 :
243 : @par Postconditions
244 : @code
245 : this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
246 : @endcode
247 :
248 : @par Complexity
249 : Linear in `r.size()`.
250 :
251 : @par Exception Safety
252 : Calls to allocate may throw.
253 :
254 : @param r The response to copy.
255 : */
256 3 : response(response const&) = default;
257 :
258 : /** Constructor.
259 :
260 : The newly constructed object contains
261 : a copy of `r`.
262 :
263 : @par Postconditions
264 : @code
265 : this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
266 : @endcode
267 :
268 : @par Complexity
269 : Linear in `r.size()`.
270 :
271 : @par Exception Safety
272 : Calls to allocate may throw.
273 :
274 : @param r The response to copy.
275 : */
276 4 : response(response_base const& r)
277 4 : : response_base(r)
278 : {
279 4 : }
280 :
281 : /** Assignment
282 :
283 : The contents of `r` are transferred to
284 : `this`, including the underlying
285 : character buffer. The previous contents
286 : of `this` are destroyed.
287 : After assignment, the moved-from
288 : object is as if default-constructed.
289 :
290 : @par Postconditions
291 : @code
292 : r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
293 : @endcode
294 :
295 : @par Complexity
296 : Constant.
297 :
298 : @param r The response to assign from.
299 :
300 : @return A reference to this object.
301 : */
302 : response&
303 1 : operator=(
304 : response&& r) noexcept
305 : {
306 1 : response temp(std::move(r));
307 1 : temp.swap(*this);
308 2 : return *this;
309 1 : }
310 :
311 : /** Assignment.
312 :
313 : The contents of `r` are copied and
314 : the previous contents of `this` are
315 : discarded.
316 :
317 : @par Postconditions
318 : @code
319 : this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
320 : @endcode
321 :
322 : @par Complexity
323 : Linear in `r.size()`.
324 :
325 : @par Exception Safety
326 : Strong guarantee.
327 : Calls to allocate may throw.
328 : Exception thrown if max capacity exceeded.
329 :
330 : @throw std::length_error
331 : Max capacity would be exceeded.
332 :
333 : @param r The response to copy.
334 :
335 : @return A reference to this object.
336 : */
337 : response&
338 1 : operator=(
339 : response const& r)
340 : {
341 1 : copy_impl(r.h_);
342 1 : return *this;
343 : }
344 :
345 : /** Assignment.
346 :
347 : The contents of `r` are copied and
348 : the previous contents of `this` are
349 : discarded.
350 :
351 : @par Postconditions
352 : @code
353 : this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
354 : @endcode
355 :
356 : @par Complexity
357 : Linear in `r.size()`.
358 :
359 : @par Exception Safety
360 : Strong guarantee.
361 : Calls to allocate may throw.
362 : Exception thrown if max capacity exceeded.
363 :
364 : @throw std::length_error
365 : Max capacity would be exceeded.
366 :
367 : @param r The response to copy.
368 :
369 : @return A reference to this object.
370 : */
371 : response&
372 1 : operator=(
373 : response_base const& r)
374 : {
375 1 : copy_impl(r.h_);
376 1 : return *this;
377 : }
378 :
379 : //--------------------------------------------
380 :
381 : /** Swap.
382 :
383 : Exchanges the contents of this response
384 : with another response. All views,
385 : iterators and references remain valid.
386 :
387 : If `this == &other`, this function call has no effect.
388 :
389 : @par Example
390 : @code
391 : response r1(status::ok);
392 : response r2(status::bad_request);
393 : r1.swap(r2);
394 : assert(r1.buffer() == "HTTP/1.1 400 Bad Request\r\n\r\n" );
395 : assert(r2.buffer() == "HTTP/1.1 200 OK\r\n\r\n" );
396 : @endcode
397 :
398 : @par Complexity
399 : Constant
400 :
401 : @param other The object to swap with
402 : */
403 : void
404 4 : swap(response& other) noexcept
405 : {
406 4 : h_.swap(other.h_);
407 4 : std::swap(max_cap_, other.max_cap_);
408 4 : }
409 :
410 : /** Swap.
411 :
412 : Exchanges the contents of `v0` with
413 : another `v1`. All views, iterators and
414 : references remain valid.
415 :
416 : If `&v0 == &v1`, this function call has no effect.
417 :
418 : @par Example
419 : @code
420 : response r1(status::ok);
421 : response r2(status::bad_request);
422 : std::swap(r1, r2);
423 : assert(r1.buffer() == "HTTP/1.1 400 Bad Request\r\n\r\n" );
424 : assert(r2.buffer() == "HTTP/1.1 200 OK\r\n\r\n" );
425 : @endcode
426 :
427 : @par Effects
428 : @code
429 : v0.swap(v1);
430 : @endcode
431 :
432 : @par Complexity
433 : Constant.
434 :
435 : @param v0 The first object to swap.
436 : @param v1 The second object to swap.
437 :
438 : @see
439 : @ref response::swap.
440 : */
441 : friend
442 : void
443 : swap(
444 : response& v0,
445 : response& v1) noexcept
446 : {
447 : v0.swap(v1);
448 : }
449 : };
450 :
451 : } // http_proto
452 : } // boost
453 :
454 : #endif
|