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