GCC Code Coverage Report


Directory: ./
File: libs/http_proto/include/boost/http_proto/response.hpp
Date: 2025-12-18 06:34:37
Exec Total Coverage
Lines: 58 59 98.3%
Functions: 17 17 100.0%
Branches: 4 5 80.0%

Line Branch Exec Source
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/detail/config.hpp>
16 #include <boost/http_proto/message_base.hpp>
17 #include <boost/http_proto/status.hpp>
18
19 namespace boost {
20 namespace http_proto {
21
22 /** A container for HTTP responses.
23
24 This container owns a response, represented by
25 a buffer which is managed by performing
26 dynamic memory allocations as needed. The
27 contents may be inspected and modified, and
28 the implementation maintains a useful
29 invariant: changes to the response always
30 leave it in a valid state.
31
32 @par Example
33 @code
34 response res(status::not_found);
35
36 res.set(field::server, "Boost.HttpProto");
37 res.set(field::content_type, "text/plain");
38 res.set_content_length(80);
39
40 assert(res.buffer() ==
41 "HTTP/1.1 404 Not Found\r\n"
42 "Server: Boost.HttpProto\r\n"
43 "Content-Type: text/plain\r\n"
44 "Content-Length: 80\r\n"
45 "\r\n");
46 @endcode
47
48 @see
49 @ref response_parser,
50 @ref request.
51 */
52 class response
53 : public message_base
54 {
55 friend class response_parser;
56
57 1 response(
58 view_tag_t,
59 detail::header const& h) noexcept
60 1 : message_base(view_tag, h)
61 {
62 1 }
63
64 public:
65 //--------------------------------------------
66 //
67 // Special Members
68 //
69 //--------------------------------------------
70
71 /** Constructor.
72
73 A default-constructed response contains
74 a valid HTTP 200 OK response with no headers.
75
76 @par Example
77 @code
78 response res;
79 @endcode
80
81 @par Postconditions
82 @code
83 this->buffer() == "HTTP/1.1 200 OK\r\n\r\n"
84 @endcode
85
86 @par Complexity
87 Constant.
88 */
89 99 response() noexcept
90 99 : message_base(detail::kind::response)
91 {
92 99 }
93
94 /** Constructor.
95
96 Constructs a response from the string `s`,
97 which must contain valid HTTP response
98 or else an exception is thrown.
99 The new response retains ownership by
100 making a copy of the passed string.
101
102 @par Example
103 @code
104 response res(
105 "HTTP/1.1 404 Not Found\r\n"
106 "Server: Boost.HttpProto\r\n"
107 "Content-Type: text/plain\r\n"
108 "\r\n");
109 @endcode
110
111 @par Postconditions
112 @code
113 this->buffer.data() != s.data()
114 @endcode
115
116 @par Complexity
117 Linear in `s.size()`.
118
119 @par Exception Safety
120 Calls to allocate may throw.
121 Exception thrown on invalid input.
122
123 @throw system_error
124 The input does not contain a valid response.
125
126 @param s The string to parse.
127 */
128 explicit
129 99 response(
130 core::string_view s)
131 99 : message_base(detail::kind::response, s)
132 {
133 98 }
134
135 /** Constructor.
136
137 Allocates `cap` bytes initially, with an
138 upper limit of `max_cap`. Growing beyond
139 `max_cap` will throw an exception.
140
141 Useful when an estimated initial size is
142 known, but further growth up to a maximum
143 is allowed.
144
145 When `max_cap == cap`, the container
146 guarantees to never allocate.
147
148 @par Preconditions
149 @code
150 max_cap >= cap
151 @endcode
152
153 @par Exception Safety
154 Calls to allocate may throw.
155
156 @param cap Initial capacity in bytes (may be `0`).
157
158 @param max_cap Maximum allowed capacity in bytes.
159 */
160 explicit
161 10 response(
162 std::size_t cap,
163 std::size_t max_cap = std::size_t(-1))
164 10 : response()
165 {
166
1/1
✓ Branch 1 taken 10 times.
10 reserve_bytes(cap);
167
1/1
✓ Branch 1 taken 8 times.
10 set_max_capacity_in_bytes(max_cap);
168 10 }
169
170 /** Constructor.
171
172 The start-line of the response will
173 contain the standard text for the
174 supplied status code and HTTP version.
175
176 @par Example
177 @code
178 response res(status::not_found, version::http_1_0);
179 @endcode
180
181 @par Complexity
182 Linear in `to_string(s).size()`.
183
184 @par Exception Safety
185 Calls to allocate may throw.
186
187 @param sc The status code.
188
189 @param v The HTTP version.
190 */
191 9 response(
192 http_proto::status sc,
193 http_proto::version v)
194 9 : response()
195 {
196
1/1
✓ Branch 1 taken 9 times.
9 set_start_line(sc, v);
197 9 }
198
199 /** Constructor.
200
201 The start-line of the response will
202 contain the standard text for the
203 supplied status code with the HTTP version
204 defaulted to `HTTP/1.1`.
205
206 @par Example
207 @code
208 response res(status::not_found);
209 @endcode
210
211 @par Complexity
212 Linear in `to_string(s).size()`.
213
214 @par Exception Safety
215 Calls to allocate may throw.
216
217 @param sc The status code.
218 */
219 explicit
220 2 response(
221 http_proto::status sc)
222 2 : response(
223 2 sc, http_proto::version::http_1_1)
224 {
225 2 }
226
227 /** Constructor.
228
229 The contents of `r` are transferred
230 to the newly constructed object,
231 which includes the underlying
232 character buffer.
233 After construction, the moved-from
234 object is as if default-constructed.
235
236 @par Postconditions
237 @code
238 r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
239 @endcode
240
241 @par Complexity
242 Constant.
243
244 @param r The response to move from.
245 */
246 3 response(response&& r) noexcept
247 3 : response()
248 {
249 3 swap(r);
250 3 }
251
252 /** Constructor.
253
254 The newly constructed object contains
255 a copy of `r`.
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 @par Exception Safety
266 Calls to allocate may throw.
267
268 @param r The response to copy.
269 */
270 3 response(response const&) = default;
271
272 /** Assignment
273
274 The contents of `r` are transferred to
275 `this`, including the underlying
276 character buffer. The previous contents
277 of `this` are destroyed.
278 After assignment, the moved-from
279 object is as if default-constructed.
280
281 @par Postconditions
282 @code
283 r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
284 @endcode
285
286 @par Complexity
287 Constant.
288
289 @param r The response to assign from.
290
291 @return A reference to this object.
292 */
293 response&
294 1 operator=(
295 response&& r) noexcept
296 {
297 1 response temp(std::move(r));
298 1 temp.swap(*this);
299 2 return *this;
300 1 }
301
302 /** Assignment.
303
304 The contents of `r` are copied and
305 the previous contents of `this` are
306 discarded.
307
308 @par Postconditions
309 @code
310 this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
311 @endcode
312
313 @par Complexity
314 Linear in `r.size()`.
315
316 @par Exception Safety
317 Strong guarantee.
318 Calls to allocate may throw.
319 Exception thrown if max capacity exceeded.
320
321 @throw std::length_error
322 Max capacity would be exceeded.
323
324 @param r The response to copy.
325
326 @return A reference to this object.
327 */
328 response&
329 1 operator=(
330 response const& r)
331 {
332 1 copy_impl(r.h_);
333 1 return *this;
334 }
335
336 //--------------------------------------------
337
338 /** Swap.
339
340 Exchanges the contents of this response
341 with another response. All views,
342 iterators and references remain valid.
343
344 If `this == &other`, this function call has no effect.
345
346 @par Example
347 @code
348 response r1(status::ok);
349 response r2(status::bad_request);
350 r1.swap(r2);
351 assert(r1.buffer() == "HTTP/1.1 400 Bad Request\r\n\r\n" );
352 assert(r2.buffer() == "HTTP/1.1 200 OK\r\n\r\n" );
353 @endcode
354
355 @par Complexity
356 Constant
357
358 @param other The object to swap with
359 */
360 void
361 4 swap(response& other) noexcept
362 {
363 4 h_.swap(other.h_);
364 4 std::swap(max_cap_, other.max_cap_);
365 4 std::swap(view_, other.view_);
366 4 }
367
368 /** Swap.
369
370 Exchanges the contents of `v0` with
371 another `v1`. All views, iterators and
372 references remain valid.
373
374 If `&v0 == &v1`, this function call has no effect.
375
376 @par Example
377 @code
378 response r1(status::ok);
379 response r2(status::bad_request);
380 std::swap(r1, r2);
381 assert(r1.buffer() == "HTTP/1.1 400 Bad Request\r\n\r\n" );
382 assert(r2.buffer() == "HTTP/1.1 200 OK\r\n\r\n" );
383 @endcode
384
385 @par Effects
386 @code
387 v0.swap(v1);
388 @endcode
389
390 @par Complexity
391 Constant.
392
393 @param v0 The first object to swap.
394 @param v1 The second object to swap.
395
396 @see
397 @ref response::swap.
398 */
399 friend
400 void
401 swap(
402 response& v0,
403 response& v1) noexcept
404 {
405 v0.swap(v1);
406 }
407
408 //--------------------------------------------
409 //
410 // Observers
411 //
412 //--------------------------------------------
413
414 /** Return the reason string.
415
416 This field is obsolete in HTTP/1
417 and should only be used for display
418 purposes.
419 */
420 core::string_view
421 26 reason() const noexcept
422 {
423 52 return core::string_view(
424 26 h_.cbuf + 13,
425 26 h_.prefix - 15);
426 }
427
428 /** Return the status code.
429 */
430 http_proto::status
431 26 status() const noexcept
432 {
433 26 return h_.res.status;
434 }
435
436 /** Return the status code as an integral.
437 */
438 unsigned short
439 26 status_int() const noexcept
440 {
441 26 return h_.res.status_int;
442 }
443
444 //--------------------------------------------
445 //
446 // Modifiers
447 //
448 //--------------------------------------------
449
450 /** Set the status code and version of the response.
451
452 The reason-phrase will be set to the
453 standard text for the specified status
454 code.
455
456 This is more efficient than setting the
457 properties individually.
458
459 @par Exception Safety
460 Strong guarantee.
461 Calls to allocate may throw.
462 Exception thrown if max capacity exceeded.
463
464 @throw std::length_error
465 Max capacity would be exceeded.
466 @throw std::invalid_argument
467 `sc == status::unknown`
468
469 @param sc The status code to set. This
470 must not be @ref status::unknown.
471
472 @param v The version to set.
473 */
474 void
475 11 set_start_line(
476 http_proto::status sc,
477 http_proto::version v =
478 http_proto::version::http_1_1)
479 {
480 11 set_start_line_impl(sc,
481 static_cast<unsigned short>(sc),
482 to_string(sc), v);
483 11 }
484
485 /** Set the HTTP version of the response
486
487 @par Exception Safety
488 Strong guarantee.
489 Calls to allocate may throw.
490 Exception thrown if maximum capacity exceeded.
491
492 @throw std::length_error
493 Maximum capacity would be exceeded.
494
495 @param v The version to set.
496 */
497 BOOST_HTTP_PROTO_DECL
498 void
499 set_version(
500 http_proto::version v);
501
502 /** Set the status code of the response.
503
504 The reason-phrase will be set to the
505 standard text for the specified status
506 code. The version will remain unchanged.
507
508 @par Exception Safety
509 Strong guarantee.
510 Calls to allocate may throw.
511 Exception thrown if maximum capacity exceeded.
512
513 @throw std::length_error
514 Maximum capacity would be exceeded.
515 @throw std::invalid_argument
516 `sc == status::unknown`
517
518 @param sc The status code to set. This
519 must not be @ref status::unknown.
520 */
521 void
522 3 set_status(
523 http_proto::status sc)
524 {
525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(sc == http_proto::status::unknown)
526 detail::throw_invalid_argument();
527 3 set_start_line_impl(sc,
528 static_cast<unsigned short>(sc),
529 to_string(sc),
530 version());
531 3 }
532
533 /** Set the status code and version of the response.
534
535 The reason-phrase will be set to the
536 standard text for the specified status
537 code.
538
539 This is more efficient than setting the
540 properties individually.
541
542 @par Exception Safety
543 Strong guarantee.
544 Calls to allocate may throw.
545 Exception thrown on invalid input.
546 Exception thrown if max capacity exceeded.
547
548 @throw system_error
549 Input is invalid.
550
551 @throw std::length_error
552 Max capacity would be exceeded.
553
554 @param si An integral representing the
555 status code to set.
556
557 @param reason A string view representing the
558 reason string to set.
559
560 @param v The version to set.
561 */
562 void
563 8 set_start_line(
564 unsigned short si,
565 core::string_view reason,
566 http_proto::version v =
567 http_proto::version::http_1_1)
568 {
569 8 set_start_line_impl(
570 int_to_status(si),
571 si,
572 reason,
573 v);
574 7 }
575
576 private:
577 BOOST_HTTP_PROTO_DECL
578 void
579 set_start_line_impl(
580 http_proto::status sc,
581 unsigned short si,
582 core::string_view reason,
583 http_proto::version v);
584 };
585
586 } // http_proto
587 } // boost
588
589 #endif
590