params_encoded_base.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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. #ifndef BOOST_URL_PARAMS_ENCODED_BASE_HPP
  11. #define BOOST_URL_PARAMS_ENCODED_BASE_HPP
  12. #include <boost/url/detail/config.hpp>
  13. #include <boost/url/ignore_case.hpp>
  14. #include <boost/url/param.hpp>
  15. #include <boost/url/detail/params_iter_impl.hpp>
  16. #include <boost/url/detail/url_impl.hpp>
  17. #include <iosfwd>
  18. namespace boost {
  19. namespace urls {
  20. /** Common functionality for containers
  21. This base class is used by the library
  22. to provide common member functions for
  23. containers. This cannot be instantiated
  24. directly; Instead, use one of the
  25. containers or functions:
  26. @par Containers
  27. @li @ref params_ref
  28. @li @ref params_view
  29. @li @ref params_encoded_ref
  30. @li @ref params_encoded_view
  31. */
  32. class params_encoded_base
  33. {
  34. friend class url_view_base;
  35. friend class params_encoded_ref;
  36. friend class params_encoded_view;
  37. detail::query_ref ref_;
  38. params_encoded_base() = default;
  39. params_encoded_base(
  40. params_encoded_base const&) = default;
  41. params_encoded_base& operator=(
  42. params_encoded_base const&) = default;
  43. params_encoded_base(
  44. detail::query_ref const& ref) noexcept;
  45. public:
  46. /** A Bidirectional iterator to a query parameter
  47. Objects of this type allow iteration
  48. through the parameters in the query.
  49. Strings returned by iterators may
  50. contain percent escapes.
  51. The values returned are read-only;
  52. changes to parameters must be made
  53. through the container instead, if the
  54. container supports modification.
  55. <br>
  56. The strings produced when iterators
  57. are dereferenced refer to the underlying
  58. character buffer.
  59. Ownership is not transferred; the caller
  60. is responsible for ensuring that the
  61. lifetime of the buffer extends until
  62. it is no longer referenced by any
  63. container or iterator.
  64. */
  65. #ifdef BOOST_URL_DOCS
  66. using iterator = __see_below__;
  67. #else
  68. class iterator;
  69. #endif
  70. /// @copydoc iterator
  71. using const_iterator = iterator;
  72. /** The value type
  73. Values of this type represent parameters
  74. whose strings retain unique ownership by
  75. making a copy.
  76. @par Example
  77. @code
  78. params_encoded_view::value_type qp( *url_view( "?first=John&last=Doe" ).params().find( "first" ) );
  79. @endcode
  80. @see
  81. @ref param.
  82. */
  83. using value_type = param;
  84. /** The reference type
  85. This is the type of value returned when
  86. iterators of the view are dereferenced.
  87. @see
  88. @ref param_view.
  89. */
  90. using reference = param_pct_view;
  91. /// @copydoc reference
  92. using const_reference = param_pct_view;
  93. /** An unsigned integer type to represent sizes.
  94. */
  95. using size_type = std::size_t;
  96. /** A signed integer type used to represent differences.
  97. */
  98. using difference_type = std::ptrdiff_t;
  99. //--------------------------------------------
  100. //
  101. // Observers
  102. //
  103. //--------------------------------------------
  104. /** Return the maximum number of characters possible
  105. This represents the largest number of
  106. characters that are possible in a path,
  107. not including any null terminator.
  108. @par Exception Safety
  109. Throws nothing.
  110. */
  111. static
  112. constexpr
  113. std::size_t
  114. max_size() noexcept
  115. {
  116. return BOOST_URL_MAX_SIZE;
  117. }
  118. /** Return the query corresponding to these params
  119. This function returns the query string
  120. referenced by the container.
  121. The returned string may contain
  122. percent escapes.
  123. @par Example
  124. @code
  125. assert( url_view( "?first=John&last=Doe" ).encoded_params().buffer() == "first=John&last=Doe" );
  126. @endcode
  127. @par Complexity
  128. Constant.
  129. @par Exception Safety
  130. Throws nothing.
  131. @par BNF
  132. @code
  133. query-params = query-param *( "&" query-param )
  134. query-param = key [ "=" value ]
  135. key = *qpchar
  136. value = *( qpchar / "=" )
  137. @endcode
  138. @par Specification
  139. @li <a href="https://en.wikipedia.org/wiki/Query_string"
  140. >Query string (Wikipedia)</a>
  141. */
  142. BOOST_URL_DECL
  143. pct_string_view
  144. buffer() const noexcept;
  145. /** Return true if there are no params
  146. @par Example
  147. @code
  148. assert( ! url_view( "?key=value" ).encoded_params().empty() );
  149. @endcode
  150. @par Complexity
  151. Constant.
  152. @par Exception Safety
  153. Throws nothing.
  154. */
  155. BOOST_URL_DECL
  156. bool
  157. empty() const noexcept;
  158. /** Return the number of params
  159. @par Example
  160. @code
  161. assert( url_view( "?key=value").encoded_params().size() == 1 );
  162. @endcode
  163. @par Complexity
  164. Constant.
  165. @par Exception Safety
  166. Throws nothing.
  167. */
  168. BOOST_URL_DECL
  169. std::size_t
  170. size() const noexcept;
  171. /** Return an iterator to the beginning
  172. @par Complexity
  173. Linear in the size of the first param.
  174. @par Exception Safety
  175. Throws nothing.
  176. */
  177. BOOST_URL_DECL
  178. iterator
  179. begin() const noexcept;
  180. /** Return an iterator to the end
  181. @par Complexity
  182. Constant.
  183. @par Exception Safety
  184. Throws nothing.
  185. */
  186. BOOST_URL_DECL
  187. iterator
  188. end() const noexcept;
  189. //--------------------------------------------
  190. /** Return true if a matching key exists
  191. This function examines the parameters
  192. in the container to find a match for
  193. the specified key,
  194. which may contain percent escapes.
  195. The comparison is performed as if all
  196. escaped characters were decoded first.
  197. @par Example
  198. @code
  199. assert( url_view( "?first=John&last=Doe" ).encoded_params().contains( "first" ) );
  200. @endcode
  201. @par Complexity
  202. Linear in `this->buffer().size()`.
  203. @par Exception Safety
  204. Exceptions thrown on invalid input.
  205. @throw system_error
  206. `key` contains an invalid percent-encoding.
  207. @param key The key to match.
  208. By default, a case-sensitive
  209. comparison is used.
  210. @param ic An optional parameter. If
  211. the value @ref ignore_case is passed
  212. here, the comparison is
  213. case-insensitive.
  214. */
  215. bool
  216. contains(
  217. pct_string_view key,
  218. ignore_case_param ic = {}) const noexcept;
  219. /** Return the number of matching keys
  220. This function examines the parameters
  221. in the container to find the number of
  222. matches for the specified key,
  223. which may contain percent escapes.
  224. The comparison is performed as if all
  225. escaped characters were decoded first.
  226. @par Example
  227. @code
  228. assert( url_view( "?first=John&last=Doe" ).encoded_params().count( "first" ) == 1 );
  229. @endcode
  230. @par Complexity
  231. Linear in `this->buffer().size()`.
  232. @par Exception Safety
  233. Exceptions thrown on invalid input.
  234. @throw system_error
  235. `key` contains an invalid percent-encoding.
  236. @param key The key to match.
  237. By default, a case-sensitive
  238. comparison is used.
  239. @param ic An optional parameter. If
  240. the value @ref ignore_case is passed
  241. here, the comparison is
  242. case-insensitive.
  243. */
  244. BOOST_URL_DECL
  245. std::size_t
  246. count(
  247. pct_string_view key,
  248. ignore_case_param ic = {}) const noexcept;
  249. /** Find a matching key
  250. This function examines the parameters
  251. in the container to find a match for
  252. the specified key,
  253. which may contain percent escapes.
  254. The comparison is performed as if all
  255. escaped characters were decoded first.
  256. <br>
  257. The search starts from the first param
  258. and proceeds forward until either the
  259. key is found or the end of the range is
  260. reached, in which case `end()` is
  261. returned.
  262. @par Example
  263. @code
  264. assert( url_view( "?first=John&last=Doe" ).encoded_params().find( "First", ignore_case )->value == "John" );
  265. @endcode
  266. @par Effects
  267. @code
  268. return this->find( this->begin(), key, ic );
  269. @endcode
  270. @par Complexity
  271. Linear in `this->buffer().size()`.
  272. @par Exception Safety
  273. Exceptions thrown on invalid input.
  274. @throw system_error
  275. `key` contains an invalid percent-encoding.
  276. @return an iterator to the param
  277. @param key The key to match.
  278. By default, a case-sensitive
  279. comparison is used.
  280. @param ic An optional parameter. If
  281. the value @ref ignore_case is passed
  282. here, the comparison is
  283. case-insensitive.
  284. */
  285. iterator
  286. find(
  287. pct_string_view key,
  288. ignore_case_param ic = {}) const noexcept;
  289. /** Find a matching key
  290. This function examines the parameters
  291. in the container to find a match for
  292. the specified key, which may contain
  293. percent escapes.
  294. The comparison is performed as if all
  295. escaped characters were decoded first.
  296. <br>
  297. The search starts at `from`
  298. and proceeds forward until either the
  299. key is found or the end of the range is
  300. reached, in which case `end()` is
  301. returned.
  302. @par Example
  303. @code
  304. url_view u( "?First=John&Last=Doe" );
  305. assert( u.encoded_params().find( "first" ) != u.encoded_params().find( "first", ignore_case ) );
  306. @endcode
  307. @par Complexity
  308. Linear in `this->buffer().size()`.
  309. @par Exception Safety
  310. Exceptions thrown on invalid input.
  311. @throw system_error
  312. `key` contains an invalid percent-encoding.
  313. @return an iterator to the param
  314. @param from The position to begin the
  315. search from. This can be `end()`.
  316. @param key The key to match.
  317. By default, a case-sensitive
  318. comparison is used.
  319. @param ic An optional parameter. If
  320. the value @ref ignore_case is passed
  321. here, the comparison is
  322. case-insensitive.
  323. */
  324. iterator
  325. find(
  326. iterator from,
  327. pct_string_view key,
  328. ignore_case_param ic = {}) const noexcept;
  329. /** Find a matching key
  330. This function examines the parameters
  331. in the container to find a match for
  332. the specified key, which may contain
  333. percent escapes.
  334. The comparison is performed as if all
  335. escaped characters were decoded first.
  336. <br>
  337. The search starts from the last param
  338. and proceeds backwards until either the
  339. key is found or the beginning of the
  340. range is reached, in which case `end()`
  341. is returned.
  342. @par Example
  343. @code
  344. assert( url_view( "?first=John&last=Doe" ).encoded_params().find_last( "last" )->value == "Doe" );
  345. @endcode
  346. @par Complexity
  347. Linear in `this->buffer().size()`.
  348. @par Exception Safety
  349. Exceptions thrown on invalid input.
  350. @throw system_error
  351. `key` contains an invalid percent-encoding.
  352. @return an iterator to the param
  353. @param key The key to match.
  354. By default, a case-sensitive
  355. comparison is used.
  356. @param ic An optional parameter. If
  357. the value @ref ignore_case is passed
  358. here, the comparison is
  359. case-insensitive.
  360. */
  361. iterator
  362. find_last(
  363. pct_string_view key,
  364. ignore_case_param ic = {}) const noexcept;
  365. /** Find a matching key
  366. This function examines the parameters
  367. in the container to find a match for
  368. the specified key, which may contain
  369. percent escapes.
  370. The comparison is performed as if all
  371. escaped characters were decoded first.
  372. <br>
  373. The search starts prior to `before`
  374. and proceeds backwards until either the
  375. key is found or the beginning of the
  376. range is reached, in which case `end()`
  377. is returned.
  378. @par Example
  379. @code
  380. url_view u( "?First=John&Last=Doe" );
  381. assert( u.encoded_params().find_last( "last" ) != u.encoded_params().find_last( "last", ignore_case ) );
  382. @endcode
  383. @par Complexity
  384. Linear in `this->buffer().size()`.
  385. @return an iterator to the param
  386. @param before One past the position
  387. to begin the search from. This can
  388. be `end()`.
  389. @param key The key to match.
  390. By default, a case-sensitive
  391. comparison is used.
  392. @param ic An optional parameter. If
  393. the value @ref ignore_case is passed
  394. here, the comparison is
  395. case-insensitive.
  396. */
  397. iterator
  398. find_last(
  399. iterator before,
  400. pct_string_view key,
  401. ignore_case_param ic = {}) const noexcept;
  402. private:
  403. BOOST_URL_DECL
  404. detail::params_iter_impl
  405. find_impl(
  406. detail::params_iter_impl,
  407. pct_string_view,
  408. ignore_case_param) const noexcept;
  409. BOOST_URL_DECL
  410. detail::params_iter_impl
  411. find_last_impl(
  412. detail::params_iter_impl,
  413. pct_string_view,
  414. ignore_case_param) const noexcept;
  415. };
  416. //------------------------------------------------
  417. /** Format to an output stream
  418. Any percent-escapes are emitted as-is;
  419. no decoding is performed.
  420. @par Complexity
  421. Linear in `ps.buffer().size()`.
  422. @par Effects
  423. @code
  424. return os << ps.buffer();
  425. @endcode
  426. */
  427. BOOST_URL_DECL
  428. std::ostream&
  429. operator<<(
  430. std::ostream& os,
  431. params_encoded_base const& qp);
  432. } // urls
  433. } // boost
  434. #include <boost/url/impl/params_encoded_base.hpp>
  435. #endif