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