RESTinio
range.hpp
Go to the documentation of this file.
1 /*
2  * RESTinio
3  */
4 
5 /*!
6  * @file
7  * @brief Stuff related to value of Range HTTP-field.
8  *
9  * @since v.0.6.2
10  */
11 
12 #pragma once
13 
14 #include <restinio/helpers/http_field_parsers/basics.hpp>
15 
16 #include <restinio/variant.hpp>
17 
18 namespace restinio
19 {
20 
21 namespace http_field_parsers
22 {
23 
24 namespace range_details
25 {
26 
27 /*!
28  * @brief Value of range for the case where both ends of the range
29  * are defined.
30  *
31  * This type will be used if a range is defined such way:
32 @verbatim
33 bytes=1000-5000,6000-7000
34 @endverbatim
35  *
36  * @since v.0.6.2
37  */
38 template< typename T >
40 {
41  T first;
42  T last;
43 };
44 
45 /*!
46  * @brief Value of range for the case where only left border of the
47  * range is defined.
48  *
49  * This type will be used if a range is defined such way:
50 @verbatim
51 bytes=1000-
52 @endverbatim
53  *
54  * @since v.0.6.2
55  */
56 template< typename T >
58 {
59  T first;
60 };
61 
62 /*!
63  * @brief Value of range for the case where only length of range's
64  * suffix is defined.
65  *
66  * This type will be used if a range is defined such way:
67 @verbatim
68 bytes=-450
69 @endverbatim
70  *
71  * @since v.0.6.2
72  */
73 template< typename T >
75 {
76  T length;
77 };
78 
79 /*!
80  * @brief Variant type for all possible cases of specification for one range.
81  *
82  * @since v.0.6.2
83  */
84 template< typename T >
89 
90 /*!
91  * @brief A struct that holds a container of byte_range_specs.
92  *
93  * @since v.0.6.2
94  */
95 template< typename T >
97 {
99 };
100 
101 /*!
102  * @brief A description of a range value of units those are not "bytes".
103  *
104  * This type will be used for values like:
105 @verbatim
106 x-megabytes=1-45,450-1300
107 @endverbatim
108  *
109  * Please note that other_ranges_specifier_t::range_set contains the raw
110  * value. E.g. for the example above range_set will hold "1-45,450-1300".
111  *
112  * @since v.0.6.2
113  */
115 {
118 };
119 
120 /*!
121  * @brief Variant type for holding parsed value of Range HTTP-field.
122  *
123  * @since v.0.6.2
124  */
125 template< typename T >
126 using value_t = variant_t<
129 
130 /*!
131  * @brief Factory for creation of a parser for byte_range_spec values.
132  *
133  * Creates a parser for the following rule:
134 @verbatim
135 byte-range-spec = byte-range / suffix-byte-range-spec
136 
137 byte-range = first-byte-pos "-" [ last-byte-pos ]
138 first-byte-pos = 1*DIGIT
139 last-byte-pos = 1*DIGIT
140 
141 suffix-byte-range-spec = "-" suffix-length
142 suffix-length = 1*DIGIT
143 @endverbatim
144  *
145  * The parser returned produces value of byte_range_spec_t<T>.
146  *
147  * @since v.0.6.2
148  */
149 template< typename T >
151 auto
153 {
154  return produce< byte_range_spec_t<T> >(
155  alternatives(
159  symbol('-'),
162  ) >> as_result(),
165  >> &open_ended_range_t<T>::first,
166  symbol('-')
167  ) >> as_result(),
169  symbol('-'),
171  >> &suffix_length_t<T>::length
172  ) >> as_result()
173  )
174  );
175 }
176 
177 /*!
178  * @brief Factory for a parser of 'bytes=' prefix.
179  *
180  * @since v.0.6.2
181  */
183 inline auto
185 {
186  return sequence( exact( "bytes" ), symbol('=') );
187 }
188 
189 /*!
190  * @brief Factory for creation of a parser for byte_ranges_specifier values.
191  *
192  * Creates a parser for the following rule:
193 @verbatim
194 byte-ranges-specifier = bytes-unit "=" byte-range-set
195 byte-range-set = 1#( byte-range-spec / suffix-byte-range-spec )
196 byte-range-spec = first-byte-pos "-" [ last-byte-pos ]
197 first-byte-pos = 1*DIGIT
198 last-byte-pos = 1*DIGIT
199 
200 suffix-byte-range-spec = "-" suffix-length
201 suffix-length = 1*DIGIT
202 @endverbatim
203  *
204  * The parser returned produces value of byte_ranges_specifier_t<T>.
205  *
206  * @since v.0.6.2
207  */
208 template< typename T >
210 auto
212 {
213  return produce< byte_ranges_specifier_t<T> >(
217  std::vector< byte_range_spec_t<T> > >(
220  )
221  );
222 }
223 
224 /*!
225  * @brief Factory for creation of a parser for other_ranges_specifier values.
226  *
227  * Creates a parser for the following rule:
228 @verbatim
229 other-ranges-specifier = other-range-unit "=" other-range-set
230 other-range-set = 1*VCHAR
231 @endverbatim
232  *
233  * The parser returned produces value of other_ranges_specifier_t.
234  *
235  * @since v.0.6.2
236  */
238 inline auto
240 {
243  symbol('='),
245  produce< std::string >(
246  repeat( 1u, N, vchar_symbol_p() >> to_container() )
248  )
249  );
250 }
251 
252 } /* namespace range_details */
253 
254 //
255 // range_value_t
256 //
257 /*!
258  * @brief Tools for working with the value of Range HTTP-field.
259  *
260  * This struct represents parsed value of HTTP-field Range
261  * (see https://tools.ietf.org/html/rfc7233#section-3.1 and
262  * https://tools.ietf.org/html/rfc7233#section-2):
263 @verbatim
264 Range = byte-ranges-specifier / other-ranges-specifier
265 
266 byte-ranges-specifier = bytes-unit "=" byte-range-set
267 byte-range-set = 1#( byte-range-spec / suffix-byte-range-spec )
268 byte-range-spec = first-byte-pos "-" [ last-byte-pos ]
269 first-byte-pos = 1*DIGIT
270 last-byte-pos = 1*DIGIT
271 
272 suffix-byte-range-spec = "-" suffix-length
273 suffix-length = 1*DIGIT
274 
275 other-ranges-specifier = other-range-unit "=" other-range-set
276 other-range-set = 1*VCHAR
277 @endverbatim
278  *
279  * \tparam T integer type for holding parsed values for byte-ranges-specifier.
280  * It is expected to be type like int, unsigned int, long, unsigned long,
281  * std::uint64_t, std::uint_least64_t and so on.
282  *
283  * @since v.0.6.2
284  */
285 template< typename T >
287 {
288  /*!
289  * @brief Value of range for the case where both ends of the range
290  * are defined.
291  *
292  * This type will be used if a range is defined such way:
293  @verbatim
294  bytes=1000-5000,6000-7000
295  @endverbatim
296  *
297  * Usage example:
298  * @code
299  using range_type = restinio::http_field_parsers::range_value_t<std::uint_least64_t>;
300  const auto parse_result = range_type::try_parse(range_field_value);
301  if(parse_result) {
302  if(const auto * byte_ranges =
303  restinio::get_if<range_type::byte_ranges_specifier_t>(parse_result->value)) {
304  for(const auto & r : byte_ranges->ranges) {
305  if(const auto * full_range =
306  restinio::get_if<range_type::double_ended_range_t>(&r)) {
307  ... // access to full_range->first and full_range->last
308  }
309  else
310  ...
311  }
312  }
313  }
314  * @endcode
315  *
316  * @since v.0.6.2
317  */
318  using double_ended_range_t = range_details::double_ended_range_t<T>;
319 
320  /*!
321  * @brief Value of range for the case where only left border of the
322  * range is defined.
323  *
324  * This type will be used if a range is defined such way:
325  @verbatim
326  bytes=1000-
327  @endverbatim
328  *
329  * Usage example:
330  * @code
331  using range_type = restinio::http_field_parsers::range_value_t<std::uint_least64_t>;
332  const auto parse_result = range_type::try_parse(range_field_value);
333  if(parse_result) {
334  if(const auto * byte_ranges =
335  restinio::get_if<range_type::byte_ranges_specifier_t>(parse_result->value)) {
336  for(const auto & r : byte_ranges->ranges) {
337  if(const auto * open_range =
338  restinio::get_if<range_type::open_ended_range_t>(&r)) {
339  ... // access to open_range->first.
340  }
341  else
342  ...
343  }
344  }
345  }
346  * @endcode
347  * @since v.0.6.2
348  */
349  using open_ended_range_t = range_details::open_ended_range_t<T>;
350 
351  /*!
352  * @brief Value of range for the case where only length of range's
353  * suffix is defined.
354  *
355  * This type will be used if a range is defined such way:
356  @verbatim
357  bytes=-450
358  @endverbatim
359  *
360  * Usage example:
361  * @code
362  using range_type = restinio::http_field_parsers::range_value_t<std::uint_least64_t>;
363  const auto parse_result = range_type::try_parse(range_field_value);
364  if(parse_result) {
365  if(const auto * byte_ranges =
366  restinio::get_if<range_type::byte_ranges_specifier_t>(parse_result->value)) {
367  for(const auto & r : byte_ranges->ranges) {
368  if(const auto * suffix =
369  restinio::get_if<range_type::suffix_length_t>(&r)) {
370  ... // access to suffix->first.
371  }
372  else
373  ...
374  }
375  }
376  }
377  * @endcode
378  *
379  * @since v.0.6.2
380  */
381  using suffix_length_t = range_details::suffix_length_t<T>;
382 
383  /*!
384  * @brief Variant type for all possible cases of specification for one range.
385  *
386  * @since v.0.6.2
387  */
389 
390  /*!
391  * @brief A struct that holds a container of byte_range_specs.
392  *
393  * Usage example:
394  * @code
395  using range_type = restinio::http_field_parsers::range_value_t<std::uint_least64_t>;
396  const auto parse_result = range_type::try_parse(range_field_value);
397  if(parse_result) {
398  if(const auto * byte_ranges =
399  restinio::get_if<range_type::byte_ranges_specifier_t>(parse_result->value)) {
400  for(const auto & r : byte_ranges->ranges) {
401  if(const auto * full_range =
402  restinio::get_if<range_type::double_ended_range_t>(&r)) {
403  ... // access to full_range->first and full_range->last
404  }
405  else if(const auto * open_range =
406  restinio::get_if<range_type::open_ended_range_t>(&r)) {
407  ... // access to open_range->first.
408  }
409  else if(const auto * suffix =
410  restinio::get_if<range_type::suffix_length_t>(&r)) {
411  ... // access to suffix->first.
412  }
413  }
414  }
415  }
416  * @endcode
417  *
418  * @since v.0.6.2
419  */
420  using byte_ranges_specifier_t = range_details::byte_ranges_specifier_t<T>;
421 
422  /*!
423  * @brief A description of a range value of units those are not "bytes".
424  *
425  * This type will be used for values like:
426  @verbatim
427  x-megabytes=1-45,450-1300
428  @endverbatim
429  *
430  * Please note that other_ranges_specifier_t::range_set contains the raw
431  * value. E.g. for the example above range_set will hold "1-45,450-1300".
432  *
433  * @since v.0.6.2
434  */
435  using other_ranges_specifier_t = range_details::other_ranges_specifier_t;
436 
437  /*!
438  * @brief Variant type for holding parsed value of Range HTTP-field.
439  *
440  * @since v.0.6.2
441  */
443 
445 
446  /*!
447  * @brief A factory function for a parser of Range value.
448  *
449  * @since v.0.6.2
450  */
452  static auto
454  {
455  using namespace range_details;
456 
457  return produce< range_value_t >(
458  alternatives(
463  )
464  );
465  }
466 
467  /*!
468  * @brief An attempt to parse Range HTTP-field.
469  *
470  * @since v.0.6.2
471  */
475  {
477  }
478 };
479 
480 } /* namespace http_field_parsers */
481 
482 } /* namespace restinio */
A description of a range value of units those are not "bytes".
Definition: range.hpp:114
Value of range for the case where only length of range&#39;s suffix is defined.
Definition: range.hpp:74
Value of range for the case where both ends of the range are defined.
Definition: range.hpp:39
RESTINIO_NODISCARD auto make_other_ranges_specifier_parser()
Factory for creation of a parser for other_ranges_specifier values.
Definition: range.hpp:239
static RESTINIO_NODISCARD expected_t< range_value_t, restinio::easy_parser::parse_error_t > try_parse(string_view_t what)
An attempt to parse Range HTTP-field.
Definition: range.hpp:474
Value of range for the case where only left border of the range is defined.
Definition: range.hpp:57
RESTINIO_NODISCARD auto try_parse_field(const generic_request_t< Extra_Data > &req, http_field_t field_id, string_view_t default_value=string_view_t{})
A helper function for extraction and parsing a value of HTTP-field.
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...
Definition: value_or.hpp:64