Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // | ||
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
6 | // | ||
7 | // Official repository: https://github.com/boostorg/url | ||
8 | // | ||
9 | |||
10 | #ifndef BOOST_URL_STATIC_URL_HPP | ||
11 | #define BOOST_URL_STATIC_URL_HPP | ||
12 | |||
13 | #include <boost/url/detail/config.hpp> | ||
14 | #include <boost/url/url_base.hpp> | ||
15 | #include <boost/align/align_up.hpp> | ||
16 | #include <boost/static_assert.hpp> | ||
17 | #include <cstddef> | ||
18 | |||
19 | namespace boost { | ||
20 | namespace urls { | ||
21 | |||
22 | #ifndef BOOST_URL_DOCS | ||
23 | template<std::size_t Capacity> | ||
24 | class static_url; | ||
25 | #endif | ||
26 | |||
27 | // VFALCO This class is for reducing | ||
28 | // the number of template instantiations, | ||
29 | // and keep definitions in the library | ||
30 | |||
31 | /** Common implementation for all static URLs | ||
32 | |||
33 | This base class is used by the library | ||
34 | to provide common functionality for | ||
35 | static URLs. Users should not use this | ||
36 | class directly. Instead, construct an | ||
37 | instance of one of the containers | ||
38 | or call a parsing function. | ||
39 | |||
40 | @par Containers | ||
41 | @li @ref url | ||
42 | @li @ref url_view | ||
43 | @li @ref static_url | ||
44 | |||
45 | @par Parsing Functions | ||
46 | @li @ref parse_absolute_uri | ||
47 | @li @ref parse_origin_form | ||
48 | @li @ref parse_relative_ref | ||
49 | @li @ref parse_uri | ||
50 | @li @ref parse_uri_reference | ||
51 | */ | ||
52 | class BOOST_URL_DECL | ||
53 | static_url_base | ||
54 | : public url_base | ||
55 | { | ||
56 | template<std::size_t> | ||
57 | friend class static_url; | ||
58 | |||
59 | 58 | ~static_url_base() = default; | |
60 | static_url_base( | ||
61 | char* buf, std::size_t cap) noexcept; | ||
62 | static_url_base( | ||
63 | char* buf, std::size_t cap, core::string_view s); | ||
64 | void clear_impl() noexcept override; | ||
65 | void reserve_impl(std::size_t, op_t&) override; | ||
66 | void cleanup(op_t&) override; | ||
67 | |||
68 | void | ||
69 | 24 | copy(url_view_base const& u) | |
70 | { | ||
71 | 24 | this->url_base::copy(u); | |
72 | 21 | } | |
73 | |||
74 | }; | ||
75 | |||
76 | //------------------------------------------------ | ||
77 | |||
78 | /** A modifiable container for a URL. | ||
79 | |||
80 | This container owns a url, represented | ||
81 | by an inline, null-terminated character | ||
82 | buffer with fixed capacity. | ||
83 | The contents may be inspected and modified, | ||
84 | and the implementation maintains a useful | ||
85 | invariant: changes to the url always | ||
86 | leave it in a valid state. | ||
87 | |||
88 | @par Example | ||
89 | @code | ||
90 | static_url< 1024 > u( "https://www.example.com" ); | ||
91 | @endcode | ||
92 | |||
93 | @par Invariants | ||
94 | @code | ||
95 | this->capacity() == Capacity | ||
96 | @endcode | ||
97 | |||
98 | @tparam Capacity The maximum capacity | ||
99 | in characters, not including the | ||
100 | null terminator. | ||
101 | |||
102 | @see | ||
103 | @ref url, | ||
104 | @ref url_view. | ||
105 | */ | ||
106 | template<std::size_t Capacity> | ||
107 | class static_url | ||
108 | : public static_url_base | ||
109 | { | ||
110 | char buf_[Capacity + 1]; | ||
111 | |||
112 | friend std::hash<static_url>; | ||
113 | using url_view_base::digest; | ||
114 | |||
115 | public: | ||
116 | //-------------------------------------------- | ||
117 | // | ||
118 | // Special Members | ||
119 | // | ||
120 | //-------------------------------------------- | ||
121 | |||
122 | /** Destructor | ||
123 | |||
124 | Any params, segments, iterators, or | ||
125 | views which reference this object are | ||
126 | invalidated. The underlying character | ||
127 | buffer is destroyed, invalidating all | ||
128 | references to it. | ||
129 | */ | ||
130 | 54 | ~static_url() = default; | |
131 | |||
132 | /** Constructor | ||
133 | |||
134 | Default constructed urls contain | ||
135 | a zero-length string. This matches | ||
136 | the grammar for a relative-ref with | ||
137 | an empty path and no query or | ||
138 | fragment. | ||
139 | |||
140 | @par Example | ||
141 | @code | ||
142 | static_url< 1024 > u; | ||
143 | @endcode | ||
144 | |||
145 | @par Postconditions | ||
146 | @code | ||
147 | this->empty() == true | ||
148 | @endcode | ||
149 | |||
150 | @par Complexity | ||
151 | Constant. | ||
152 | |||
153 | @par Exception Safety | ||
154 | Throws nothing. | ||
155 | |||
156 | @par BNF | ||
157 | @code | ||
158 | relative-ref = relative-part [ "?" query ] [ "#" fragment ] | ||
159 | @endcode | ||
160 | |||
161 | @par Specification | ||
162 | <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.2" | ||
163 | >4.2. Relative Reference (rfc3986)</a> | ||
164 | */ | ||
165 | 28 | static_url() noexcept | |
166 | : static_url_base( | ||
167 | 28 | buf_, sizeof(buf_)) | |
168 | { | ||
169 | 28 | } | |
170 | |||
171 | /** Constructor | ||
172 | |||
173 | This function constructs a url from | ||
174 | the string `s`, which must contain a | ||
175 | valid <em>URI</em> or <em>relative-ref</em> | ||
176 | or else an exception is thrown. | ||
177 | The new url retains ownership by | ||
178 | making a copy of the passed string. | ||
179 | |||
180 | @par Example | ||
181 | @code | ||
182 | static_url< 1024 > u( "https://www.example.com" ); | ||
183 | @endcode | ||
184 | |||
185 | @par Effects | ||
186 | @code | ||
187 | return static_url( parse_uri_reference( s ).value() ); | ||
188 | @endcode | ||
189 | |||
190 | @par Postconditions | ||
191 | @code | ||
192 | this->buffer().data() != s.data() | ||
193 | @endcode | ||
194 | |||
195 | @par Complexity | ||
196 | Linear in `s.size()`. | ||
197 | |||
198 | @par Exception Safety | ||
199 | Exceptions thrown on invalid input. | ||
200 | |||
201 | @throw system_error | ||
202 | The input does not contain a valid url. | ||
203 | |||
204 | @param s The string to parse. | ||
205 | |||
206 | @par BNF | ||
207 | @code | ||
208 | URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] | ||
209 | |||
210 | relative-ref = relative-part [ "?" query ] [ "#" fragment ] | ||
211 | @endcode | ||
212 | |||
213 | @par Specification | ||
214 | @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.1" | ||
215 | >4.1. URI Reference</a> | ||
216 | */ | ||
217 | explicit | ||
218 | 30 | static_url( | |
219 | core::string_view s) | ||
220 | : static_url_base( | ||
221 | 30 | buf_, sizeof(buf_), s) | |
222 | { | ||
223 | 26 | } | |
224 | |||
225 | /** Constructor | ||
226 | |||
227 | The newly constructed object contains | ||
228 | a copy of `u`. | ||
229 | |||
230 | @par Postconditions | ||
231 | @code | ||
232 | this->buffer() == u.buffer() && this->buffer.data() != u.buffer().data() | ||
233 | @endcode | ||
234 | |||
235 | @par Complexity | ||
236 | Linear in `u.size()`. | ||
237 | |||
238 | @par Exception Safety | ||
239 | Exception thrown if maximum size exceeded. | ||
240 | |||
241 | @param u The url to copy. | ||
242 | */ | ||
243 | ✗ | static_url( | |
244 | static_url const& u) noexcept | ||
245 | ✗ | : static_url() | |
246 | { | ||
247 | ✗ | copy(u); | |
248 | ✗ | } | |
249 | |||
250 | /** Constructor | ||
251 | |||
252 | The newly constructed object contains | ||
253 | a copy of `u`. | ||
254 | |||
255 | @par Postconditions | ||
256 | @code | ||
257 | this->buffer() == u.buffer() && this->buffer.data() != u.buffer().data() | ||
258 | @endcode | ||
259 | |||
260 | @par Complexity | ||
261 | Linear in `u.size()`. | ||
262 | |||
263 | @par Exception Safety | ||
264 | Exception thrown if capacity exceeded. | ||
265 | |||
266 | @throw system_error | ||
267 | Capacity would be exceeded. | ||
268 | |||
269 | @param u The url to copy. | ||
270 | */ | ||
271 | 10 | static_url( | |
272 | url_view_base const& u) | ||
273 | 12 | : static_url() | |
274 | { | ||
275 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
|
10 | copy(u); |
276 | 8 | } | |
277 | |||
278 | /** Assignment | ||
279 | |||
280 | The contents of `u` are copied and | ||
281 | the previous contents of `this` are | ||
282 | discarded. | ||
283 | Capacity remains unchanged. | ||
284 | |||
285 | @par Postconditions | ||
286 | @code | ||
287 | this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data() | ||
288 | @endcode | ||
289 | |||
290 | @par Complexity | ||
291 | Linear in `u.size()`. | ||
292 | |||
293 | @par Exception Safety | ||
294 | Throws nothing. | ||
295 | |||
296 | @param u The url to copy. | ||
297 | */ | ||
298 | static_url& | ||
299 | operator=( | ||
300 | static_url const& u) noexcept | ||
301 | { | ||
302 | if (this != &u) | ||
303 | copy(u); | ||
304 | return *this; | ||
305 | } | ||
306 | |||
307 | /** Assignment | ||
308 | |||
309 | The contents of `u` are copied and | ||
310 | the previous contents of `this` are | ||
311 | discarded. | ||
312 | |||
313 | @par Postconditions | ||
314 | @code | ||
315 | this->buffer() == u.buffer() && this->buffer().data() != u.buffer().data() | ||
316 | @endcode | ||
317 | |||
318 | @par Complexity | ||
319 | Linear in `u.size()`. | ||
320 | |||
321 | @par Exception Safety | ||
322 | Strong guarantee. | ||
323 | Exception thrown if capacity exceeded. | ||
324 | |||
325 | @throw system_error | ||
326 | Capacity would be exceeded. | ||
327 | |||
328 | @param u The url to copy. | ||
329 | */ | ||
330 | static_url& | ||
331 | 5 | operator=( | |
332 | url_view_base const& u) | ||
333 | { | ||
334 | 5 | copy(u); | |
335 | 4 | return *this; | |
336 | } | ||
337 | |||
338 | |||
339 | //-------------------------------------------- | ||
340 | // | ||
341 | // fluent api | ||
342 | // | ||
343 | |||
344 | /// @copydoc url_base::set_scheme | ||
345 | static_url& set_scheme(core::string_view s) { url_base::set_scheme(s); return *this; } | ||
346 | /// @copydoc url_base::set_scheme_id | ||
347 | static_url& set_scheme_id(urls::scheme id) { url_base::set_scheme_id(id); return *this; } | ||
348 | /// @copydoc url_base::remove_scheme | ||
349 | static_url& remove_scheme() { url_base::remove_scheme(); return *this; } | ||
350 | |||
351 | /// @copydoc url_base::set_encoded_authority | ||
352 | static_url& set_encoded_authority(pct_string_view s) { url_base::set_encoded_authority(s); return *this; } | ||
353 | /// @copydoc url_base::remove_authority | ||
354 | static_url& remove_authority() { url_base::remove_authority(); return *this; } | ||
355 | |||
356 | /// @copydoc url_base::set_userinfo | ||
357 | static_url& set_userinfo(core::string_view s) { url_base::set_userinfo(s); return *this; } | ||
358 | /// @copydoc url_base::set_encoded_userinfo | ||
359 | static_url& set_encoded_userinfo(pct_string_view s) { url_base::set_encoded_userinfo(s); return *this; } | ||
360 | /// @copydoc url_base::remove_userinfo | ||
361 | static_url& remove_userinfo() noexcept { url_base::remove_userinfo(); return *this; } | ||
362 | /// @copydoc url_base::set_user | ||
363 | static_url& set_user(core::string_view s) { url_base::set_user(s); return *this; } | ||
364 | /// @copydoc url_base::set_encoded_user | ||
365 | static_url& set_encoded_user(pct_string_view s) { url_base::set_encoded_user(s); return *this; } | ||
366 | /// @copydoc url_base::set_password | ||
367 | static_url& set_password(core::string_view s) { url_base::set_password(s); return *this; } | ||
368 | /// @copydoc url_base::set_encoded_password | ||
369 | static_url& set_encoded_password(pct_string_view s) { url_base::set_encoded_password(s); return *this; } | ||
370 | /// @copydoc url_base::remove_password | ||
371 | static_url& remove_password() noexcept { url_base::remove_password(); return *this; } | ||
372 | |||
373 | /// @copydoc url_base::set_host | ||
374 | static_url& set_host(core::string_view s) { url_base::set_host(s); return *this; } | ||
375 | /// @copydoc url_base::set_encoded_host | ||
376 | static_url& set_encoded_host(pct_string_view s) { url_base::set_encoded_host(s); return *this; } | ||
377 | /// @copydoc url_base::set_host_address | ||
378 | static_url& set_host_address(core::string_view s) { url_base::set_host_address(s); return *this; } | ||
379 | /// @copydoc url_base::set_encoded_host_address | ||
380 | static_url& set_encoded_host_address(pct_string_view s) { url_base::set_encoded_host_address(s); return *this; } | ||
381 | /// @copydoc url_base::set_host_ipv4 | ||
382 | static_url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; } | ||
383 | /// @copydoc url_base::set_host_ipv6 | ||
384 | static_url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; } | ||
385 | /// @copydoc url_base::set_host_ipvfuture | ||
386 | static_url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; } | ||
387 | /// @copydoc url_base::set_host_name | ||
388 | static_url& set_host_name(core::string_view s) { url_base::set_host_name(s); return *this; } | ||
389 | /// @copydoc url_base::set_encoded_host_name | ||
390 | static_url& set_encoded_host_name(pct_string_view s) { url_base::set_encoded_host_name(s); return *this; } | ||
391 | /// @copydoc url_base::set_port_number | ||
392 | static_url& set_port_number(std::uint16_t n) { url_base::set_port_number(n); return *this; } | ||
393 | /// @copydoc url_base::set_port | ||
394 | static_url& set_port(core::string_view s) { url_base::set_port(s); return *this; } | ||
395 | /// @copydoc url_base::remove_port | ||
396 | static_url& remove_port() noexcept { url_base::remove_port(); return *this; } | ||
397 | |||
398 | /// @copydoc url_base::set_path_absolute | ||
399 | //bool set_path_absolute(bool absolute); | ||
400 | /// @copydoc url_base::set_path | ||
401 | static_url& set_path(core::string_view s) { url_base::set_path(s); return *this; } | ||
402 | /// @copydoc url_base::set_encoded_path | ||
403 | static_url& set_encoded_path(pct_string_view s) { url_base::set_encoded_path(s); return *this; } | ||
404 | |||
405 | /// @copydoc url_base::set_query | ||
406 | static_url& set_query(core::string_view s) { url_base::set_query(s); return *this; } | ||
407 | /// @copydoc url_base::set_encoded_query | ||
408 | static_url& set_encoded_query(pct_string_view s) { url_base::set_encoded_query(s); return *this; } | ||
409 | /// @copydoc url_base::remove_query | ||
410 | static_url& remove_query() noexcept { url_base::remove_query(); return *this; } | ||
411 | |||
412 | /// @copydoc url_base::remove_fragment | ||
413 | static_url& remove_fragment() noexcept { url_base::remove_fragment(); return *this; } | ||
414 | /// @copydoc url_base::set_fragment | ||
415 | static_url& set_fragment(core::string_view s) { url_base::set_fragment(s); return *this; } | ||
416 | /// @copydoc url_base::set_encoded_fragment | ||
417 | static_url& set_encoded_fragment(pct_string_view s) { url_base::set_encoded_fragment(s); return *this; } | ||
418 | |||
419 | /// @copydoc url_base::remove_origin | ||
420 | static_url& remove_origin() { url_base::remove_origin(); return *this; } | ||
421 | |||
422 | /// @copydoc url_base::normalize | ||
423 | static_url& normalize() { url_base::normalize(); return *this; } | ||
424 | /// @copydoc url_base::normalize_scheme | ||
425 | static_url& normalize_scheme() { url_base::normalize_scheme(); return *this; } | ||
426 | /// @copydoc url_base::normalize_authority | ||
427 | static_url& normalize_authority() { url_base::normalize_authority(); return *this; } | ||
428 | /// @copydoc url_base::normalize_path | ||
429 | static_url& normalize_path() { url_base::normalize_path(); return *this; } | ||
430 | /// @copydoc url_base::normalize_query | ||
431 | static_url& normalize_query() { url_base::normalize_query(); return *this; } | ||
432 | /// @copydoc url_base::normalize_fragment | ||
433 | static_url& normalize_fragment() { url_base::normalize_fragment(); return *this; } | ||
434 | |||
435 | //-------------------------------------------- | ||
436 | }; | ||
437 | |||
438 | } // urls | ||
439 | } // boost | ||
440 | |||
441 | //------------------------------------------------ | ||
442 | |||
443 | // std::hash specialization | ||
444 | #ifndef BOOST_URL_DOCS | ||
445 | namespace std { | ||
446 | template<std::size_t N> | ||
447 | struct hash< ::boost::urls::static_url<N> > | ||
448 | { | ||
449 | hash() = default; | ||
450 | hash(hash const&) = default; | ||
451 | hash& operator=(hash const&) = default; | ||
452 | |||
453 | explicit | ||
454 | hash(std::size_t salt) noexcept | ||
455 | : salt_(salt) | ||
456 | { | ||
457 | } | ||
458 | |||
459 | std::size_t | ||
460 | operator()(::boost::urls::static_url<N> const& u) const noexcept | ||
461 | { | ||
462 | return u.digest(salt_); | ||
463 | } | ||
464 | |||
465 | private: | ||
466 | std::size_t salt_ = 0; | ||
467 | }; | ||
468 | } // std | ||
469 | #endif | ||
470 | |||
471 | #endif | ||
472 |