params_encoded_base.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. //
  2. // Copyright (c) 2019 Vinnie Falco ([email protected])
  3. // Copyright (c) 2022 Alan de Freitas ([email protected])
  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 BOOST_URL_DECL 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. pct_string_view
  143. buffer() const noexcept;
  144. /** Return true if there are no params
  145. @par Example
  146. @code
  147. assert( ! url_view( "?key=value" ).encoded_params().empty() );
  148. @endcode
  149. @par Complexity
  150. Constant.
  151. @par Exception Safety
  152. Throws nothing.
  153. */
  154. bool
  155. empty() const noexcept;
  156. /** Return the number of params
  157. @par Example
  158. @code
  159. assert( url_view( "?key=value").encoded_params().size() == 1 );
  160. @endcode
  161. @par Complexity
  162. Constant.
  163. @par Exception Safety
  164. Throws nothing.
  165. */
  166. std::size_t
  167. size() const noexcept;
  168. /** Return an iterator to the beginning
  169. @par Complexity
  170. Linear in the size of the first param.
  171. @par Exception Safety
  172. Throws nothing.
  173. */
  174. iterator
  175. begin() const noexcept;
  176. /** Return an iterator to the end
  177. @par Complexity
  178. Constant.
  179. @par Exception Safety
  180. Throws nothing.
  181. */
  182. iterator
  183. end() const noexcept;
  184. //--------------------------------------------
  185. /** Return true if a matching key exists
  186. This function examines the parameters
  187. in the container to find a match for
  188. the specified key,
  189. which may contain percent escapes.
  190. The comparison is performed as if all
  191. escaped characters were decoded first.
  192. @par Example
  193. @code
  194. assert( url_view( "?first=John&last=Doe" ).encoded_params().contains( "first" ) );
  195. @endcode
  196. @par Complexity
  197. Linear in `this->buffer().size()`.
  198. @par Exception Safety
  199. Exceptions thrown on invalid input.
  200. @throw system_error
  201. `key` contains an invalid percent-encoding.
  202. @param key The key to match.
  203. By default, a case-sensitive
  204. comparison is used.
  205. @param ic An optional parameter. If
  206. the value @ref ignore_case is passed
  207. here, the comparison is
  208. case-insensitive.
  209. */
  210. bool
  211. contains(
  212. pct_string_view key,
  213. ignore_case_param ic = {}) const noexcept;
  214. /** Return the number of matching keys
  215. This function examines the parameters
  216. in the container to find the number of
  217. matches for the specified key,
  218. which may contain percent escapes.
  219. The comparison is performed as if all
  220. escaped characters were decoded first.
  221. @par Example
  222. @code
  223. assert( url_view( "?first=John&last=Doe" ).encoded_params().count( "first" ) == 1 );
  224. @endcode
  225. @par Complexity
  226. Linear in `this->buffer().size()`.
  227. @par Exception Safety
  228. Exceptions thrown on invalid input.
  229. @throw system_error
  230. `key` contains an invalid percent-encoding.
  231. @param key The key to match.
  232. By default, a case-sensitive
  233. comparison is used.
  234. @param ic An optional parameter. If
  235. the value @ref ignore_case is passed
  236. here, the comparison is
  237. case-insensitive.
  238. */
  239. std::size_t
  240. count(
  241. pct_string_view key,
  242. ignore_case_param ic = {}) const noexcept;
  243. /** Find a matching key
  244. This function examines the parameters
  245. in the container to find a match for
  246. the specified key,
  247. which may contain percent escapes.
  248. The comparison is performed as if all
  249. escaped characters were decoded first.
  250. <br>
  251. The search starts from the first param
  252. and proceeds forward until either the
  253. key is found or the end of the range is
  254. reached, in which case `end()` is
  255. returned.
  256. @par Example
  257. @code
  258. assert( url_view( "?first=John&last=Doe" ).encoded_params().find( "First", ignore_case )->value == "John" );
  259. @endcode
  260. @par Effects
  261. @code
  262. return this->find( this->begin(), key, ic );
  263. @endcode
  264. @par Complexity
  265. Linear in `this->buffer().size()`.
  266. @par Exception Safety
  267. Exceptions thrown on invalid input.
  268. @throw system_error
  269. `key` contains an invalid percent-encoding.
  270. @return an iterator to the param
  271. @param key The key to match.
  272. By default, a case-sensitive
  273. comparison is used.
  274. @param ic An optional parameter. If
  275. the value @ref ignore_case is passed
  276. here, the comparison is
  277. case-insensitive.
  278. */
  279. iterator
  280. find(
  281. pct_string_view key,
  282. ignore_case_param ic = {}) const noexcept;
  283. /** Find a matching key
  284. This function examines the parameters
  285. in the container to find a match for
  286. the specified key, which may contain
  287. percent escapes.
  288. The comparison is performed as if all
  289. escaped characters were decoded first.
  290. <br>
  291. The search starts at `from`
  292. and proceeds forward until either the
  293. key is found or the end of the range is
  294. reached, in which case `end()` is
  295. returned.
  296. @par Example
  297. @code
  298. url_view u( "?First=John&Last=Doe" );
  299. assert( u.encoded_params().find( "first" ) != u.encoded_params().find( "first", ignore_case ) );
  300. @endcode
  301. @par Complexity
  302. Linear in `this->buffer().size()`.
  303. @par Exception Safety
  304. Exceptions thrown on invalid input.
  305. @throw system_error
  306. `key` contains an invalid percent-encoding.
  307. @return an iterator to the param
  308. @param from The position to begin the
  309. search from. This can be `end()`.
  310. @param key The key to match.
  311. By default, a case-sensitive
  312. comparison is used.
  313. @param ic An optional parameter. If
  314. the value @ref ignore_case is passed
  315. here, the comparison is
  316. case-insensitive.
  317. */
  318. iterator
  319. find(
  320. iterator from,
  321. pct_string_view key,
  322. ignore_case_param ic = {}) const noexcept;
  323. /** Find a matching key
  324. This function examines the parameters
  325. in the container to find a match for
  326. the specified key, which may contain
  327. percent escapes.
  328. The comparison is performed as if all
  329. escaped characters were decoded first.
  330. <br>
  331. The search starts from the last param
  332. and proceeds backwards until either the
  333. key is found or the beginning of the
  334. range is reached, in which case `end()`
  335. is returned.
  336. @par Example
  337. @code
  338. assert( url_view( "?first=John&last=Doe" ).encoded_params().find_last( "last" )->value == "Doe" );
  339. @endcode
  340. @par Complexity
  341. Linear in `this->buffer().size()`.
  342. @par Exception Safety
  343. Exceptions thrown on invalid input.
  344. @throw system_error
  345. `key` contains an invalid percent-encoding.
  346. @return an iterator to the param
  347. @param key The key to match.
  348. By default, a case-sensitive
  349. comparison is used.
  350. @param ic An optional parameter. If
  351. the value @ref ignore_case is passed
  352. here, the comparison is
  353. case-insensitive.
  354. */
  355. iterator
  356. find_last(
  357. pct_string_view key,
  358. ignore_case_param ic = {}) const noexcept;
  359. /** Find a matching key
  360. This function examines the parameters
  361. in the container to find a match for
  362. the specified key, which may contain
  363. percent escapes.
  364. The comparison is performed as if all
  365. escaped characters were decoded first.
  366. <br>
  367. The search starts prior to `before`
  368. and proceeds backwards until either the
  369. key is found or the beginning of the
  370. range is reached, in which case `end()`
  371. is returned.
  372. @par Example
  373. @code
  374. url_view u( "?First=John&Last=Doe" );
  375. assert( u.encoded_params().find_last( "last" ) != u.encoded_params().find_last( "last", ignore_case ) );
  376. @endcode
  377. @par Complexity
  378. Linear in `this->buffer().size()`.
  379. @return an iterator to the param
  380. @param before One past the position
  381. to begin the search from. This can
  382. be `end()`.
  383. @param key The key to match.
  384. By default, a case-sensitive
  385. comparison is used.
  386. @param ic An optional parameter. If
  387. the value @ref ignore_case is passed
  388. here, the comparison is
  389. case-insensitive.
  390. */
  391. iterator
  392. find_last(
  393. iterator before,
  394. pct_string_view key,
  395. ignore_case_param ic = {}) const noexcept;
  396. private:
  397. detail::params_iter_impl
  398. find_impl(
  399. detail::params_iter_impl,
  400. pct_string_view,
  401. ignore_case_param) const noexcept;
  402. detail::params_iter_impl
  403. find_last_impl(
  404. detail::params_iter_impl,
  405. pct_string_view,
  406. ignore_case_param) const noexcept;
  407. };
  408. //------------------------------------------------
  409. /** Format to an output stream
  410. Any percent-escapes are emitted as-is;
  411. no decoding is performed.
  412. @par Complexity
  413. Linear in `ps.buffer().size()`.
  414. @par Effects
  415. @code
  416. return os << ps.buffer();
  417. @endcode
  418. */
  419. BOOST_URL_DECL
  420. std::ostream&
  421. operator<<(
  422. std::ostream& os,
  423. params_encoded_base const& qp);
  424. } // urls
  425. } // boost
  426. #include <boost/url/impl/params_encoded_base.hpp>
  427. #endif