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