RESTinio
Loading...
Searching...
No Matches
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 <variant>
17
18namespace restinio
19{
20
21namespace http_field_parsers
22{
23
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
33bytes=1000-5000,6000-7000
34@endverbatim
35 *
36 * @since v.0.6.2
37 */
38template< typename T >
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
51bytes=1000-
52@endverbatim
53 *
54 * @since v.0.6.2
55 */
56template< typename T >
58{
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
68bytes=-450
69@endverbatim
70 *
71 * @since v.0.6.2
72 */
73template< typename T >
75{
77};
78
79/*!
80 * @brief Variant type for all possible cases of specification for one range.
81 *
82 * @since v.0.6.2
83 */
84template< typename T >
85using byte_range_spec_t = std::variant<
88 suffix_length_t<T> >;
89
90/*!
91 * @brief A struct that holds a container of byte_range_specs.
92 *
93 * @since v.0.6.2
94 */
95template< typename T >
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
106x-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{
116 std::string range_unit;
117 std::string range_set;
118};
119
120/*!
121 * @brief Variant type for holding parsed value of Range HTTP-field.
122 *
123 * @since v.0.6.2
124 */
125template< typename T >
126using value_t = std::variant<
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
135byte-range-spec = byte-range / suffix-byte-range-spec
136
137byte-range = first-byte-pos "-" [ last-byte-pos ]
138first-byte-pos = 1*DIGIT
139last-byte-pos = 1*DIGIT
140
141suffix-byte-range-spec = "-" suffix-length
142suffix-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 */
149template< typename T >
150[[nodiscard]]
151auto
153{
154 return produce< byte_range_spec_t<T> >(
155 alternatives(
156 produce< double_ended_range_t<T> >(
157 non_negative_decimal_number_p<T>()
158 >> &double_ended_range_t<T>::first,
159 symbol('-'),
160 non_negative_decimal_number_p<T>()
161 >> &double_ended_range_t<T>::last
162 ) >> as_result(),
163 produce< open_ended_range_t<T> >(
164 non_negative_decimal_number_p<T>()
165 >> &open_ended_range_t<T>::first,
166 symbol('-')
167 ) >> as_result(),
168 produce< suffix_length_t<T> >(
169 symbol('-'),
170 non_negative_decimal_number_p<T>()
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 */
182[[nodiscard]]
183inline 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
194byte-ranges-specifier = bytes-unit "=" byte-range-set
195byte-range-set = 1#( byte-range-spec / suffix-byte-range-spec )
196byte-range-spec = first-byte-pos "-" [ last-byte-pos ]
197first-byte-pos = 1*DIGIT
198last-byte-pos = 1*DIGIT
199
200suffix-byte-range-spec = "-" suffix-length
201suffix-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 */
208template< typename T >
209[[nodiscard]]
210auto
212{
213 return produce< byte_ranges_specifier_t<T> >(
214 make_bytes_prefix_parser(),
215 force_only_this_alternative(
216 non_empty_comma_separated_list_p<
217 std::vector< byte_range_spec_t<T> > >(
218 make_byte_range_spec_parser<T>()
219 ) >> &byte_ranges_specifier_t<T>::ranges
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
229other-ranges-specifier = other-range-unit "=" other-range-set
230other-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 */
237[[nodiscard]]
238inline auto
240{
241 return produce< other_ranges_specifier_t >(
242 token_p() >> &other_ranges_specifier_t::range_unit,
243 symbol('='),
244 force_only_this_alternative(
245 produce< std::string >(
246 repeat( 1u, N, vchar_symbol_p() >> to_container() )
247 ) >> &other_ranges_specifier_t::range_set
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
264Range = byte-ranges-specifier / other-ranges-specifier
265
266byte-ranges-specifier = bytes-unit "=" byte-range-set
267byte-range-set = 1#( byte-range-spec / suffix-byte-range-spec )
268byte-range-spec = first-byte-pos "-" [ last-byte-pos ]
269first-byte-pos = 1*DIGIT
270last-byte-pos = 1*DIGIT
271
272suffix-byte-range-spec = "-" suffix-length
273suffix-length = 1*DIGIT
274
275other-ranges-specifier = other-range-unit "=" other-range-set
276other-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 */
285template< 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 std::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 std::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 */
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 std::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 std::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 */
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 std::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 std::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 */
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 std::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 std::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 std::get_if<range_type::open_ended_range_t>(&r)) {
407 ... // access to open_range->first.
408 }
409 else if(const auto * suffix =
410 std::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 */
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 */
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 */
451 [[nodiscard]]
452 static auto
454 {
455 using namespace range_details;
456
457 return produce< range_value_t >(
458 alternatives(
459 make_byte_ranges_specifier_parser<T>() >>
460 &range_value_t::value,
462 &range_value_t::value
463 )
464 );
465 }
466
467 /*!
468 * @brief An attempt to parse Range HTTP-field.
469 *
470 * @since v.0.6.2
471 */
472 [[nodiscard]]
474 try_parse( string_view_t what )
475 {
476 return restinio::easy_parser::try_parse( what, make_parser() );
477 }
478};
479
480} /* namespace http_field_parsers */
481
482} /* namespace restinio */
auto make_other_ranges_specifier_parser()
Factory for creation of a parser for other_ranges_specifier values.
Definition range.hpp:239
auto make_byte_range_spec_parser()
Factory for creation of a parser for byte_range_spec values.
Definition range.hpp:152
auto make_bytes_prefix_parser()
Factory for a parser of 'bytes=' prefix.
Definition range.hpp:184
std::variant< byte_ranges_specifier_t< T >, other_ranges_specifier_t > value_t
Variant type for holding parsed value of Range HTTP-field.
Definition range.hpp:126
std::variant< double_ended_range_t< T >, open_ended_range_t< T >, suffix_length_t< T > > byte_range_spec_t
Variant type for all possible cases of specification for one range.
Definition range.hpp:85
auto make_byte_ranges_specifier_parser()
Factory for creation of a parser for byte_ranges_specifier values.
Definition range.hpp:211
A struct that holds a container of byte_range_specs.
Definition range.hpp:97
Value of range for the case where both ends of the range are defined.
Definition range.hpp:40
Value of range for the case where only left border of the range is defined.
Definition range.hpp:58
A description of a range value of units those are not "bytes".
Definition range.hpp:115
Value of range for the case where only length of range's suffix is defined.
Definition range.hpp:75
Tools for working with the value of Range HTTP-field.
Definition range.hpp:287
range_details::byte_ranges_specifier_t< T > byte_ranges_specifier_t
A struct that holds a container of byte_range_specs.
Definition range.hpp:420
range_details::suffix_length_t< T > suffix_length_t
Value of range for the case where only length of range's suffix is defined.
Definition range.hpp:381
static 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
static auto make_parser()
A factory function for a parser of Range value.
Definition range.hpp:453
range_details::other_ranges_specifier_t other_ranges_specifier_t
A description of a range value of units those are not "bytes".
Definition range.hpp:435
range_details::open_ended_range_t< T > open_ended_range_t
Value of range for the case where only left border of the range is defined.
Definition range.hpp:349
range_details::double_ended_range_t< T > double_ended_range_t
Value of range for the case where both ends of the range are defined.
Definition range.hpp:318