Line data Source code
1 : //
2 : // Copyright (c) 2022 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_DETAIL_IMPL_URL_IMPL_IPP
11 : #define BOOST_URL_DETAIL_IMPL_URL_IMPL_IPP
12 :
13 : #include <boost/url/detail/config.hpp>
14 : #include "path.hpp"
15 : #include <boost/url/detail/url_impl.hpp>
16 : #include <boost/url/authority_view.hpp>
17 : #include <boost/assert.hpp>
18 : #include <cstring>
19 :
20 : namespace boost {
21 : namespace urls {
22 : namespace detail {
23 :
24 : #if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
25 : #pragma GCC diagnostic push
26 : #pragma GCC diagnostic ignored "-Warray-bounds"
27 : #endif
28 :
29 : //------------------------------------------------
30 : //
31 : // url_impl
32 : //
33 : //------------------------------------------------
34 :
35 : void
36 2249 : url_impl::
37 : apply_scheme(
38 : core::string_view s) noexcept
39 : {
40 2249 : scheme_ = string_to_scheme(s);
41 2249 : set_size(id_scheme, s.size() + 1);
42 2249 : }
43 :
44 : void
45 380 : url_impl::
46 : apply_userinfo(
47 : pct_string_view const& user,
48 : pct_string_view const* pass) noexcept
49 : {
50 : // this function is for
51 : // authority_view_rule only
52 380 : BOOST_ASSERT(from_ == from::authority);
53 :
54 : // userinfo
55 380 : set_size(id_user, user.size());
56 380 : decoded_[id_user] =
57 380 : user.decoded_size();
58 380 : if(pass)
59 : {
60 251 : set_size(id_pass,
61 251 : pass->size() + 2);
62 251 : decoded_[id_pass] =
63 251 : pass->decoded_size();
64 : }
65 : else
66 : {
67 : // trailing '@'
68 129 : set_size(id_pass, 1 );
69 : }
70 380 : }
71 :
72 : void
73 1848 : url_impl::
74 : apply_host(
75 : host_type ht,
76 : pct_string_view s,
77 : unsigned char const* addr) noexcept
78 : {
79 : // this function is for
80 : // authority_view_rule only
81 1848 : BOOST_ASSERT(from_ == from::authority);
82 :
83 : // host, port
84 1848 : host_type_ = ht;
85 1848 : set_size(id_host, s.size());
86 1848 : decoded_[id_host] =
87 1848 : s.decoded_size();
88 1848 : std::memcpy(
89 1848 : ip_addr_,
90 : addr,
91 : sizeof(ip_addr_));
92 1848 : }
93 :
94 : void
95 247 : url_impl::
96 : apply_port(
97 : core::string_view s,
98 : unsigned short pn) noexcept
99 : {
100 : // this function is for
101 : // authority_view_rule only
102 247 : BOOST_ASSERT(from_ == from::authority);
103 :
104 247 : port_number_ = pn;
105 247 : set_size(id_port, 1 + s.size());
106 247 : }
107 :
108 : void
109 1792 : url_impl::
110 : apply_authority(
111 : authority_view const& a) noexcept
112 : {
113 1792 : BOOST_ASSERT(from_ != from::authority);
114 :
115 : // userinfo
116 1792 : set_size(id_user,
117 1792 : a.u_.len(id_user) +
118 1792 : (from_ == from::authority ? 0 : 2));
119 1792 : set_size(id_pass, a.u_.len(id_pass));
120 1792 : decoded_[id_user] = a.u_.decoded_[id_user];
121 1792 : decoded_[id_pass] = a.u_.decoded_[id_pass];
122 :
123 : // host, port
124 1792 : host_type_ = a.u_.host_type_;
125 1792 : port_number_ = a.u_.port_number_;
126 1792 : set_size(id_host, a.u_.len(id_host));
127 1792 : set_size(id_port, a.u_.len(id_port));
128 1792 : std::memcpy(
129 1792 : ip_addr_,
130 1792 : a.u_.ip_addr_,
131 : sizeof(ip_addr_));
132 1792 : decoded_[id_host] = a.u_.decoded_[id_host];
133 1792 : }
134 :
135 : void
136 3523 : url_impl::
137 : apply_path(
138 : pct_string_view s,
139 : std::size_t nseg) noexcept
140 : {
141 3523 : set_size(id_path, s.size());
142 3523 : decoded_[id_path] = s.decoded_size();
143 3523 : nseg_ = detail::path_segments(s, nseg);
144 3523 : }
145 :
146 : void
147 430 : url_impl::
148 : apply_query(
149 : pct_string_view s,
150 : std::size_t n) noexcept
151 : {
152 430 : nparam_ = n;
153 430 : set_size(id_query, 1 + s.size());
154 430 : decoded_[id_query] = s.decoded_size();
155 430 : }
156 :
157 : void
158 210 : url_impl::
159 : apply_frag(
160 : pct_string_view s) noexcept
161 : {
162 210 : set_size(id_frag, s.size() + 1);
163 210 : decoded_[id_frag] = s.decoded_size();
164 210 : }
165 :
166 : // return length of [first, last)
167 : auto
168 20187 : url_impl::
169 : len(
170 : int first,
171 : int last) const noexcept ->
172 : std::size_t
173 : {
174 20187 : BOOST_ASSERT(first <= last);
175 20187 : BOOST_ASSERT(last <= id_end);
176 20187 : return offset(last) - offset(first);
177 : }
178 :
179 : // return length of part
180 : auto
181 262748 : url_impl::
182 : len(int id) const noexcept ->
183 : std::size_t
184 : {
185 : return id == id_end
186 525496 : ? zero_
187 262748 : : ( offset(id + 1) -
188 525496 : offset(id) );
189 : }
190 :
191 : // return offset of id
192 : auto
193 688690 : url_impl::
194 : offset(int id) const noexcept ->
195 : std::size_t
196 : {
197 : return
198 : id == id_scheme
199 688690 : ? zero_
200 688690 : : offset_[id];
201 : }
202 :
203 : // return id as string
204 : core::string_view
205 46519 : url_impl::
206 : get(int id) const noexcept
207 : {
208 : return {
209 46519 : cs_ + offset(id), len(id) };
210 : }
211 :
212 : // return [first, last) as string
213 : core::string_view
214 791 : url_impl::
215 : get(int first,
216 : int last) const noexcept
217 : {
218 791 : return { cs_ + offset(first),
219 791 : offset(last) - offset(first) };
220 : }
221 :
222 : // return id as pct-string
223 : pct_string_view
224 2085 : url_impl::
225 : pct_get(
226 : int id) const noexcept
227 : {
228 : return make_pct_string_view_unsafe(
229 2085 : cs_ + offset(id),
230 : len(id),
231 4170 : decoded_[id]);
232 : }
233 :
234 : // return [first, last) as pct-string
235 : pct_string_view
236 120 : url_impl::
237 : pct_get(
238 : int first,
239 : int last) const noexcept
240 : {
241 120 : auto const pos = offset(first);
242 120 : std::size_t n = 0;
243 360 : for(auto i = first; i < last;)
244 240 : n += decoded_[i++];
245 : return make_pct_string_view_unsafe(
246 120 : cs_ + pos,
247 120 : offset(last) - pos,
248 120 : n);
249 : }
250 :
251 : //------------------------------------------------
252 :
253 : // change id to size n
254 : void
255 18762 : url_impl::
256 : set_size(
257 : int id,
258 : std::size_t n) noexcept
259 : {
260 18762 : auto d = n - len(id);
261 18762 : for(auto i = id + 1;
262 113823 : i <= id_end; ++i)
263 95061 : offset_[i] += d;
264 18762 : }
265 :
266 : // trim id to size n,
267 : // moving excess into id+1
268 : void
269 811 : url_impl::
270 : split(
271 : int id,
272 : std::size_t n) noexcept
273 : {
274 811 : BOOST_ASSERT(id < id_end - 1);
275 : //BOOST_ASSERT(n <= len(id));
276 811 : offset_[id + 1] = offset(id) + n;
277 811 : }
278 :
279 : // add n to [first, last]
280 : void
281 1587 : url_impl::
282 : adjust(
283 : int first,
284 : int last,
285 : std::size_t n) noexcept
286 : {
287 1587 : for(int i = first;
288 8638 : i <= last; ++i)
289 7051 : offset_[i] += n;
290 1587 : }
291 :
292 : // set [first, last) offset
293 : void
294 1568 : url_impl::
295 : collapse(
296 : int first,
297 : int last,
298 : std::size_t n) noexcept
299 : {
300 1568 : for(int i = first + 1;
301 2113 : i < last; ++i)
302 545 : offset_[i] = n;
303 1568 : }
304 :
305 :
306 : //------------------------------------------------
307 : //
308 : // path_ref
309 : //
310 : //------------------------------------------------
311 :
312 2017 : path_ref::
313 : path_ref(
314 2017 : url_impl const& impl) noexcept
315 : {
316 2017 : if(impl.from_ == url_impl::from::url)
317 : {
318 1569 : impl_ = &impl;
319 : }
320 : else
321 : {
322 448 : core::string_view s = impl.get(id_path);
323 448 : data_ = s.data();
324 448 : size_ = s.size();
325 448 : nseg_ = impl.nseg_;
326 448 : dn_ = impl.decoded_[id_path];
327 : }
328 2017 : }
329 :
330 141 : path_ref::
331 : path_ref(
332 : core::string_view s,
333 : std::size_t dn,
334 141 : std::size_t nseg) noexcept
335 141 : : data_(s.data())
336 141 : , size_(s.size())
337 : , nseg_(nseg)
338 141 : , dn_(dn)
339 : {
340 141 : }
341 :
342 : pct_string_view
343 4475 : path_ref::
344 : buffer() const noexcept
345 : {
346 4475 : if(impl_)
347 : return make_pct_string_view_unsafe(
348 2321 : impl_->cs_ +
349 2321 : impl_->offset(id_path),
350 2321 : impl_->len(id_path),
351 4642 : impl_->decoded_[id_path]);
352 : return make_pct_string_view_unsafe(
353 2154 : data_, size_, dn_);
354 : }
355 :
356 : std::size_t
357 3899 : path_ref::
358 : size() const noexcept
359 : {
360 3899 : if(impl_)
361 2657 : return impl_->len(id_path);
362 1242 : return size_;
363 : }
364 :
365 : char const*
366 12602 : path_ref::
367 : data() const noexcept
368 : {
369 12602 : if(impl_)
370 7447 : return impl_->cs_ +
371 7447 : impl_->offset(id_path);
372 5155 : return data_;
373 : }
374 :
375 : char const*
376 4397 : path_ref::
377 : end() const noexcept
378 : {
379 4397 : if(impl_)
380 2945 : return impl_->cs_ +
381 2945 : impl_->offset(id_query);
382 1452 : return data_ + size_;
383 : }
384 :
385 : std::size_t
386 8630 : path_ref::
387 : nseg() const noexcept
388 : {
389 8630 : if(impl_)
390 5508 : return impl_->nseg_;
391 3122 : return nseg_;
392 : }
393 :
394 : //------------------------------------------------
395 : //
396 : // query_ref
397 : //
398 : //------------------------------------------------
399 :
400 674 : query_ref::
401 : query_ref(
402 : core::string_view s,
403 : std::size_t dn,
404 674 : std::size_t nparam) noexcept
405 674 : : data_(s.data())
406 674 : , size_(s.size())
407 : , nparam_(nparam)
408 674 : , dn_(dn)
409 : {
410 674 : }
411 :
412 425 : query_ref::
413 : query_ref(
414 425 : url_impl const& impl) noexcept
415 : {
416 425 : if(impl.from_ == url_impl::from::url)
417 : {
418 344 : impl_ = &impl;
419 : }
420 : else
421 : {
422 81 : core::string_view s = impl.get(id_query);
423 81 : if (!s.empty())
424 : {
425 79 : s.remove_prefix(1);
426 79 : question_mark_ = true;
427 : }
428 81 : data_ = s.data();
429 81 : size_ = s.size();
430 81 : nparam_ = impl.nparam_;
431 81 : dn_ = impl.decoded_[id_query];
432 : }
433 425 : }
434 :
435 : pct_string_view
436 454 : query_ref::
437 : buffer() const noexcept
438 : {
439 454 : if(impl_)
440 : {
441 2 : auto pos = impl_->offset_[id_query];
442 2 : auto pos1 = impl_->offset_[id_frag];
443 2 : if(pos < pos1)
444 : {
445 0 : ++pos; // no '?'
446 : return make_pct_string_view_unsafe(
447 0 : impl_->cs_ + pos,
448 : pos1 - pos,
449 0 : impl_->decoded_[id_query]);
450 : }
451 : // empty
452 : return make_pct_string_view_unsafe(
453 2 : impl_->cs_ + pos,
454 : 0,
455 2 : 0);
456 : }
457 : // no '?'
458 : return make_pct_string_view_unsafe(
459 452 : data_, size_, dn_);
460 : }
461 :
462 : // with '?'
463 : std::size_t
464 5282 : query_ref::
465 : size() const noexcept
466 : {
467 5282 : if(impl_)
468 1990 : return impl_->len(id_query);
469 3292 : if(size_ > 0)
470 3264 : return size_ + 1;
471 28 : return question_mark_;
472 : }
473 :
474 : // no '?'
475 : char const*
476 5807 : query_ref::
477 : begin() const noexcept
478 : {
479 5807 : if(impl_)
480 : {
481 : // using the offset array here
482 2267 : auto pos = impl_->offset_[id_query];
483 2267 : auto pos1 = impl_->offset_[id_frag];
484 2267 : if(pos < pos1)
485 2267 : return impl_->cs_ + pos + 1; // no '?'
486 : // empty
487 0 : return impl_->cs_ + pos;
488 : }
489 3540 : return data_;
490 :
491 : }
492 :
493 : char const*
494 2282 : query_ref::
495 : end() const noexcept
496 : {
497 2282 : if(impl_)
498 902 : return impl_->cs_ +
499 902 : impl_->offset(id_frag);
500 1380 : return data_ + size_;
501 : }
502 :
503 : std::size_t
504 8886 : query_ref::
505 : nparam() const noexcept
506 : {
507 8886 : if(impl_)
508 3134 : return impl_->nparam_;
509 5752 : return nparam_;
510 : }
511 :
512 : #if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
513 : #pragma GCC diagnostic pop
514 : #endif
515 :
516 : } // detail
517 : } // urls
518 : } // boost
519 :
520 : #endif
|