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

9  

10  
#ifndef BOOST_HTTP_REQUEST_HPP
10  
#ifndef BOOST_HTTP_REQUEST_HPP
11  
#define BOOST_HTTP_REQUEST_HPP
11  
#define BOOST_HTTP_REQUEST_HPP
12  

12  

13  
#include <boost/http/request_base.hpp>
13  
#include <boost/http/request_base.hpp>
14  

14  

15  
namespace boost {
15  
namespace boost {
16  
namespace http {
16  
namespace http {
17  

17  

18  
/** A modifiable container for HTTP requests.
18  
/** A modifiable container for HTTP requests.
19  

19  

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

27  

28  
    @par Example
28  
    @par Example
29  
    @code
29  
    @code
30  
    request req(method::get, "/");
30  
    request req(method::get, "/");
31  

31  

32  
    req.set(field::host, "example.com");
32  
    req.set(field::host, "example.com");
33  
    req.set(field::accept_encoding, "gzip, deflate, br");
33  
    req.set(field::accept_encoding, "gzip, deflate, br");
34  
    req.set(field::cache_control, "no-cache");
34  
    req.set(field::cache_control, "no-cache");
35  

35  

36  
    assert(req.buffer() ==
36  
    assert(req.buffer() ==
37  
    "GET / HTTP/1.1\r\n"
37  
    "GET / HTTP/1.1\r\n"
38  
    "Host: example.com\r\n"
38  
    "Host: example.com\r\n"
39  
    "Accept-Encoding: gzip, deflate, br\r\n"
39  
    "Accept-Encoding: gzip, deflate, br\r\n"
40  
    "Cache-Control: no-cache\r\n"
40  
    "Cache-Control: no-cache\r\n"
41  
    "\r\n");
41  
    "\r\n");
42  
    @endcode
42  
    @endcode
43  

43  

44  
    @see
44  
    @see
45  
        @ref static_request,
45  
        @ref static_request,
46  
        @ref request_base.
46  
        @ref request_base.
47  
*/
47  
*/
48  
class request
48  
class request
49  
    : public request_base
49  
    : public request_base
50  
{
50  
{
51  
public:
51  
public:
52  
    //--------------------------------------------
52  
    //--------------------------------------------
53  
    //
53  
    //
54  
    // Special Members
54  
    // Special Members
55  
    //
55  
    //
56  
    //--------------------------------------------
56  
    //--------------------------------------------
57  

57  

58  
    /** Constructor.
58  
    /** Constructor.
59  

59  

60  
        A default-constructed request contains
60  
        A default-constructed request contains
61  
        a valid HTTP `GET` request with no headers.
61  
        a valid HTTP `GET` request with no headers.
62  

62  

63  
        @par Example
63  
        @par Example
64  
        @code
64  
        @code
65  
        request req;
65  
        request req;
66  
        @endcode
66  
        @endcode
67  

67  

68  
        @par Postconditions
68  
        @par Postconditions
69  
        @code
69  
        @code
70  
        this->buffer() == "GET / HTTP/1.1\r\n\r\n"
70  
        this->buffer() == "GET / HTTP/1.1\r\n\r\n"
71  
        @endcode
71  
        @endcode
72  

72  

73  
        @par Complexity
73  
        @par Complexity
74  
        Constant.
74  
        Constant.
75  
    */
75  
    */
76  
    request() noexcept = default;
76  
    request() noexcept = default;
77  

77  

78  
    /** Constructor.
78  
    /** Constructor.
79  

79  

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

85  

86  
        @par Example
86  
        @par Example
87  
        @code
87  
        @code
88  
        request req(
88  
        request req(
89  
            "GET / HTTP/1.1\r\n"
89  
            "GET / HTTP/1.1\r\n"
90  
            "Accept-Encoding: gzip, deflate, br\r\n"
90  
            "Accept-Encoding: gzip, deflate, br\r\n"
91  
            "Cache-Control: no-cache\r\n"
91  
            "Cache-Control: no-cache\r\n"
92  
            "\r\n");
92  
            "\r\n");
93  
        @endcode
93  
        @endcode
94  

94  

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

99  

100  
        @par Complexity
100  
        @par Complexity
101  
        Linear in `s.size()`.
101  
        Linear in `s.size()`.
102  

102  

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

106  

107  
        @throw system_error
107  
        @throw system_error
108  
        The input does not contain a valid request.
108  
        The input does not contain a valid request.
109  

109  

110  
        @param s The string to parse.
110  
        @param s The string to parse.
111  
    */
111  
    */
112  
    explicit
112  
    explicit
113  
    request(
113  
    request(
114  
        core::string_view s)
114  
        core::string_view s)
115  
        : request_base(s)
115  
        : request_base(s)
116  
    {
116  
    {
117  
    }
117  
    }
118  

118  

119  
    /** Constructor.
119  
    /** Constructor.
120  

120  

121  
        The start-line of the request will
121  
        The start-line of the request will
122  
        contain the standard text for the
122  
        contain the standard text for the
123  
        supplied method, target and HTTP version.
123  
        supplied method, target and HTTP version.
124  

124  

125  
        @par Example
125  
        @par Example
126  
        @code
126  
        @code
127  
        request req(method::get, "/index.html", version::http_1_0);
127  
        request req(method::get, "/index.html", version::http_1_0);
128  
        @endcode
128  
        @endcode
129  

129  

130  
        @par Complexity
130  
        @par Complexity
131  
        Linear in `to_string(m).size() + t.size()`.
131  
        Linear in `to_string(m).size() + t.size()`.
132  

132  

133  
        @par Exception Safety
133  
        @par Exception Safety
134  
        Calls to allocate may throw.
134  
        Calls to allocate may throw.
135  

135  

136  
        @param m The method to set.
136  
        @param m The method to set.
137  

137  

138  
        @param t The string representing a target.
138  
        @param t The string representing a target.
139  

139  

140  
        @param v The version to set.
140  
        @param v The version to set.
141  
    */
141  
    */
142  
    request(
142  
    request(
143  
        http::method m,
143  
        http::method m,
144  
        core::string_view t,
144  
        core::string_view t,
145  
        http::version v) noexcept
145  
        http::version v) noexcept
146  
        : request()
146  
        : request()
147  
    {
147  
    {
148  
        set_start_line(m, t, v);
148  
        set_start_line(m, t, v);
149  
    }
149  
    }
150  

150  

151  
    /** Constructor.
151  
    /** Constructor.
152  

152  

153  
        The start-line of the request will
153  
        The start-line of the request will
154  
        contain the standard text for the
154  
        contain the standard text for the
155  
        supplied method and target with the HTTP
155  
        supplied method and target with the HTTP
156  
        version defaulted to `HTTP/1.1`.
156  
        version defaulted to `HTTP/1.1`.
157  

157  

158  
        @par Example
158  
        @par Example
159  
        @code
159  
        @code
160  
        request req(method::get, "/index.html");
160  
        request req(method::get, "/index.html");
161  
        @endcode
161  
        @endcode
162  

162  

163  
        @par Complexity
163  
        @par Complexity
164  
        Linear in `to_string(s).size()`.
164  
        Linear in `to_string(s).size()`.
165  

165  

166  
        @par Exception Safety
166  
        @par Exception Safety
167  
        Calls to allocate may throw.
167  
        Calls to allocate may throw.
168  

168  

169  
        @param m The method to set.
169  
        @param m The method to set.
170  

170  

171  
        @param t The string representing a target.
171  
        @param t The string representing a target.
172  
    */
172  
    */
173  
    request(
173  
    request(
174  
        http::method m,
174  
        http::method m,
175  
        core::string_view t)
175  
        core::string_view t)
176  
        : request(
176  
        : request(
177  
            m, t, http::version::http_1_1)
177  
            m, t, http::version::http_1_1)
178  
    {
178  
    {
179  
    }
179  
    }
180  

180  

181  
    /** Constructor.
181  
    /** Constructor.
182  

182  

183  
        Allocates `cap` bytes initially, with an
183  
        Allocates `cap` bytes initially, with an
184  
        upper limit of `max_cap`. Growing beyond
184  
        upper limit of `max_cap`. Growing beyond
185  
        `max_cap` will throw an exception.
185  
        `max_cap` will throw an exception.
186  

186  

187  
        Useful when an estimated initial size is
187  
        Useful when an estimated initial size is
188  
        known, but further growth up to a maximum
188  
        known, but further growth up to a maximum
189  
        is allowed.
189  
        is allowed.
190  

190  

191  
        When `cap == max_cap`, the container
191  
        When `cap == max_cap`, the container
192  
        guarantees to never allocate.
192  
        guarantees to never allocate.
193  

193  

194  
        @par Preconditions
194  
        @par Preconditions
195  
        @code
195  
        @code
196  
        max_cap >= cap
196  
        max_cap >= cap
197  
        @endcode
197  
        @endcode
198  

198  

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

201  

202  
        @param cap Initial capacity in bytes (may be `0`).
202  
        @param cap Initial capacity in bytes (may be `0`).
203  

203  

204  
        @param max_cap Maximum allowed capacity in bytes.
204  
        @param max_cap Maximum allowed capacity in bytes.
205  
    */
205  
    */
206  
    request(
206  
    request(
207  
        std::size_t cap,
207  
        std::size_t cap,
208  
        std::size_t max_cap = std::size_t(-1))
208  
        std::size_t max_cap = std::size_t(-1))
209  
        : request()
209  
        : request()
210  
    {
210  
    {
211  
        reserve_bytes(cap);
211  
        reserve_bytes(cap);
212  
        set_max_capacity_in_bytes(max_cap);
212  
        set_max_capacity_in_bytes(max_cap);
213  
    }
213  
    }
214  

214  

215  
    /** Constructor.
215  
    /** Constructor.
216  

216  

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

223  

224  
        @par Postconditions
224  
        @par Postconditions
225  
        @code
225  
        @code
226  
        r.buffer() == "GET / HTTP/1.1\r\n\r\n"
226  
        r.buffer() == "GET / HTTP/1.1\r\n\r\n"
227  
        @endcode
227  
        @endcode
228  

228  

229  
        @par Complexity
229  
        @par Complexity
230  
        Constant.
230  
        Constant.
231  

231  

232  
        @param r The request to move from.
232  
        @param r The request to move from.
233  
    */
233  
    */
234  
    request(
234  
    request(
235  
        request&& other) noexcept
235  
        request&& other) noexcept
236  
        : request()
236  
        : request()
237  
    {
237  
    {
238  
        swap(other);
238  
        swap(other);
239  
    }
239  
    }
240  

240  

241  
    /** Constructor.
241  
    /** Constructor.
242  

242  

243  
        The newly constructed object contains
243  
        The newly constructed object contains
244  
        a copy of `r`.
244  
        a copy of `r`.
245  

245  

246  
        @par Postconditions
246  
        @par Postconditions
247  
        @code
247  
        @code
248  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
248  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
249  
        @endcode
249  
        @endcode
250  

250  

251  
        @par Complexity
251  
        @par Complexity
252  
        Linear in `r.size()`.
252  
        Linear in `r.size()`.
253  

253  

254  
        @par Exception Safety
254  
        @par Exception Safety
255  
        Calls to allocate may throw.
255  
        Calls to allocate may throw.
256  

256  

257  
        @param r The request to copy.
257  
        @param r The request to copy.
258  
    */
258  
    */
259  
    request(
259  
    request(
260  
        request const& r) = default;
260  
        request const& r) = default;
261  

261  

262  
    /** Constructor.
262  
    /** Constructor.
263  

263  

264  
        The newly constructed object contains
264  
        The newly constructed object contains
265  
        a copy of `r`.
265  
        a copy of `r`.
266  

266  

267  
        @par Postconditions
267  
        @par Postconditions
268  
        @code
268  
        @code
269  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
269  
        this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data()
270  
        @endcode
270  
        @endcode
271  

271  

272  
        @par Complexity
272  
        @par Complexity
273  
        Linear in `r.size()`.
273  
        Linear in `r.size()`.
274  

274  

275  
        @par Exception Safety
275  
        @par Exception Safety
276  
        Calls to allocate may throw.
276  
        Calls to allocate may throw.
277  

277  

278  
        @param r The request to copy.
278  
        @param r The request to copy.
279  
    */
279  
    */
280  
    request(
280  
    request(
281  
        request_base const& r)
281  
        request_base const& r)
282  
        : request_base(r)
282  
        : request_base(r)
283  
    {
283  
    {
284  
    }
284  
    }
285  

285  

286  
    /** Assignment
286  
    /** Assignment
287  

287  

288  
        The contents of `r` are transferred to
288  
        The contents of `r` are transferred to
289  
        `this`, including the underlying
289  
        `this`, including the underlying
290  
        character buffer. The previous contents
290  
        character buffer. The previous contents
291  
        of `this` are destroyed.
291  
        of `this` are destroyed.
292  
        After assignment, the moved-from
292  
        After assignment, the moved-from
293  
        object is as if default-constructed.
293  
        object is as if default-constructed.
294  

294  

295  
        @par Postconditions
295  
        @par Postconditions
296  
        @code
296  
        @code
297  
        r.buffer() == "GET / HTTP/1.1\r\n\r\n"
297  
        r.buffer() == "GET / HTTP/1.1\r\n\r\n"
298  
        @endcode
298  
        @endcode
299  

299  

300  
        @par Complexity
300  
        @par Complexity
301  
        Constant.
301  
        Constant.
302  

302  

303  
        @param r The request to assign from.
303  
        @param r The request to assign from.
304  

304  

305  
        @return A reference to this object.
305  
        @return A reference to this object.
306  
    */
306  
    */
307  
    request&
307  
    request&
308  
    operator=(request&& r) noexcept
308  
    operator=(request&& r) noexcept
309  
    {
309  
    {
310  
        request temp(std::move(r));
310  
        request temp(std::move(r));
311  
        temp.swap(*this);
311  
        temp.swap(*this);
312  
        return *this;
312  
        return *this;
313  
    }
313  
    }
314  

314  

315  
    /** Assignment.
315  
    /** Assignment.
316  

316  

317  
        The contents of `r` are copied and
317  
        The contents of `r` are copied and
318  
        the previous contents of `this` are
318  
        the previous contents of `this` are
319  
        discarded.
319  
        discarded.
320  

320  

321  
        @par Postconditions
321  
        @par Postconditions
322  
        @code
322  
        @code
323  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
323  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
324  
        @endcode
324  
        @endcode
325  

325  

326  
        @par Complexity
326  
        @par Complexity
327  
        Linear in `r.size()`.
327  
        Linear in `r.size()`.
328  

328  

329  
        @par Exception Safety
329  
        @par Exception Safety
330  
        Strong guarantee.
330  
        Strong guarantee.
331  
        Calls to allocate may throw.
331  
        Calls to allocate may throw.
332  
        Exception thrown if max capacity exceeded.
332  
        Exception thrown if max capacity exceeded.
333  

333  

334  
        @throw std::length_error
334  
        @throw std::length_error
335  
        Max capacity would be exceeded.
335  
        Max capacity would be exceeded.
336  

336  

337  
        @param r The request to copy.
337  
        @param r The request to copy.
338  

338  

339  
        @return A reference to this object.
339  
        @return A reference to this object.
340  
    */
340  
    */
341  
    request&
341  
    request&
342  
    operator=(
342  
    operator=(
343  
        request const& r)
343  
        request const& r)
344  
    {
344  
    {
345  
        copy_impl(r.h_);
345  
        copy_impl(r.h_);
346  
        return *this;
346  
        return *this;
347  
    }
347  
    }
348  

348  

349  
    /** Assignment.
349  
    /** Assignment.
350  

350  

351  
        The contents of `r` are copied and
351  
        The contents of `r` are copied and
352  
        the previous contents of `this` are
352  
        the previous contents of `this` are
353  
        discarded.
353  
        discarded.
354  

354  

355  
        @par Postconditions
355  
        @par Postconditions
356  
        @code
356  
        @code
357  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
357  
        this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data()
358  
        @endcode
358  
        @endcode
359  

359  

360  
        @par Complexity
360  
        @par Complexity
361  
        Linear in `r.size()`.
361  
        Linear in `r.size()`.
362  

362  

363  
        @par Exception Safety
363  
        @par Exception Safety
364  
        Strong guarantee.
364  
        Strong guarantee.
365  
        Calls to allocate may throw.
365  
        Calls to allocate may throw.
366  
        Exception thrown if max capacity exceeded.
366  
        Exception thrown if max capacity exceeded.
367  

367  

368  
        @throw std::length_error
368  
        @throw std::length_error
369  
        Max capacity would be exceeded.
369  
        Max capacity would be exceeded.
370  

370  

371  
        @param r The request to copy.
371  
        @param r The request to copy.
372  

372  

373  
        @return A reference to this object.
373  
        @return A reference to this object.
374  
    */
374  
    */
375  
    request&
375  
    request&
376  
    operator=(
376  
    operator=(
377  
        request_base const& r)
377  
        request_base const& r)
378  
    {
378  
    {
379  
        copy_impl(r.h_);
379  
        copy_impl(r.h_);
380  
        return *this;
380  
        return *this;
381  
    }
381  
    }
382  

382  

383  
    //--------------------------------------------
383  
    //--------------------------------------------
384  

384  

385  
    /** Swap.
385  
    /** Swap.
386  

386  

387  
        Exchanges the contents of this request
387  
        Exchanges the contents of this request
388  
        with another request. All views,
388  
        with another request. All views,
389  
        iterators and references remain valid.
389  
        iterators and references remain valid.
390  

390  

391  
        If `this == &other`, this function call has no effect.
391  
        If `this == &other`, this function call has no effect.
392  

392  

393  
        @par Example
393  
        @par Example
394  
        @code
394  
        @code
395  
        request r1(method::get, "/");
395  
        request r1(method::get, "/");
396  
        request r2(method::delete_, "/item/42");
396  
        request r2(method::delete_, "/item/42");
397  
        r1.swap(r2);
397  
        r1.swap(r2);
398  
        assert(r1.buffer() == "DELETE /item/42 HTTP/1.1\r\n\r\n" );
398  
        assert(r1.buffer() == "DELETE /item/42 HTTP/1.1\r\n\r\n" );
399  
        assert(r2.buffer() == "GET / HTTP/1.1\r\n\r\n" );
399  
        assert(r2.buffer() == "GET / HTTP/1.1\r\n\r\n" );
400  
        @endcode
400  
        @endcode
401  

401  

402  
        @par Complexity
402  
        @par Complexity
403  
        Constant
403  
        Constant
404  

404  

405  
        @param other The object to swap with
405  
        @param other The object to swap with
406  
    */
406  
    */
407  
    void
407  
    void
408  
    swap(request& other) noexcept
408  
    swap(request& other) noexcept
409  
    {
409  
    {
410  
        h_.swap(other.h_);
410  
        h_.swap(other.h_);
411  
        std::swap(max_cap_, other.max_cap_);
411  
        std::swap(max_cap_, other.max_cap_);
412  
    }
412  
    }
413  

413  

414  
    /** Swap.
414  
    /** Swap.
415  

415  

416  
        Exchanges the contents of `v0` with
416  
        Exchanges the contents of `v0` with
417  
        another `v1`. All views, iterators and
417  
        another `v1`. All views, iterators and
418  
        references remain valid.
418  
        references remain valid.
419  

419  

420  
        If `&v0 == &v1`, this function call has no effect.
420  
        If `&v0 == &v1`, this function call has no effect.
421  

421  

422  
        @par Example
422  
        @par Example
423  
        @code
423  
        @code
424  
        request r1(method::get, "/");
424  
        request r1(method::get, "/");
425  
        request r2(method::delete_, "/item/42");
425  
        request r2(method::delete_, "/item/42");
426  
        std::swap(r1, r2);
426  
        std::swap(r1, r2);
427  
        assert(r1.buffer() == "DELETE /item/42 HTTP/1.1\r\n\r\n" );
427  
        assert(r1.buffer() == "DELETE /item/42 HTTP/1.1\r\n\r\n" );
428  
        assert(r2.buffer() == "GET / HTTP/1.1\r\n\r\n" );
428  
        assert(r2.buffer() == "GET / HTTP/1.1\r\n\r\n" );
429  
        @endcode
429  
        @endcode
430  

430  

431  
        @par Effects
431  
        @par Effects
432  
        @code
432  
        @code
433  
        v0.swap(v1);
433  
        v0.swap(v1);
434  
        @endcode
434  
        @endcode
435  

435  

436  
        @par Complexity
436  
        @par Complexity
437  
        Constant.
437  
        Constant.
438  

438  

439  
        @param v0 The first object to swap.
439  
        @param v0 The first object to swap.
440  
        @param v1 The second object to swap.
440  
        @param v1 The second object to swap.
441  

441  

442  
        @see
442  
        @see
443  
            @ref request::swap
443  
            @ref request::swap
444  
    */
444  
    */
445  
    friend
445  
    friend
446  
    void
446  
    void
447  
    swap(
447  
    swap(
448  
        request& v0,
448  
        request& v0,
449  
        request& v1) noexcept
449  
        request& v1) noexcept
450  
    {
450  
    {
451  
        v0.swap(v1);
451  
        v0.swap(v1);
452  
    }
452  
    }
453  
};
453  
};
454  

454  

455  
} // http
455  
} // http
456  
} // boost
456  
} // boost
457  

457  

458  
#endif
458  
#endif