1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2024 Christian Mazakas
3  
// Copyright (c) 2024 Christian Mazakas
4  
// Copyright (c) 2025 Mohammad Nejati
4  
// Copyright (c) 2025 Mohammad Nejati
5  
//
5  
//
6  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
7  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8  
//
8  
//
9  
// Official repository: https://github.com/cppalliance/http
9  
// Official repository: https://github.com/cppalliance/http
10  
//
10  
//
11  

11  

12  
#ifndef BOOST_HTTP_RESPONSE_HPP
12  
#ifndef BOOST_HTTP_RESPONSE_HPP
13  
#define BOOST_HTTP_RESPONSE_HPP
13  
#define BOOST_HTTP_RESPONSE_HPP
14  

14  

15  
#include <boost/http/response_base.hpp>
15  
#include <boost/http/response_base.hpp>
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace http {
18  
namespace http {
19  

19  

20  
/** A modifiable container for HTTP responses.
20  
/** A modifiable container for HTTP responses.
21  

21  

22  
    This container owns a response, represented by
22  
    This container owns a response, represented by
23  
    a buffer which is managed by performing
23  
    a buffer which is managed by performing
24  
    dynamic memory allocations as needed. The
24  
    dynamic memory allocations as needed. The
25  
    contents may be inspected and modified, and
25  
    contents may be inspected and modified, and
26  
    the implementation maintains a useful
26  
    the implementation maintains a useful
27  
    invariant: changes to the response always
27  
    invariant: changes to the response always
28  
    leave it in a valid state.
28  
    leave it in a valid state.
29  

29  

30  
    @par Example
30  
    @par Example
31  
    @code
31  
    @code
32  
    response res(status::not_found);
32  
    response res(status::not_found);
33  

33  

34  
    res.set(field::server, "Boost.HTTP");
34  
    res.set(field::server, "Boost.HTTP");
35  
    res.set(field::content_type, "text/plain");
35  
    res.set(field::content_type, "text/plain");
36  
    res.set_content_length(80);
36  
    res.set_content_length(80);
37  

37  

38  
    assert(res.buffer() ==
38  
    assert(res.buffer() ==
39  
        "HTTP/1.1 404 Not Found\r\n"
39  
        "HTTP/1.1 404 Not Found\r\n"
40  
        "Server: Boost.HTTP\r\n"
40  
        "Server: Boost.HTTP\r\n"
41  
        "Content-Type: text/plain\r\n"
41  
        "Content-Type: text/plain\r\n"
42  
        "Content-Length: 80\r\n"
42  
        "Content-Length: 80\r\n"
43  
        "\r\n");
43  
        "\r\n");
44  
    @endcode
44  
    @endcode
45  

45  

46  
    @see
46  
    @see
47  
        @ref static_response,
47  
        @ref static_response,
48  
        @ref response_base.
48  
        @ref response_base.
49  
*/
49  
*/
50  
class response
50  
class response
51  
    : public response_base
51  
    : public response_base
52  
{
52  
{
53  
public:
53  
public:
54  
    //--------------------------------------------
54  
    //--------------------------------------------
55  
    //
55  
    //
56  
    // Special Members
56  
    // Special Members
57  
    //
57  
    //
58  
    //--------------------------------------------
58  
    //--------------------------------------------
59  

59  

60  
    /** Constructor.
60  
    /** Constructor.
61  

61  

62  
        A default-constructed response contains
62  
        A default-constructed response contains
63  
        a valid HTTP 200 OK response with no headers.
63  
        a valid HTTP 200 OK response with no headers.
64  

64  

65  
        @par Example
65  
        @par Example
66  
        @code
66  
        @code
67  
        response res;
67  
        response res;
68  
        @endcode
68  
        @endcode
69  

69  

70  
        @par Postconditions
70  
        @par Postconditions
71  
        @code
71  
        @code
72  
        this->buffer() == "HTTP/1.1 200 OK\r\n\r\n"
72  
        this->buffer() == "HTTP/1.1 200 OK\r\n\r\n"
73  
        @endcode
73  
        @endcode
74  

74  

75  
        @par Complexity
75  
        @par Complexity
76  
        Constant.
76  
        Constant.
77  
    */
77  
    */
78  
    response() noexcept = default;
78  
    response() noexcept = default;
79  

79  

80  
    /** Constructor.
80  
    /** Constructor.
81  

81  

82  
        Constructs a response from the string `s`,
82  
        Constructs a response from the string `s`,
83  
        which must contain valid HTTP response
83  
        which must contain valid HTTP response
84  
        or else an exception is thrown.
84  
        or else an exception is thrown.
85  
        The new response retains ownership by
85  
        The new response retains ownership by
86  
        making a copy of the passed string.
86  
        making a copy of the passed string.
87  

87  

88  
        @par Example
88  
        @par Example
89  
        @code
89  
        @code
90  
        response res(
90  
        response res(
91  
            "HTTP/1.1 404 Not Found\r\n"
91  
            "HTTP/1.1 404 Not Found\r\n"
92  
            "Server: Boost.HTTP\r\n"
92  
            "Server: Boost.HTTP\r\n"
93  
            "Content-Type: text/plain\r\n"
93  
            "Content-Type: text/plain\r\n"
94  
            "\r\n");
94  
            "\r\n");
95  
        @endcode
95  
        @endcode
96  

96  

97  
        @par Postconditions
97  
        @par Postconditions
98  
        @code
98  
        @code
99  
        this->buffer.data() != s.data()
99  
        this->buffer.data() != s.data()
100  
        @endcode
100  
        @endcode
101  

101  

102  
        @par Complexity
102  
        @par Complexity
103  
        Linear in `s.size()`.
103  
        Linear in `s.size()`.
104  

104  

105  
        @par Exception Safety
105  
        @par Exception Safety
106  
        Calls to allocate may throw.
106  
        Calls to allocate may throw.
107  
        Exception thrown on invalid input.
107  
        Exception thrown on invalid input.
108  

108  

109  
        @throw system_error
109  
        @throw system_error
110  
        The input does not contain a valid response.
110  
        The input does not contain a valid response.
111  

111  

112  
        @param s The string to parse.
112  
        @param s The string to parse.
113  
    */
113  
    */
114  
    explicit
114  
    explicit
115  
    response(
115  
    response(
116  
        core::string_view s)
116  
        core::string_view s)
117  
        : response_base(s)
117  
        : response_base(s)
118  
    {
118  
    {
119  
    }
119  
    }
120  

120  

121  
    /** Constructor.
121  
    /** Constructor.
122  

122  

123  
        Allocates `cap` bytes initially, with an
123  
        Allocates `cap` bytes initially, with an
124  
        upper limit of `max_cap`. Growing beyond
124  
        upper limit of `max_cap`. Growing beyond
125  
        `max_cap` will throw an exception.
125  
        `max_cap` will throw an exception.
126  

126  

127  
        Useful when an estimated initial size is
127  
        Useful when an estimated initial size is
128  
        known, but further growth up to a maximum
128  
        known, but further growth up to a maximum
129  
        is allowed.
129  
        is allowed.
130  

130  

131  
        When `max_cap == cap`, the container
131  
        When `max_cap == cap`, the container
132  
        guarantees to never allocate.
132  
        guarantees to never allocate.
133  

133  

134  
        @par Preconditions
134  
        @par Preconditions
135  
        @code
135  
        @code
136  
        max_cap >= cap
136  
        max_cap >= cap
137  
        @endcode
137  
        @endcode
138  

138  

139  
        @par Exception Safety
139  
        @par Exception Safety
140  
        Calls to allocate may throw.
140  
        Calls to allocate may throw.
141  

141  

142  
        @param cap Initial capacity in bytes (may be `0`).
142  
        @param cap Initial capacity in bytes (may be `0`).
143  

143  

144  
        @param max_cap Maximum allowed capacity in bytes.
144  
        @param max_cap Maximum allowed capacity in bytes.
145  
    */
145  
    */
146  
    explicit
146  
    explicit
147  
    response(
147  
    response(
148  
        std::size_t cap,
148  
        std::size_t cap,
149  
        std::size_t max_cap = std::size_t(-1))
149  
        std::size_t max_cap = std::size_t(-1))
150  
        : response()
150  
        : response()
151  
    {
151  
    {
152  
        reserve_bytes(cap);
152  
        reserve_bytes(cap);
153  
        set_max_capacity_in_bytes(max_cap);
153  
        set_max_capacity_in_bytes(max_cap);
154  
    }
154  
    }
155  

155  

156  
    /** Constructor.
156  
    /** Constructor.
157  

157  

158  
        The start-line of the response will
158  
        The start-line of the response will
159  
        contain the standard text for the
159  
        contain the standard text for the
160  
        supplied status code and HTTP version.
160  
        supplied status code and HTTP version.
161  

161  

162  
        @par Example
162  
        @par Example
163  
        @code
163  
        @code
164  
        response res(status::not_found, version::http_1_0);
164  
        response res(status::not_found, version::http_1_0);
165  
        @endcode
165  
        @endcode
166  

166  

167  
        @par Complexity
167  
        @par Complexity
168  
        Linear in `to_string(s).size()`.
168  
        Linear in `to_string(s).size()`.
169  

169  

170  
        @par Exception Safety
170  
        @par Exception Safety
171  
        Calls to allocate may throw.
171  
        Calls to allocate may throw.
172  

172  

173  
        @param sc The status code.
173  
        @param sc The status code.
174  

174  

175  
        @param v The HTTP version.
175  
        @param v The HTTP version.
176  
    */
176  
    */
177  
    response(
177  
    response(
178  
        http::status sc,
178  
        http::status sc,
179  
        http::version v)
179  
        http::version v)
180  
        : response()
180  
        : response()
181  
    {
181  
    {
182  
        set_start_line(sc, v);
182  
        set_start_line(sc, v);
183  
    }
183  
    }
184  

184  

185  
    /** Constructor.
185  
    /** Constructor.
186  

186  

187  
        The start-line of the response will
187  
        The start-line of the response will
188  
        contain the standard text for the
188  
        contain the standard text for the
189  
        supplied status code with the HTTP version
189  
        supplied status code with the HTTP version
190  
        defaulted to `HTTP/1.1`.
190  
        defaulted to `HTTP/1.1`.
191  

191  

192  
        @par Example
192  
        @par Example
193  
        @code
193  
        @code
194  
        response res(status::not_found);
194  
        response res(status::not_found);
195  
        @endcode
195  
        @endcode
196  

196  

197  
        @par Complexity
197  
        @par Complexity
198  
        Linear in `to_string(s).size()`.
198  
        Linear in `to_string(s).size()`.
199  

199  

200  
        @par Exception Safety
200  
        @par Exception Safety
201  
        Calls to allocate may throw.
201  
        Calls to allocate may throw.
202  

202  

203  
        @param sc The status code.
203  
        @param sc The status code.
204  
    */
204  
    */
205  
    explicit
205  
    explicit
206  
    response(
206  
    response(
207  
        http::status sc)
207  
        http::status sc)
208  
        : response(
208  
        : response(
209  
            sc, http::version::http_1_1)
209  
            sc, http::version::http_1_1)
210  
    {
210  
    {
211  
    }
211  
    }
212  

212  

213  
    /** Constructor.
213  
    /** Constructor.
214  

214  

215  
        The contents of `r` are transferred
215  
        The contents of `r` are transferred
216  
        to the newly constructed object,
216  
        to the newly constructed object,
217  
        which includes the underlying
217  
        which includes the underlying
218  
        character buffer.
218  
        character buffer.
219  
        After construction, the moved-from
219  
        After construction, the moved-from
220  
        object is as if default-constructed.
220  
        object is as if default-constructed.
221  

221  

222  
        @par Postconditions
222  
        @par Postconditions
223  
        @code
223  
        @code
224  
        r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
224  
        r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
225  
        @endcode
225  
        @endcode
226  

226  

227  
        @par Complexity
227  
        @par Complexity
228  
        Constant.
228  
        Constant.
229  

229  

230  
        @param r The response to move from.
230  
        @param r The response to move from.
231  
    */
231  
    */
232  
    response(response&& r) noexcept
232  
    response(response&& r) noexcept
233  
        : response()
233  
        : response()
234  
    {
234  
    {
235  
        swap(r);
235  
        swap(r);
236  
    }
236  
    }
237  

237  

238  
    /** Constructor.
238  
    /** Constructor.
239  

239  

240  
        The newly constructed object contains
240  
        The newly constructed object contains
241  
        a copy of `r`.
241  
        a copy of `r`.
242  

242  

243  
        @par Postconditions
243  
        @par Postconditions
244  
        @code
244  
        @code
245  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
245  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
246  
        @endcode
246  
        @endcode
247  

247  

248  
        @par Complexity
248  
        @par Complexity
249  
        Linear in `r.size()`.
249  
        Linear in `r.size()`.
250  

250  

251  
        @par Exception Safety
251  
        @par Exception Safety
252  
        Calls to allocate may throw.
252  
        Calls to allocate may throw.
253  

253  

254  
        @param r The response to copy.
254  
        @param r The response to copy.
255  
    */
255  
    */
256  
    response(response const&) = default;
256  
    response(response const&) = default;
257  

257  

258  
    /** Constructor.
258  
    /** Constructor.
259  

259  

260  
        The newly constructed object contains
260  
        The newly constructed object contains
261  
        a copy of `r`.
261  
        a copy of `r`.
262  

262  

263  
        @par Postconditions
263  
        @par Postconditions
264  
        @code
264  
        @code
265  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
265  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
266  
        @endcode
266  
        @endcode
267  

267  

268  
        @par Complexity
268  
        @par Complexity
269  
        Linear in `r.size()`.
269  
        Linear in `r.size()`.
270  

270  

271  
        @par Exception Safety
271  
        @par Exception Safety
272  
        Calls to allocate may throw.
272  
        Calls to allocate may throw.
273  

273  

274  
        @param r The response to copy.
274  
        @param r The response to copy.
275  
    */
275  
    */
276  
    response(response_base const& r)
276  
    response(response_base const& r)
277  
        : response_base(r)
277  
        : response_base(r)
278  
    {
278  
    {
279  
    }
279  
    }
280  

280  

281  
    /** Assignment
281  
    /** Assignment
282  

282  

283  
        The contents of `r` are transferred to
283  
        The contents of `r` are transferred to
284  
        `this`, including the underlying
284  
        `this`, including the underlying
285  
        character buffer. The previous contents
285  
        character buffer. The previous contents
286  
        of `this` are destroyed.
286  
        of `this` are destroyed.
287  
        After assignment, the moved-from
287  
        After assignment, the moved-from
288  
        object is as if default-constructed.
288  
        object is as if default-constructed.
289  

289  

290  
        @par Postconditions
290  
        @par Postconditions
291  
        @code
291  
        @code
292  
        r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
292  
        r.buffer() == "HTTP/1.1 200 OK\r\n\r\n"
293  
        @endcode
293  
        @endcode
294  

294  

295  
        @par Complexity
295  
        @par Complexity
296  
        Constant.
296  
        Constant.
297  

297  

298  
        @param r The response to assign from.
298  
        @param r The response to assign from.
299  

299  

300  
        @return A reference to this object.
300  
        @return A reference to this object.
301  
    */
301  
    */
302  
    response&
302  
    response&
303  
    operator=(
303  
    operator=(
304  
        response&& r) noexcept
304  
        response&& r) noexcept
305  
    {
305  
    {
306  
        response temp(std::move(r));
306  
        response temp(std::move(r));
307  
        temp.swap(*this);
307  
        temp.swap(*this);
308  
        return *this;
308  
        return *this;
309  
    }
309  
    }
310  

310  

311  
    /** Assignment.
311  
    /** Assignment.
312  

312  

313  
        The contents of `r` are copied and
313  
        The contents of `r` are copied and
314  
        the previous contents of `this` are
314  
        the previous contents of `this` are
315  
        discarded.
315  
        discarded.
316  

316  

317  
        @par Postconditions
317  
        @par Postconditions
318  
        @code
318  
        @code
319  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
319  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
320  
        @endcode
320  
        @endcode
321  

321  

322  
        @par Complexity
322  
        @par Complexity
323  
        Linear in `r.size()`.
323  
        Linear in `r.size()`.
324  

324  

325  
        @par Exception Safety
325  
        @par Exception Safety
326  
        Strong guarantee.
326  
        Strong guarantee.
327  
        Calls to allocate may throw.
327  
        Calls to allocate may throw.
328  
        Exception thrown if max capacity exceeded.
328  
        Exception thrown if max capacity exceeded.
329  

329  

330  
        @throw std::length_error
330  
        @throw std::length_error
331  
        Max capacity would be exceeded.
331  
        Max capacity would be exceeded.
332  

332  

333  
        @param r The response to copy.
333  
        @param r The response to copy.
334  

334  

335  
        @return A reference to this object.
335  
        @return A reference to this object.
336  
    */
336  
    */
337  
    response&
337  
    response&
338  
    operator=(
338  
    operator=(
339  
        response const& r)
339  
        response const& r)
340  
    {
340  
    {
341  
        copy_impl(r.h_);
341  
        copy_impl(r.h_);
342  
        return *this;
342  
        return *this;
343  
    }
343  
    }
344  

344  

345  
    /** Assignment.
345  
    /** Assignment.
346  

346  

347  
        The contents of `r` are copied and
347  
        The contents of `r` are copied and
348  
        the previous contents of `this` are
348  
        the previous contents of `this` are
349  
        discarded.
349  
        discarded.
350  

350  

351  
        @par Postconditions
351  
        @par Postconditions
352  
        @code
352  
        @code
353  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
353  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
354  
        @endcode
354  
        @endcode
355  

355  

356  
        @par Complexity
356  
        @par Complexity
357  
        Linear in `r.size()`.
357  
        Linear in `r.size()`.
358  

358  

359  
        @par Exception Safety
359  
        @par Exception Safety
360  
        Strong guarantee.
360  
        Strong guarantee.
361  
        Calls to allocate may throw.
361  
        Calls to allocate may throw.
362  
        Exception thrown if max capacity exceeded.
362  
        Exception thrown if max capacity exceeded.
363  

363  

364  
        @throw std::length_error
364  
        @throw std::length_error
365  
        Max capacity would be exceeded.
365  
        Max capacity would be exceeded.
366  

366  

367  
        @param r The response to copy.
367  
        @param r The response to copy.
368  

368  

369  
        @return A reference to this object.
369  
        @return A reference to this object.
370  
    */
370  
    */
371  
    response&
371  
    response&
372  
    operator=(
372  
    operator=(
373  
        response_base const& r)
373  
        response_base const& r)
374  
    {
374  
    {
375  
        copy_impl(r.h_);
375  
        copy_impl(r.h_);
376  
        return *this;
376  
        return *this;
377  
    }
377  
    }
378  

378  

379  
    //--------------------------------------------
379  
    //--------------------------------------------
380  

380  

381  
    /** Swap.
381  
    /** Swap.
382  

382  

383  
        Exchanges the contents of this response
383  
        Exchanges the contents of this response
384  
        with another response. All views,
384  
        with another response. All views,
385  
        iterators and references remain valid.
385  
        iterators and references remain valid.
386  

386  

387  
        If `this == &other`, this function call has no effect.
387  
        If `this == &other`, this function call has no effect.
388  

388  

389  
        @par Example
389  
        @par Example
390  
        @code
390  
        @code
391  
        response r1(status::ok);
391  
        response r1(status::ok);
392  
        response r2(status::bad_request);
392  
        response r2(status::bad_request);
393  
        r1.swap(r2);
393  
        r1.swap(r2);
394  
        assert(r1.buffer() == "HTTP/1.1 400 Bad Request\r\n\r\n" );
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" );
395  
        assert(r2.buffer() == "HTTP/1.1 200 OK\r\n\r\n" );
396  
        @endcode
396  
        @endcode
397  

397  

398  
        @par Complexity
398  
        @par Complexity
399  
        Constant
399  
        Constant
400  

400  

401  
        @param other The object to swap with
401  
        @param other The object to swap with
402  
    */
402  
    */
403  
    void
403  
    void
404  
    swap(response& other) noexcept
404  
    swap(response& other) noexcept
405  
    {
405  
    {
406  
        h_.swap(other.h_);
406  
        h_.swap(other.h_);
407  
        std::swap(max_cap_, other.max_cap_);
407  
        std::swap(max_cap_, other.max_cap_);
408  
    }
408  
    }
409  

409  

410  
    /** Swap.
410  
    /** Swap.
411  

411  

412  
        Exchanges the contents of `v0` with
412  
        Exchanges the contents of `v0` with
413  
        another `v1`. All views, iterators and
413  
        another `v1`. All views, iterators and
414  
        references remain valid.
414  
        references remain valid.
415  

415  

416  
        If `&v0 == &v1`, this function call has no effect.
416  
        If `&v0 == &v1`, this function call has no effect.
417  

417  

418  
        @par Example
418  
        @par Example
419  
        @code
419  
        @code
420  
        response r1(status::ok);
420  
        response r1(status::ok);
421  
        response r2(status::bad_request);
421  
        response r2(status::bad_request);
422  
        std::swap(r1, r2);
422  
        std::swap(r1, r2);
423  
        assert(r1.buffer() == "HTTP/1.1 400 Bad Request\r\n\r\n" );
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" );
424  
        assert(r2.buffer() == "HTTP/1.1 200 OK\r\n\r\n" );
425  
        @endcode
425  
        @endcode
426  

426  

427  
        @par Effects
427  
        @par Effects
428  
        @code
428  
        @code
429  
        v0.swap(v1);
429  
        v0.swap(v1);
430  
        @endcode
430  
        @endcode
431  

431  

432  
        @par Complexity
432  
        @par Complexity
433  
        Constant.
433  
        Constant.
434  

434  

435  
        @param v0 The first object to swap.
435  
        @param v0 The first object to swap.
436  
        @param v1 The second object to swap.
436  
        @param v1 The second object to swap.
437  

437  

438  
        @see
438  
        @see
439  
            @ref response::swap.
439  
            @ref response::swap.
440  
    */
440  
    */
441  
    friend
441  
    friend
442  
    void
442  
    void
443  
    swap(
443  
    swap(
444  
        response& v0,
444  
        response& v0,
445  
        response& v1) noexcept
445  
        response& v1) noexcept
446  
    {
446  
    {
447  
        v0.swap(v1);
447  
        v0.swap(v1);
448  
    }
448  
    }
449  
};
449  
};
450  

450  

451  
} // http
451  
} // http
452  
} // boost
452  
} // boost
453  

453  

454  
#endif
454  
#endif