Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/boostorg/url
9 : //
10 :
11 : #ifndef BOOST_URL_PARAM_HPP
12 : #define BOOST_URL_PARAM_HPP
13 :
14 : #include <boost/url/detail/config.hpp>
15 : #include <boost/url/detail/optional_string.hpp>
16 : #include <boost/url/pct_string_view.hpp>
17 : #include <cstddef>
18 : #include <string>
19 :
20 : namespace boost {
21 : namespace urls {
22 :
23 : #ifndef BOOST_URL_DOCS
24 : struct param_pct_view;
25 : struct param_view;
26 : #endif
27 :
28 : /** The type of no_value
29 : */
30 : struct no_value_t
31 : {
32 : };
33 :
34 : /** Constant indicating no value in a param
35 : */
36 : constexpr no_value_t no_value{};
37 :
38 : //------------------------------------------------
39 :
40 : /** A query parameter
41 :
42 : Objects of this type represent a single key
43 : and value pair in a query string where a key
44 : is always present and may be empty, while the
45 : presence of a value is indicated by
46 : @ref has_value equal to true.
47 : An empty value is distinct from no value.
48 :
49 : Depending on where the object was obtained,
50 : the strings may or may not contain percent
51 : escapes.
52 :
53 : For most usages, key comparisons are
54 : case-sensitive and duplicate keys in
55 : a query are possible. However, it is
56 : the authority that has final control
57 : over how the query is interpreted.
58 :
59 : @par BNF
60 : @code
61 : query-params = query-param *( "&" query-param )
62 : query-param = key [ "=" value ]
63 : key = *qpchar
64 : value = *( qpchar / "=" )
65 : @endcode
66 :
67 : @par Specification
68 : @li <a href="https://en.wikipedia.org/wiki/Query_string"
69 : >Query string (Wikipedia)</a>
70 :
71 : @see
72 : @ref param_view,
73 : @ref param_pct_view.
74 : */
75 1 : struct param
76 : {
77 : /** The key
78 :
79 : For most usages, key comparisons are
80 : case-sensitive and duplicate keys in
81 : a query are possible. However, it is
82 : the authority that has final control
83 : over how the query is interpreted.
84 : */
85 : std::string key;
86 :
87 : /** The value
88 :
89 : The presence of a value is indicated by
90 : @ref has_value equal to true.
91 : An empty value is distinct from no value.
92 : */
93 : std::string value;
94 :
95 : /** True if a value is present
96 :
97 : The presence of a value is indicated by
98 : `has_value == true`.
99 : An empty value is distinct from no value.
100 : */
101 : bool has_value = false;
102 :
103 : /** Constructor
104 :
105 : Default constructed query parameters
106 : have an empty key and no value.
107 :
108 : @par Example
109 : @code
110 : param qp;
111 : @endcode
112 :
113 : @par Postconditions
114 : @code
115 : this->key == "" && this->value == "" && this->has_value == false
116 : @endcode
117 :
118 : @par Complexity
119 : Constant.
120 :
121 : @par Exception Safety
122 : Throws nothing.
123 : */
124 6 : param() = default;
125 :
126 : /** Constructor
127 :
128 : Upon construction, this acquires
129 : ownership of the members of other
130 : via move construction. The moved
131 : from object is as if default
132 : constructed.
133 :
134 : @par Complexity
135 : Constant.
136 :
137 : @par Exception Safety
138 : Throws nothing.
139 :
140 : @par other The object to construct from.
141 : */
142 1 : param(param&& other) noexcept
143 1 : : key(std::move(other.key))
144 1 : , value(std::move(other.value))
145 1 : , has_value(other.has_value)
146 : {
147 : #ifdef BOOST_URL_COW_STRINGS
148 : // for copy-on-write std::string
149 : other.key.clear();
150 : other.value.clear();
151 : #endif
152 1 : other.has_value = false;
153 1 : }
154 :
155 : /** Constructor
156 :
157 : Upon construction, this becomes a copy
158 : of `other`.
159 :
160 : @par Postconditions
161 : @code
162 : this->key == other.key && this->value == other.value && this->has_value == other.has_value
163 : @endcode
164 :
165 : @par Complexity
166 : Linear in `other.key.size() + other.value.size()`.
167 :
168 : @par Exception Safety
169 : Calls to allocate may throw.
170 :
171 : @par other The object to construct from.
172 : */
173 2 : param(param const& other) = default;
174 :
175 : /** Assignment
176 :
177 : Upon assignment, this acquires
178 : ownership of the members of other
179 : via move assignment. The moved
180 : from object is as if default
181 : constructed.
182 :
183 : @par Complexity
184 : Constant.
185 :
186 : @par Exception Safety
187 : Throws nothing.
188 :
189 : @par other The object to assign from.
190 : */
191 : param&
192 3 : operator=(param&& other) noexcept
193 : {
194 3 : key = std::move(other.key);
195 3 : value = std::move(other.value);
196 3 : has_value = other.has_value;
197 : #ifdef BOOST_URL_COW_STRINGS
198 : // for copy-on-write std::string
199 : other.key.clear();
200 : other.value.clear();
201 : #endif
202 3 : other.has_value = false;
203 3 : return *this;
204 : }
205 :
206 : /** Assignment
207 :
208 : Upon assignment, this becomes a copy
209 : of `other`.
210 :
211 : @par Postconditions
212 : @code
213 : this->key == other.key && this->value == other.value && this->has_value == other.has_value
214 : @endcode
215 :
216 : @par Complexity
217 : Linear in `other.key.size() + other.value.size()`.
218 :
219 : @par Exception Safety
220 : Calls to allocate may throw.
221 :
222 : @par other The object to assign from.
223 : */
224 : param& operator=(
225 : param const&) = default;
226 :
227 : //--------------------------------------------
228 :
229 : /** Constructor
230 :
231 : This constructs a parameter with a key
232 : and value.
233 :
234 : No validation is performed on the strings.
235 : Ownership of the key and value is acquired
236 : by making copies.
237 :
238 : @par Example
239 : @code
240 : param qp( "key", "value" );
241 : @endcode
242 :
243 : @code
244 : param qp( "key", optional<core::string_view>("value") );
245 : @endcode
246 :
247 : @code
248 : param qp( "key", boost::none );
249 : @endcode
250 :
251 : @code
252 : param qp( "key", nullptr );
253 : @endcode
254 :
255 : @code
256 : param qp( "key", no_value );
257 : @endcode
258 :
259 : @par Postconditions
260 : @code
261 : this->key == key && this->value == value && this->has_value == true
262 : @endcode
263 :
264 : @par Complexity
265 : Linear in `key.size() + value.size()`.
266 :
267 : @par Exception Safety
268 : Calls to allocate may throw.
269 :
270 : @tparam OptionalString An optional string
271 : type, such as `core::string_view`,
272 : `std::nullptr`, @ref no_value_t, or
273 : `optional<core::string_view>`.
274 :
275 : @param key, value The key and value to set.
276 : */
277 : template <class OptionalString>
278 16 : param(
279 : core::string_view key,
280 : OptionalString const& value)
281 16 : : param(key, detail::get_optional_string(value))
282 : {
283 16 : }
284 :
285 : /** Assignment
286 :
287 : The members of `other` are copied,
288 : re-using already existing string capacity.
289 :
290 : @par Postconditions
291 : @code
292 : this->key == other.key && this->value == other.value && this->has_value == other.has_value
293 : @endcode
294 :
295 : @par Complexity
296 : Linear in `other.key.size() + other.value.size()`.
297 :
298 : @par Exception Safety
299 : Calls to allocate may throw.
300 :
301 : @param other The parameter to copy.
302 : */
303 : param&
304 : operator=(param_view const& other);
305 :
306 : /** Assignment
307 :
308 : The members of `other` are copied,
309 : re-using already existing string capacity.
310 :
311 : @par Postconditions
312 : @code
313 : this->key == other.key && this->value == other.value && this->has_value == other.has_value
314 : @endcode
315 :
316 : @par Complexity
317 : Linear in `other.key.size() + other.value.size()`.
318 :
319 : @par Exception Safety
320 : Calls to allocate may throw.
321 :
322 : @param other The parameter to copy.
323 : */
324 : param&
325 : operator=(param_pct_view const& other);
326 :
327 : #ifndef BOOST_URL_DOCS
328 : // arrow support
329 : param const*
330 1 : operator->() const noexcept
331 : {
332 1 : return this;
333 : }
334 :
335 : // aggregate construction
336 780 : param(
337 : core::string_view key,
338 : core::string_view value,
339 : bool has_value) noexcept
340 780 : : key(key)
341 : , value(has_value
342 780 : ? value
343 : : core::string_view())
344 1560 : , has_value(has_value)
345 : {
346 780 : }
347 : #endif
348 :
349 : private:
350 16 : param(
351 : core::string_view key,
352 : detail::optional_string const& value)
353 16 : : param(key, value.s, value.b)
354 : {
355 16 : }
356 : };
357 :
358 : //------------------------------------------------
359 :
360 : /** A query parameter
361 :
362 : Objects of this type represent a single key
363 : and value pair in a query string where a key
364 : is always present and may be empty, while the
365 : presence of a value is indicated by
366 : @ref has_value equal to true.
367 : An empty value is distinct from no value.
368 :
369 : Depending on where the object was obtained,
370 : the strings may or may not contain percent
371 : escapes.
372 :
373 : For most usages, key comparisons are
374 : case-sensitive and duplicate keys in
375 : a query are possible. However, it is
376 : the authority that has final control
377 : over how the query is interpreted.
378 :
379 : <br>
380 :
381 : Keys and values in this object reference
382 : external character buffers.
383 : Ownership of the buffers is not transferred;
384 : the caller is responsible for ensuring that
385 : the assigned buffers remain valid until
386 : they are no longer referenced.
387 :
388 : @par BNF
389 : @code
390 : query-params = query-param *( "&" query-param )
391 : query-param = key [ "=" value ]
392 : key = *qpchar
393 : value = *( qpchar / "=" )
394 : @endcode
395 :
396 : @par Specification
397 : @li <a href="https://en.wikipedia.org/wiki/Query_string"
398 : >Query string (Wikipedia)</a>
399 :
400 : @see
401 : @ref param,
402 : @ref param_pct_view.
403 : */
404 : struct param_view
405 : {
406 : /** The key
407 :
408 : For most usages, key comparisons are
409 : case-sensitive and duplicate keys in
410 : a query are possible. However, it is
411 : the authority that has final control
412 : over how the query is interpreted.
413 : */
414 : core::string_view key;
415 :
416 : /** The value
417 :
418 : The presence of a value is indicated by
419 : @ref has_value equal to true.
420 : An empty value is distinct from no value.
421 : */
422 : core::string_view value;
423 :
424 : /** True if a value is present
425 :
426 : The presence of a value is indicated by
427 : `has_value == true`.
428 : An empty value is distinct from no value.
429 : */
430 : bool has_value = false;
431 :
432 : //--------------------------------------------
433 :
434 : /** Constructor
435 :
436 : Default constructed query parameters
437 : have an empty key and no value.
438 :
439 : @par Example
440 : @code
441 : param_view qp;
442 : @endcode
443 :
444 : @par Postconditions
445 : @code
446 : this->key == "" && this->value == "" && this->has_value == false
447 : @endcode
448 :
449 : @par Complexity
450 : Constant.
451 :
452 : @par Exception Safety
453 : Throws nothing.
454 : */
455 : param_view() = default;
456 :
457 : /** Constructor
458 :
459 : This constructs a parameter with a key
460 : and value.
461 : No validation is performed on the strings.
462 : The new key and value reference
463 : the same corresponding underlying
464 : character buffers.
465 : Ownership of the buffers is not transferred;
466 : the caller is responsible for ensuring that
467 : the assigned buffers remain valid until
468 : they are no longer referenced.
469 :
470 : @par Example
471 : @code
472 : param_view qp( "key", "value" );
473 : @endcode
474 :
475 : @par Postconditions
476 : @code
477 : this->key.data() == key.data() && this->value.data() == value.data() && this->has_value == true
478 : @endcode
479 :
480 : @par Complexity
481 : Constant.
482 :
483 : @par Exception Safety
484 : Throws nothing.
485 :
486 : @tparam OptionalString An optional string
487 : type, such as `core::string_view`,
488 : `std::nullptr`, @ref no_value_t, or
489 : `optional<core::string_view>`.
490 :
491 : @param key, value The key and value to set.
492 : */
493 : template <class OptionalString>
494 167 : param_view(
495 : core::string_view key,
496 : OptionalString const& value) noexcept
497 167 : : param_view(key, detail::get_optional_string(value))
498 : {
499 167 : }
500 :
501 : /** Constructor
502 :
503 : This function constructs a param
504 : which references the character buffers
505 : representing the key and value in another
506 : container.
507 : Ownership of the buffers is not transferred;
508 : the caller is responsible for ensuring that
509 : the assigned buffers remain valid until
510 : they are no longer referenced.
511 :
512 : @par Example
513 : @code
514 : param qp( "key", "value" );
515 : param_view qpv( qp );
516 : @endcode
517 :
518 : @par Postconditions
519 : @code
520 : this->key == key && this->value == value && this->has_value == other.has_value
521 : @endcode
522 :
523 : @par Complexity
524 : Constant.
525 :
526 : @par Exception Safety
527 : Throws nothing.
528 :
529 : @param other The param to reference
530 : */
531 740 : param_view(
532 : param const& other) noexcept
533 740 : : param_view(
534 740 : other.key,
535 740 : other.value,
536 740 : other.has_value)
537 : {
538 740 : }
539 :
540 : /** Conversion
541 :
542 : This function performs a conversion from
543 : a reference-like query parameter to one
544 : retaining ownership of the strings by
545 : making a copy.
546 : No validation is performed on the strings.
547 :
548 : @par Complexity
549 : Linear in `this->key.size() + this->value.size()`.
550 :
551 : @par Exception Safety
552 : Calls to allocate may throw.
553 : */
554 : explicit
555 4 : operator
556 : param()
557 : {
558 4 : return { key, value, has_value };
559 : }
560 :
561 : #ifndef BOOST_URL_DOCS
562 : // arrow support
563 : param_view const*
564 : operator->() const noexcept
565 : {
566 : return this;
567 : }
568 :
569 : // aggregate construction
570 1690 : param_view(
571 : core::string_view key_,
572 : core::string_view value_,
573 : bool has_value_) noexcept
574 1690 : : key(key_)
575 : , value(has_value_
576 : ? value_
577 : : core::string_view())
578 1690 : , has_value(has_value_)
579 : {
580 1690 : }
581 : #endif
582 :
583 : private:
584 167 : param_view(
585 : core::string_view key,
586 : detail::optional_string const& value)
587 167 : : param_view(key, value.s, value.b)
588 : {
589 167 : }
590 : };
591 :
592 : //------------------------------------------------
593 :
594 : /** A query parameter
595 :
596 : Objects of this type represent a single key
597 : and value pair in a query string where a key
598 : is always present and may be empty, while the
599 : presence of a value is indicated by
600 : @ref has_value equal to true.
601 : An empty value is distinct from no value.
602 :
603 : The strings may have percent escapes, and
604 : offer an additional invariant: they never
605 : contain an invalid percent-encoding.
606 :
607 : For most usages, key comparisons are
608 : case-sensitive and duplicate keys in
609 : a query are possible. However, it is
610 : the authority that has final control
611 : over how the query is interpreted.
612 :
613 : <br>
614 :
615 : Keys and values in this object reference
616 : external character buffers.
617 : Ownership of the buffers is not transferred;
618 : the caller is responsible for ensuring that
619 : the assigned buffers remain valid until
620 : they are no longer referenced.
621 :
622 : @par BNF
623 : @code
624 : query-params = query-param *( "&" query-param )
625 : query-param = key [ "=" value ]
626 : key = *qpchar
627 : value = *( qpchar / "=" )
628 : @endcode
629 :
630 : @par Specification
631 : @li <a href="https://en.wikipedia.org/wiki/Query_string"
632 : >Query string (Wikipedia)</a>
633 :
634 : @see
635 : @ref param,
636 : @ref param_view.
637 : */
638 : struct param_pct_view
639 : {
640 : /** The key
641 :
642 : For most usages, key comparisons are
643 : case-sensitive and duplicate keys in
644 : a query are possible. However, it is
645 : the authority that has final control
646 : over how the query is interpreted.
647 : */
648 : pct_string_view key;
649 :
650 : /** The value
651 :
652 : The presence of a value is indicated by
653 : @ref has_value equal to true.
654 : An empty value is distinct from no value.
655 : */
656 : pct_string_view value;
657 :
658 : /** True if a value is present
659 :
660 : The presence of a value is indicated by
661 : `has_value == true`.
662 : An empty value is distinct from no value.
663 : */
664 : bool has_value = false;
665 :
666 : //--------------------------------------------
667 :
668 : /** Constructor
669 :
670 : Default constructed query parameters
671 : have an empty key and no value.
672 :
673 : @par Example
674 : @code
675 : param_pct_view qp;
676 : @endcode
677 :
678 : @par Postconditions
679 : @code
680 : this->key == "" && this->value == "" && this->has_value == false
681 : @endcode
682 :
683 : @par Complexity
684 : Constant.
685 :
686 : @par Exception Safety
687 : Throws nothing.
688 : */
689 : param_pct_view() = default;
690 :
691 : /** Constructor
692 :
693 : This constructs a parameter with a key
694 : and value, which may both contain percent
695 : escapes.
696 : The new key and value reference
697 : the same corresponding underlying
698 : character buffers.
699 : Ownership of the buffers is not transferred;
700 : the caller is responsible for ensuring that
701 : the assigned buffers remain valid until
702 : they are no longer referenced.
703 :
704 : @par Example
705 : @code
706 : param_pct_view qp( "key", "value" );
707 : @endcode
708 :
709 : @par Postconditions
710 : @code
711 : this->key.data() == key.data() && this->value.data() == value.data() && this->has_value == true
712 : @endcode
713 :
714 : @par Complexity
715 : Linear in `key.size() + value.size()`.
716 :
717 : @par Exception Safety
718 : Exceptions thrown on invalid input.
719 :
720 : @throw system_error
721 : `key` or `value` contains an invalid percent-encoding.
722 :
723 : @param key, value The key and value to set.
724 : */
725 1086 : param_pct_view(
726 : pct_string_view key,
727 : pct_string_view value) noexcept
728 1086 : : key(key)
729 : , value(value)
730 1086 : , has_value(true)
731 : {
732 1086 : }
733 :
734 : /** Constructor
735 :
736 : This constructs a parameter with a key
737 : and optional value, which may both
738 : contain percent escapes.
739 :
740 : The new key and value reference
741 : the same corresponding underlying
742 : character buffers.
743 :
744 : Ownership of the buffers is not transferred;
745 : the caller is responsible for ensuring that
746 : the assigned buffers remain valid until
747 : they are no longer referenced.
748 :
749 : @par Example
750 : @code
751 : param_pct_view qp( "key", optional<core::string_view>("value") );
752 : @endcode
753 :
754 : @par Postconditions
755 : @code
756 : this->key.data() == key.data() && this->value->data() == value->data() && this->has_value == true
757 : @endcode
758 :
759 : @par Complexity
760 : Linear in `key.size() + value->size()`.
761 :
762 : @par Exception Safety
763 : Exceptions thrown on invalid input.
764 :
765 : @throw system_error
766 : `key` or `value` contains an invalid percent-encoding.
767 :
768 : @tparam OptionalString An optional
769 : `core::string_view` type, such as
770 : `boost::optional<core::string_view>` or
771 : `std::optional<core::string_view>`.
772 :
773 : @param key, value The key and value to set.
774 : */
775 : template <class OptionalString>
776 638 : param_pct_view(
777 : pct_string_view key,
778 : OptionalString const& value)
779 638 : : param_pct_view(key, detail::get_optional_string(value))
780 : {
781 635 : }
782 :
783 : /** Construction
784 :
785 : This converts a param which may
786 : contain unvalidated percent-escapes into
787 : a param whose key and value are
788 : guaranteed to contain strings with no
789 : invalid percent-escapes, otherwise
790 : an exception is thrown.
791 :
792 : The new key and value reference
793 : the same corresponding underlying
794 : character buffers.
795 : Ownership of the buffers is not transferred;
796 : the caller is responsible for ensuring that
797 : the assigned buffers remain valid until
798 : they are no longer referenced.
799 :
800 : @par Example
801 : @code
802 : param_pct_view qp( param_view( "key", "value" ) );
803 : @endcode
804 :
805 : @par Complexity
806 : Linear in `key.size() + value.size()`.
807 :
808 : @par Exception Safety
809 : Exceptions thrown on invalid input.
810 :
811 : @throw system_error
812 : `key` or `value` contains an invalid percent escape.
813 :
814 : @param p The param to construct from.
815 : */
816 : explicit
817 56 : param_pct_view(
818 : param_view const& p)
819 56 : : key(p.key)
820 52 : , value(p.has_value
821 : ? pct_string_view(p.value)
822 : : pct_string_view())
823 56 : , has_value(p.has_value)
824 : {
825 51 : }
826 :
827 : /** Conversion
828 :
829 : This function performs a conversion from
830 : a reference-like query parameter to one
831 : retaining ownership of the strings by
832 : making a copy.
833 :
834 : @par Complexity
835 : Linear in `this->key.size() + this->value.size()`.
836 :
837 : @par Exception Safety
838 : Calls to allocate may throw.
839 : */
840 : explicit
841 2 : operator
842 : param() const
843 : {
844 : return param(
845 2 : static_cast<std::string>(key),
846 2 : static_cast<std::string>(value),
847 4 : has_value);
848 : }
849 :
850 783 : operator
851 : param_view() const noexcept
852 : {
853 : return param_view(
854 783 : key, value, has_value);
855 : }
856 :
857 : #ifndef BOOST_URL_DOCS
858 : // arrow support
859 : param_pct_view const*
860 21 : operator->() const noexcept
861 : {
862 21 : return this;
863 : }
864 :
865 : // aggregate construction
866 635 : param_pct_view(
867 : pct_string_view key,
868 : pct_string_view value,
869 : bool has_value) noexcept
870 635 : : key(key)
871 : , value(has_value
872 : ? value
873 : : pct_string_view())
874 635 : , has_value(has_value)
875 : {
876 635 : }
877 : #endif
878 :
879 : private:
880 638 : param_pct_view(
881 : pct_string_view key,
882 : detail::optional_string const& value)
883 638 : : param_pct_view(key, value.s, value.b)
884 : {
885 635 : }
886 : };
887 :
888 : //------------------------------------------------
889 :
890 : inline
891 : param&
892 1 : param::
893 : operator=(
894 : param_view const& other)
895 : {
896 : // VFALCO operator= assignment
897 : // causes a loss of original capacity:
898 : // https://godbolt.org/z/nYef8445K
899 : //
900 : // key = other.key;
901 : // value = other.value;
902 :
903 : // preserve capacity
904 : key.assign(
905 : other.key.data(),
906 1 : other.key.size());
907 : value.assign(
908 : other.value.data(),
909 1 : other.value.size());
910 1 : has_value = other.has_value;
911 1 : return *this;
912 : }
913 :
914 : inline
915 : param&
916 1 : param::
917 : operator=(
918 : param_pct_view const& other)
919 : {
920 : // preserve capacity
921 : key.assign(
922 : other.key.data(),
923 1 : other.key.size());
924 : value.assign(
925 : other.value.data(),
926 1 : other.value.size());
927 1 : has_value = other.has_value;
928 1 : return *this;
929 : }
930 :
931 : } // urls
932 : } // boost
933 :
934 : #endif
|