100.00% Lines (40/40) 100.00% Functions (12/12)
TLA Baseline Branch
Line Hits Code Line Hits Code
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   */
HITCBC 76   202 request() noexcept = default; 76   202 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
HITCBC 113   212 request( 113   212 request(
114   core::string_view s) 114   core::string_view s)
HITCBC 115   212 : request_base(s) 115   212 : request_base(s)
116   { 116   {
HITCBC 117   211 } 117   211 }
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   */
HITCBC 142   26 request( 142   26 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
HITCBC 146   26 : request() 146   26 : request()
147   { 147   {
HITCBC 148   26 set_start_line(m, t, v); 148   26 set_start_line(m, t, v);
HITCBC 149   26 } 149   26 }
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   */
HITCBC 173   26 request( 173   26 request(
174   http::method m, 174   http::method m,
175   core::string_view t) 175   core::string_view t)
HITCBC 176   26 : request( 176   26 : request(
HITCBC 177   26 m, t, http::version::http_1_1) 177   26 m, t, http::version::http_1_1)
178   { 178   {
HITCBC 179   26 } 179   26 }
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   */
HITCBC 206   10 request( 206   10 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))
HITCBC 209   10 : request() 209   10 : request()
210   { 210   {
HITCBC 211   10 reserve_bytes(cap); 211   10 reserve_bytes(cap);
HITCBC 212   10 set_max_capacity_in_bytes(max_cap); 212   10 set_max_capacity_in_bytes(max_cap);
HITCBC 213   10 } 213   10 }
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   */
HITCBC 234   26 request( 234   26 request(
235   request&& other) noexcept 235   request&& other) noexcept
HITCBC 236   26 : request() 236   26 : request()
237   { 237   {
HITCBC 238   26 swap(other); 238   26 swap(other);
HITCBC 239   26 } 239   26 }
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   */
HITCBC 259   2 request( 259   2 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   */
HITCBC 280   2 request( 280   2 request(
281   request_base const& r) 281   request_base const& r)
HITCBC 282   2 : request_base(r) 282   2 : request_base(r)
283   { 283   {
HITCBC 284   2 } 284   2 }
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&
HITCBC 308   24 operator=(request&& r) noexcept 308   24 operator=(request&& r) noexcept
309   { 309   {
HITCBC 310   24 request temp(std::move(r)); 310   24 request temp(std::move(r));
HITCBC 311   24 temp.swap(*this); 311   24 temp.swap(*this);
HITCBC 312   48 return *this; 312   48 return *this;
HITCBC 313   24 } 313   24 }
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&
HITCBC 342   3 operator=( 342   3 operator=(
343   request const& r) 343   request const& r)
344   { 344   {
HITCBC 345   3 copy_impl(r.h_); 345   3 copy_impl(r.h_);
HITCBC 346   3 return *this; 346   3 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&
HITCBC 376   2 operator=( 376   2 operator=(
377   request_base const& r) 377   request_base const& r)
378   { 378   {
HITCBC 379   2 copy_impl(r.h_); 379   2 copy_impl(r.h_);
HITCBC 380   2 return *this; 380   2 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
HITCBC 408   50 swap(request& other) noexcept 408   50 swap(request& other) noexcept
409   { 409   {
HITCBC 410   50 h_.swap(other.h_); 410   50 h_.swap(other.h_);
HITCBC 411   50 std::swap(max_cap_, other.max_cap_); 411   50 std::swap(max_cap_, other.max_cap_);
HITCBC 412   50 } 412   50 }
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