url_base.ipp 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572
  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_IMPL_URL_BASE_IPP
  11. #define BOOST_URL_IMPL_URL_BASE_IPP
  12. #include <boost/url/url_base.hpp>
  13. #include <boost/url/error.hpp>
  14. #include <boost/url/host_type.hpp>
  15. #include <boost/url/scheme.hpp>
  16. #include <boost/url/url_view.hpp>
  17. #include <boost/url/detail/any_params_iter.hpp>
  18. #include <boost/url/detail/any_segments_iter.hpp>
  19. #include <boost/url/detail/encode.hpp>
  20. #include <boost/url/detail/except.hpp>
  21. #include <boost/url/detail/move_chars.hpp>
  22. #include <boost/url/detail/print.hpp>
  23. #include <boost/url/rfc/authority_rule.hpp>
  24. #include <boost/url/rfc/query_rule.hpp>
  25. #include <boost/url/rfc/detail/charsets.hpp>
  26. #include <boost/url/rfc/detail/host_rule.hpp>
  27. #include <boost/url/rfc/detail/ipvfuture_rule.hpp>
  28. #include <boost/url/rfc/detail/path_rules.hpp>
  29. #include <boost/url/rfc/detail/port_rule.hpp>
  30. #include <boost/url/rfc/detail/scheme_rule.hpp>
  31. #include <boost/url/rfc/detail/userinfo_rule.hpp>
  32. #include <boost/url/grammar/parse.hpp>
  33. #include <cstring>
  34. #include <iostream>
  35. #include <stdexcept>
  36. #include <utility>
  37. namespace boost {
  38. namespace urls {
  39. //------------------------------------------------
  40. // these objects help handle the cases
  41. // where the user passes in strings that
  42. // come from inside the url buffer.
  43. url_base::
  44. op_t::
  45. ~op_t()
  46. {
  47. if(old)
  48. u.cleanup(*this);
  49. u.check_invariants();
  50. }
  51. url_base::
  52. op_t::
  53. op_t(
  54. url_base& impl_,
  55. string_view* s0_,
  56. string_view* s1_) noexcept
  57. : u(impl_)
  58. , s0(s0_)
  59. , s1(s1_)
  60. {
  61. u.check_invariants();
  62. }
  63. void
  64. url_base::
  65. op_t::
  66. move(
  67. char* dest,
  68. char const* src,
  69. std::size_t n) noexcept
  70. {
  71. if(! n)
  72. return;
  73. if(s0)
  74. {
  75. if(s1)
  76. return detail::move_chars(
  77. dest, src, n, *s0, *s1);
  78. return detail::move_chars(
  79. dest, src, n, *s0);
  80. }
  81. detail::move_chars(
  82. dest, src, n);
  83. }
  84. //------------------------------------------------
  85. // construct reference
  86. url_base::
  87. url_base(
  88. detail::url_impl const& impl) noexcept
  89. : url_view_base(impl)
  90. {
  91. }
  92. void
  93. url_base::
  94. reserve_impl(std::size_t n)
  95. {
  96. op_t op(*this);
  97. reserve_impl(n, op);
  98. if(s_)
  99. s_[size()] = '\0';
  100. }
  101. // make a copy of u
  102. void
  103. url_base::
  104. copy(url_view_base const& u)
  105. {
  106. if (this == &u)
  107. return;
  108. op_t op(*this);
  109. if(u.size() == 0)
  110. {
  111. clear();
  112. return;
  113. }
  114. reserve_impl(
  115. u.size(), op);
  116. impl_ = u.impl_;
  117. impl_.cs_ = s_;
  118. impl_.from_ = {from::url};
  119. std::memcpy(s_,
  120. u.data(), u.size());
  121. s_[size()] = '\0';
  122. }
  123. //------------------------------------------------
  124. //
  125. // Scheme
  126. //
  127. //------------------------------------------------
  128. url_base&
  129. url_base::
  130. set_scheme(string_view s)
  131. {
  132. set_scheme_impl(
  133. s, string_to_scheme(s));
  134. return *this;
  135. }
  136. url_base&
  137. url_base::
  138. set_scheme_id(urls::scheme id)
  139. {
  140. if(id == urls::scheme::unknown)
  141. detail::throw_invalid_argument();
  142. if(id == urls::scheme::none)
  143. return remove_scheme();
  144. set_scheme_impl(to_string(id), id);
  145. return *this;
  146. }
  147. url_base&
  148. url_base::
  149. remove_scheme()
  150. {
  151. op_t op(*this);
  152. auto const sn = impl_.len(id_scheme);
  153. if(sn == 0)
  154. return *this;
  155. auto const po = impl_.offset(id_path);
  156. auto fseg = first_segment();
  157. bool const encode_colon =
  158. !has_authority() &&
  159. impl_.nseg_ > 0 &&
  160. s_[po] != '/' &&
  161. fseg.contains(':');
  162. if(!encode_colon)
  163. {
  164. // just remove the scheme
  165. resize_impl(id_scheme, 0, op);
  166. impl_.scheme_ = urls::scheme::none;
  167. check_invariants();
  168. return *this;
  169. }
  170. // encode any ":" in the first path segment
  171. BOOST_ASSERT(sn >= 2);
  172. auto pn = impl_.len(id_path);
  173. std::size_t cn = 0;
  174. for (char c: fseg)
  175. cn += c == ':';
  176. std::size_t new_size =
  177. size() - sn + 2 * cn;
  178. bool need_resize = new_size > size();
  179. if (need_resize)
  180. {
  181. resize_impl(
  182. id_path, pn + 2 * cn, op);
  183. }
  184. // move [id_scheme, id_path) left
  185. op.move(
  186. s_,
  187. s_ + sn,
  188. po - sn);
  189. // move [id_path, id_query) left
  190. auto qo = impl_.offset(id_query);
  191. op.move(
  192. s_ + po - sn,
  193. s_ + po,
  194. qo - po);
  195. // move [id_query, id_end) left
  196. op.move(
  197. s_ + qo - sn + 2 * cn,
  198. s_ + qo,
  199. impl_.offset(id_end) - qo);
  200. // adjust part offsets.
  201. // (po and qo are invalidated)
  202. if (need_resize)
  203. {
  204. impl_.adjust(id_user, id_end, 0 - sn);
  205. }
  206. else
  207. {
  208. impl_.adjust(id_user, id_path, 0 - sn);
  209. impl_.adjust(id_query, id_end, 0 - sn + 2 * cn);
  210. }
  211. if (encode_colon)
  212. {
  213. // move the 2nd, 3rd, ... segments
  214. auto begin = s_ + impl_.offset(id_path);
  215. auto it = begin;
  216. auto end = begin + pn;
  217. while (*it != '/' &&
  218. it != end)
  219. ++it;
  220. // we don't need op here because this is
  221. // an internal operation
  222. std::memmove(it + (2 * cn), it, end - it);
  223. // move 1st segment
  224. auto src = s_ + impl_.offset(id_path) + pn;
  225. auto dest = s_ + impl_.offset(id_query);
  226. src -= end - it;
  227. dest -= end - it;
  228. pn -= end - it;
  229. do {
  230. --src;
  231. --dest;
  232. if (*src != ':')
  233. {
  234. *dest = *src;
  235. }
  236. else
  237. {
  238. // use uppercase as required by
  239. // syntax-based normalization
  240. *dest-- = 'A';
  241. *dest-- = '3';
  242. *dest = '%';
  243. }
  244. --pn;
  245. } while (pn);
  246. }
  247. s_[size()] = '\0';
  248. impl_.scheme_ = urls::scheme::none;
  249. return *this;
  250. }
  251. //------------------------------------------------
  252. //
  253. // Authority
  254. //
  255. //------------------------------------------------
  256. url_base&
  257. url_base::
  258. set_encoded_authority(
  259. pct_string_view s)
  260. {
  261. op_t op(*this, &detail::ref(s));
  262. authority_view a = grammar::parse(
  263. s, authority_rule
  264. ).value(BOOST_URL_POS);
  265. auto n = s.size() + 2;
  266. auto const need_slash =
  267. ! is_path_absolute() &&
  268. impl_.len(id_path) > 0;
  269. if(need_slash)
  270. ++n;
  271. auto dest = resize_impl(
  272. id_user, id_path, n, op);
  273. dest[0] = '/';
  274. dest[1] = '/';
  275. std::memcpy(dest + 2,
  276. s.data(), s.size());
  277. if(need_slash)
  278. dest[n - 1] = '/';
  279. impl_.apply_authority(a);
  280. if(need_slash)
  281. impl_.adjust(
  282. id_query, id_end, 1);
  283. return *this;
  284. }
  285. url_base&
  286. url_base::
  287. remove_authority()
  288. {
  289. if(! has_authority())
  290. return *this;
  291. op_t op(*this);
  292. auto path = impl_.get(id_path);
  293. bool const need_dot = path.starts_with("//");
  294. if(need_dot)
  295. {
  296. // prepend "/.", can't throw
  297. auto p = resize_impl(
  298. id_user, id_path, 2, op);
  299. p[0] = '/';
  300. p[1] = '.';
  301. impl_.split(id_user, 0);
  302. impl_.split(id_pass, 0);
  303. impl_.split(id_host, 0);
  304. impl_.split(id_port, 0);
  305. }
  306. else
  307. {
  308. resize_impl(
  309. id_user, id_path, 0, op);
  310. }
  311. impl_.host_type_ =
  312. urls::host_type::none;
  313. return *this;
  314. }
  315. //------------------------------------------------
  316. //
  317. // Userinfo
  318. //
  319. //------------------------------------------------
  320. url_base&
  321. url_base::
  322. set_userinfo(
  323. string_view s)
  324. {
  325. op_t op(*this, &s);
  326. encoding_opts opt;
  327. auto const n = encoded_size(
  328. s, detail::userinfo_chars, opt);
  329. auto dest = set_userinfo_impl(n, op);
  330. encode(
  331. dest,
  332. n,
  333. s,
  334. detail::userinfo_chars,
  335. opt);
  336. auto const pos = impl_.get(
  337. id_user, id_host
  338. ).find_first_of(':');
  339. if(pos != string_view::npos)
  340. {
  341. impl_.split(id_user, pos);
  342. // find ':' in plain string
  343. auto const pos2 =
  344. s.find_first_of(':');
  345. impl_.decoded_[id_user] =
  346. pos2 - 1;
  347. impl_.decoded_[id_pass] =
  348. s.size() - pos2;
  349. }
  350. else
  351. {
  352. impl_.decoded_[id_user] = s.size();
  353. impl_.decoded_[id_pass] = 0;
  354. }
  355. return *this;
  356. }
  357. url_base&
  358. url_base::
  359. set_encoded_userinfo(
  360. pct_string_view s)
  361. {
  362. op_t op(*this, &detail::ref(s));
  363. encoding_opts opt;
  364. auto const pos = s.find_first_of(':');
  365. if(pos != string_view::npos)
  366. {
  367. // user:pass
  368. auto const s0 = s.substr(0, pos);
  369. auto const s1 = s.substr(pos + 1);
  370. auto const n0 =
  371. detail::re_encoded_size_unsafe(
  372. s0,
  373. detail::user_chars,
  374. opt);
  375. auto const n1 =
  376. detail::re_encoded_size_unsafe(s1,
  377. detail::password_chars,
  378. opt);
  379. auto dest =
  380. set_userinfo_impl(n0 + n1 + 1, op);
  381. impl_.decoded_[id_user] =
  382. detail::re_encode_unsafe(
  383. dest,
  384. dest + n0,
  385. s0,
  386. detail::user_chars,
  387. opt);
  388. *dest++ = ':';
  389. impl_.decoded_[id_pass] =
  390. detail::re_encode_unsafe(
  391. dest,
  392. dest + n1,
  393. s1,
  394. detail::password_chars,
  395. opt);
  396. impl_.split(id_user, 2 + n0);
  397. }
  398. else
  399. {
  400. // user
  401. auto const n =
  402. detail::re_encoded_size_unsafe(
  403. s, detail::user_chars, opt);
  404. auto dest = set_userinfo_impl(n, op);
  405. impl_.decoded_[id_user] =
  406. detail::re_encode_unsafe(
  407. dest,
  408. dest + n,
  409. s,
  410. detail::user_chars,
  411. opt);
  412. impl_.split(id_user, 2 + n);
  413. impl_.decoded_[id_pass] = 0;
  414. }
  415. return *this;
  416. }
  417. url_base&
  418. url_base::
  419. remove_userinfo() noexcept
  420. {
  421. if(impl_.len(id_pass) == 0)
  422. return *this; // no userinfo
  423. op_t op(*this);
  424. // keep authority '//'
  425. resize_impl(
  426. id_user, id_host, 2, op);
  427. impl_.decoded_[id_user] = 0;
  428. impl_.decoded_[id_pass] = 0;
  429. return *this;
  430. }
  431. //------------------------------------------------
  432. url_base&
  433. url_base::
  434. set_user(string_view s)
  435. {
  436. op_t op(*this, &s);
  437. encoding_opts opt;
  438. auto const n = encoded_size(
  439. s, detail::user_chars, opt);
  440. auto dest = set_user_impl(n, op);
  441. encode_unsafe(
  442. dest,
  443. n,
  444. s,
  445. detail::user_chars,
  446. opt);
  447. impl_.decoded_[id_user] = s.size();
  448. return *this;
  449. }
  450. url_base&
  451. url_base::
  452. set_encoded_user(
  453. pct_string_view s)
  454. {
  455. op_t op(*this, &detail::ref(s));
  456. encoding_opts opt;
  457. auto const n =
  458. detail::re_encoded_size_unsafe(
  459. s, detail::user_chars, opt);
  460. auto dest = set_user_impl(n, op);
  461. impl_.decoded_[id_user] =
  462. detail::re_encode_unsafe(
  463. dest,
  464. dest + n,
  465. s,
  466. detail::user_chars,
  467. opt);
  468. BOOST_ASSERT(
  469. impl_.decoded_[id_user] ==
  470. s.decoded_size());
  471. return *this;
  472. }
  473. //------------------------------------------------
  474. url_base&
  475. url_base::
  476. set_password(string_view s)
  477. {
  478. op_t op(*this, &s);
  479. encoding_opts opt;
  480. auto const n = encoded_size(
  481. s, detail::password_chars, opt);
  482. auto dest = set_password_impl(n, op);
  483. encode_unsafe(
  484. dest,
  485. n,
  486. s,
  487. detail::password_chars,
  488. opt);
  489. impl_.decoded_[id_pass] = s.size();
  490. return *this;
  491. }
  492. url_base&
  493. url_base::
  494. set_encoded_password(
  495. pct_string_view s)
  496. {
  497. op_t op(*this, &detail::ref(s));
  498. encoding_opts opt;
  499. auto const n =
  500. detail::re_encoded_size_unsafe(
  501. s,
  502. detail::password_chars,
  503. opt);
  504. auto dest = set_password_impl(n, op);
  505. impl_.decoded_[id_pass] =
  506. detail::re_encode_unsafe(
  507. dest,
  508. dest + n,
  509. s,
  510. detail::password_chars,
  511. opt);
  512. BOOST_ASSERT(
  513. impl_.decoded_[id_pass] ==
  514. s.decoded_size());
  515. return *this;
  516. }
  517. url_base&
  518. url_base::
  519. remove_password() noexcept
  520. {
  521. auto const n = impl_.len(id_pass);
  522. if(n < 2)
  523. return *this; // no password
  524. op_t op(*this);
  525. // clear password, retain '@'
  526. auto dest =
  527. resize_impl(id_pass, 1, op);
  528. dest[0] = '@';
  529. impl_.decoded_[id_pass] = 0;
  530. return *this;
  531. }
  532. //------------------------------------------------
  533. //
  534. // Host
  535. //
  536. //------------------------------------------------
  537. /*
  538. host_type host_type() // ipv4, ipv6, ipvfuture, name
  539. std::string host() // return encoded_host().decode()
  540. pct_string_view encoded_host() // return host part, as-is
  541. std::string host_address() // return encoded_host_address().decode()
  542. pct_string_view encoded_host_address() // ipv4, ipv6, ipvfut, or encoded name, no brackets
  543. ipv4_address host_ipv4_address() // return ipv4_address or {}
  544. ipv6_address host_ipv6_address() // return ipv6_address or {}
  545. string_view host_ipvfuture() // return ipvfuture or {}
  546. std::string host_name() // return decoded name or ""
  547. pct_string_view encoded_host_name() // return encoded host name or ""
  548. --------------------------------------------------
  549. set_host( string_view ) // set host part from plain text
  550. set_encoded_host( pct_string_view ) // set host part from encoded text
  551. set_host_address( string_view ) // set host from ipv4, ipv6, ipvfut, or plain reg-name string
  552. set_encoded_host_address( pct_string_view ) // set host from ipv4, ipv6, ipvfut, or encoded reg-name string
  553. set_host_ipv4( ipv4_address ) // set ipv4
  554. set_host_ipv6( ipv6_address ) // set ipv6
  555. set_host_ipvfuture( string_view ) // set ipvfuture
  556. set_host_name( string_view ) // set name from plain
  557. set_encoded_host_name( pct_string_view ) // set name from encoded
  558. */
  559. // set host part from plain text
  560. url_base&
  561. url_base::
  562. set_host(
  563. string_view s)
  564. {
  565. if( s.size() > 2 &&
  566. s.front() == '[' &&
  567. s.back() == ']')
  568. {
  569. // IP-literal
  570. {
  571. // IPv6-address
  572. auto rv = parse_ipv6_address(
  573. s.substr(1, s.size() - 2));
  574. if(rv)
  575. return set_host_ipv6(*rv);
  576. }
  577. {
  578. // IPvFuture
  579. auto rv = grammar::parse(
  580. s.substr(1, s.size() - 2),
  581. detail::ipvfuture_rule);
  582. if(rv)
  583. return set_host_ipvfuture(rv->str);
  584. }
  585. }
  586. else if(s.size() >= 7) // "0.0.0.0"
  587. {
  588. // IPv4-address
  589. auto rv = parse_ipv4_address(s);
  590. if(rv)
  591. return set_host_ipv4(*rv);
  592. }
  593. // reg-name
  594. op_t op(*this, &s);
  595. encoding_opts opt;
  596. auto const n = encoded_size(
  597. s, detail::host_chars, opt);
  598. auto dest = set_host_impl(n, op);
  599. encode(
  600. dest,
  601. impl_.get(id_path).data() - dest,
  602. s,
  603. detail::host_chars,
  604. opt);
  605. impl_.decoded_[id_host] = s.size();
  606. impl_.host_type_ =
  607. urls::host_type::name;
  608. return *this;
  609. }
  610. // set host part from encoded text
  611. url_base&
  612. url_base::
  613. set_encoded_host(
  614. pct_string_view s)
  615. {
  616. if( s.size() > 2 &&
  617. s.front() == '[' &&
  618. s.back() == ']')
  619. {
  620. // IP-literal
  621. {
  622. // IPv6-address
  623. auto rv = parse_ipv6_address(
  624. s.substr(1, s.size() - 2));
  625. if(rv)
  626. return set_host_ipv6(*rv);
  627. }
  628. {
  629. // IPvFuture
  630. auto rv = grammar::parse(
  631. s.substr(1, s.size() - 2),
  632. detail::ipvfuture_rule);
  633. if(rv)
  634. return set_host_ipvfuture(rv->str);
  635. }
  636. }
  637. else if(s.size() >= 7) // "0.0.0.0"
  638. {
  639. // IPv4-address
  640. auto rv = parse_ipv4_address(s);
  641. if(rv)
  642. return set_host_ipv4(*rv);
  643. }
  644. // reg-name
  645. op_t op(*this, &detail::ref(s));
  646. encoding_opts opt;
  647. auto const n = detail::re_encoded_size_unsafe(
  648. s, detail::host_chars, opt);
  649. auto dest = set_host_impl(n, op);
  650. impl_.decoded_[id_host] =
  651. detail::re_encode_unsafe(
  652. dest,
  653. impl_.get(id_path).data(),
  654. s,
  655. detail::host_chars,
  656. opt);
  657. BOOST_ASSERT(impl_.decoded_[id_host] ==
  658. s.decoded_size());
  659. impl_.host_type_ =
  660. urls::host_type::name;
  661. return *this;
  662. }
  663. url_base&
  664. url_base::
  665. set_host_address(
  666. string_view s)
  667. {
  668. {
  669. // IPv6-address
  670. auto rv = parse_ipv6_address(s);
  671. if(rv)
  672. return set_host_ipv6(*rv);
  673. }
  674. {
  675. // IPvFuture
  676. auto rv = grammar::parse(
  677. s, detail::ipvfuture_rule);
  678. if(rv)
  679. return set_host_ipvfuture(rv->str);
  680. }
  681. if(s.size() >= 7) // "0.0.0.0"
  682. {
  683. // IPv4-address
  684. auto rv = parse_ipv4_address(s);
  685. if(rv)
  686. return set_host_ipv4(*rv);
  687. }
  688. // reg-name
  689. op_t op(*this, &s);
  690. encoding_opts opt;
  691. auto const n = encoded_size(
  692. s, detail::host_chars, opt);
  693. auto dest = set_host_impl(n, op);
  694. encode(
  695. dest,
  696. impl_.get(id_path).data() - dest,
  697. s,
  698. detail::host_chars,
  699. opt);
  700. impl_.decoded_[id_host] = s.size();
  701. impl_.host_type_ =
  702. urls::host_type::name;
  703. return *this;
  704. }
  705. url_base&
  706. url_base::
  707. set_encoded_host_address(
  708. pct_string_view s)
  709. {
  710. {
  711. // IPv6-address
  712. auto rv = parse_ipv6_address(s);
  713. if(rv)
  714. return set_host_ipv6(*rv);
  715. }
  716. {
  717. // IPvFuture
  718. auto rv = grammar::parse(
  719. s, detail::ipvfuture_rule);
  720. if(rv)
  721. return set_host_ipvfuture(rv->str);
  722. }
  723. if(s.size() >= 7) // "0.0.0.0"
  724. {
  725. // IPv4-address
  726. auto rv = parse_ipv4_address(s);
  727. if(rv)
  728. return set_host_ipv4(*rv);
  729. }
  730. // reg-name
  731. op_t op(*this, &detail::ref(s));
  732. encoding_opts opt;
  733. auto const n = detail::re_encoded_size_unsafe(
  734. s, detail::host_chars, opt);
  735. auto dest = set_host_impl(n, op);
  736. impl_.decoded_[id_host] =
  737. detail::re_encode_unsafe(
  738. dest,
  739. impl_.get(id_path).data(),
  740. s,
  741. detail::host_chars,
  742. opt);
  743. BOOST_ASSERT(impl_.decoded_[id_host] ==
  744. s.decoded_size());
  745. impl_.host_type_ =
  746. urls::host_type::name;
  747. return *this;
  748. }
  749. url_base&
  750. url_base::
  751. set_host_ipv4(
  752. ipv4_address const& addr)
  753. {
  754. op_t op(*this);
  755. char buf[urls::ipv4_address::max_str_len];
  756. auto s = addr.to_buffer(buf, sizeof(buf));
  757. auto dest = set_host_impl(s.size(), op);
  758. std::memcpy(dest, s.data(), s.size());
  759. impl_.decoded_[id_host] = impl_.len(id_host);
  760. impl_.host_type_ = urls::host_type::ipv4;
  761. auto bytes = addr.to_bytes();
  762. std::memcpy(
  763. impl_.ip_addr_,
  764. bytes.data(),
  765. bytes.size());
  766. return *this;
  767. }
  768. url_base&
  769. url_base::
  770. set_host_ipv6(
  771. ipv6_address const& addr)
  772. {
  773. op_t op(*this);
  774. char buf[2 +
  775. urls::ipv6_address::max_str_len];
  776. auto s = addr.to_buffer(
  777. buf + 1, sizeof(buf) - 2);
  778. buf[0] = '[';
  779. buf[s.size() + 1] = ']';
  780. auto const n = s.size() + 2;
  781. auto dest = set_host_impl(n, op);
  782. std::memcpy(dest, buf, n);
  783. impl_.decoded_[id_host] = n;
  784. impl_.host_type_ = urls::host_type::ipv6;
  785. auto bytes = addr.to_bytes();
  786. std::memcpy(
  787. impl_.ip_addr_,
  788. bytes.data(),
  789. bytes.size());
  790. return *this;
  791. }
  792. url_base&
  793. url_base::
  794. set_host_ipvfuture(
  795. string_view s)
  796. {
  797. op_t op(*this, &s);
  798. // validate
  799. grammar::parse(s,
  800. detail::ipvfuture_rule
  801. ).value(BOOST_URL_POS);
  802. auto dest = set_host_impl(
  803. s.size() + 2, op);
  804. *dest++ = '[';
  805. dest += s.copy(dest, s.size());
  806. *dest = ']';
  807. impl_.host_type_ =
  808. urls::host_type::ipvfuture;
  809. impl_.decoded_[id_host] = s.size() + 2;
  810. return *this;
  811. }
  812. url_base&
  813. url_base::
  814. set_host_name(
  815. string_view s)
  816. {
  817. bool is_ipv4 = false;
  818. if(s.size() >= 7) // "0.0.0.0"
  819. {
  820. // IPv4-address
  821. if(parse_ipv4_address(s).has_value())
  822. is_ipv4 = true;
  823. }
  824. auto allowed = detail::host_chars;
  825. if(is_ipv4)
  826. allowed = allowed - '.';
  827. op_t op(*this, &s);
  828. encoding_opts opt;
  829. auto const n = encoded_size(
  830. s, allowed, opt);
  831. auto dest = set_host_impl(n, op);
  832. encode_unsafe(
  833. dest,
  834. n,
  835. s,
  836. allowed,
  837. opt);
  838. impl_.host_type_ =
  839. urls::host_type::name;
  840. impl_.decoded_[id_host] = s.size();
  841. return *this;
  842. }
  843. url_base&
  844. url_base::
  845. set_encoded_host_name(
  846. pct_string_view s)
  847. {
  848. bool is_ipv4 = false;
  849. if(s.size() >= 7) // "0.0.0.0"
  850. {
  851. // IPv4-address
  852. if(parse_ipv4_address(s).has_value())
  853. is_ipv4 = true;
  854. }
  855. auto allowed = detail::host_chars;
  856. if(is_ipv4)
  857. allowed = allowed - '.';
  858. op_t op(*this, &detail::ref(s));
  859. encoding_opts opt;
  860. auto const n = detail::re_encoded_size_unsafe(
  861. s, allowed, opt);
  862. auto dest = set_host_impl(n, op);
  863. impl_.decoded_[id_host] =
  864. detail::re_encode_unsafe(
  865. dest,
  866. dest + n,
  867. s,
  868. allowed,
  869. opt);
  870. BOOST_ASSERT(
  871. impl_.decoded_[id_host] ==
  872. s.decoded_size());
  873. impl_.host_type_ =
  874. urls::host_type::name;
  875. return *this;
  876. }
  877. //------------------------------------------------
  878. url_base&
  879. url_base::
  880. set_port_number(
  881. std::uint16_t n)
  882. {
  883. op_t op(*this);
  884. auto s =
  885. detail::make_printed(n);
  886. auto dest = set_port_impl(
  887. s.string().size(), op);
  888. std::memcpy(
  889. dest, s.string().data(),
  890. s.string().size());
  891. impl_.port_number_ = n;
  892. return *this;
  893. }
  894. url_base&
  895. url_base::
  896. set_port(
  897. string_view s)
  898. {
  899. op_t op(*this, &s);
  900. auto t = grammar::parse(s,
  901. detail::port_rule{}
  902. ).value(BOOST_URL_POS);
  903. auto dest =
  904. set_port_impl(t.str.size(), op);
  905. std::memcpy(dest,
  906. t.str.data(), t.str.size());
  907. if(t.has_number)
  908. impl_.port_number_ = t.number;
  909. else
  910. impl_.port_number_ = 0;
  911. return *this;
  912. }
  913. url_base&
  914. url_base::
  915. remove_port() noexcept
  916. {
  917. op_t op(*this);
  918. resize_impl(id_port, 0, op);
  919. impl_.port_number_ = 0;
  920. return *this;
  921. }
  922. //------------------------------------------------
  923. //
  924. // Compound Fields
  925. //
  926. //------------------------------------------------
  927. url_base&
  928. url_base::
  929. remove_origin()
  930. {
  931. // these two calls perform 2 memmoves instead of 1
  932. remove_authority();
  933. remove_scheme();
  934. return *this;
  935. }
  936. //------------------------------------------------
  937. //
  938. // Path
  939. //
  940. //------------------------------------------------
  941. bool
  942. url_base::
  943. set_path_absolute(
  944. bool absolute)
  945. {
  946. op_t op(*this);
  947. // check if path empty
  948. if(impl_.len(id_path) == 0)
  949. {
  950. if(! absolute)
  951. {
  952. // already not absolute
  953. return true;
  954. }
  955. // add '/'
  956. auto dest = resize_impl(
  957. id_path, 1, op);
  958. *dest = '/';
  959. ++impl_.decoded_[id_path];
  960. return true;
  961. }
  962. // check if path absolute
  963. if(s_[impl_.offset(id_path)] == '/')
  964. {
  965. if(absolute)
  966. {
  967. // already absolute
  968. return true;
  969. }
  970. if( has_authority() &&
  971. impl_.len(id_path) > 1)
  972. {
  973. // can't do it, paths are always
  974. // absolute when authority present!
  975. return false;
  976. }
  977. auto p = encoded_path();
  978. auto pos = p.find_first_of(":/", 1);
  979. if (pos != string_view::npos &&
  980. p[pos] == ':')
  981. {
  982. // prepend with .
  983. auto n = impl_.len(id_path);
  984. resize_impl(id_path, n + 1, op);
  985. std::memmove(
  986. s_ + impl_.offset(id_path) + 1,
  987. s_ + impl_.offset(id_path), n);
  988. *(s_ + impl_.offset(id_path)) = '.';
  989. ++impl_.decoded_[id_path];
  990. return true;
  991. }
  992. // remove '/'
  993. auto n = impl_.len(id_port);
  994. impl_.split(id_port, n + 1);
  995. resize_impl(id_port, n, op);
  996. --impl_.decoded_[id_path];
  997. return true;
  998. }
  999. if(! absolute)
  1000. {
  1001. // already not absolute
  1002. return true;
  1003. }
  1004. // add '/'
  1005. auto n = impl_.len(id_port);
  1006. auto dest = resize_impl(
  1007. id_port, n + 1, op) + n;
  1008. impl_.split(id_port, n);
  1009. *dest = '/';
  1010. ++impl_.decoded_[id_path];
  1011. return true;
  1012. }
  1013. url_base&
  1014. url_base::
  1015. set_path(
  1016. string_view s)
  1017. {
  1018. edit_segments(
  1019. detail::segments_iter_impl(
  1020. detail::path_ref(impl_)),
  1021. detail::segments_iter_impl(
  1022. detail::path_ref(impl_), 0),
  1023. detail::path_iter(s),
  1024. s.starts_with('/'));
  1025. return *this;
  1026. }
  1027. url_base&
  1028. url_base::
  1029. set_encoded_path(
  1030. pct_string_view s)
  1031. {
  1032. edit_segments(
  1033. detail::segments_iter_impl(
  1034. detail::path_ref(impl_)),
  1035. detail::segments_iter_impl(
  1036. detail::path_ref(impl_), 0),
  1037. detail::path_encoded_iter(s),
  1038. s.starts_with('/'));
  1039. return *this;
  1040. }
  1041. segments_ref
  1042. url_base::
  1043. segments() noexcept
  1044. {
  1045. return {*this};
  1046. }
  1047. segments_encoded_ref
  1048. url_base::
  1049. encoded_segments() noexcept
  1050. {
  1051. return {*this};
  1052. }
  1053. //------------------------------------------------
  1054. //
  1055. // Query
  1056. //
  1057. //------------------------------------------------
  1058. url_base&
  1059. url_base::
  1060. set_query(
  1061. string_view s)
  1062. {
  1063. edit_params(
  1064. detail::params_iter_impl(impl_),
  1065. detail::params_iter_impl(impl_, 0),
  1066. detail::query_iter(s, true));
  1067. return *this;
  1068. }
  1069. url_base&
  1070. url_base::
  1071. set_encoded_query(
  1072. pct_string_view s)
  1073. {
  1074. op_t op(*this);
  1075. encoding_opts opt;
  1076. std::size_t n = 0; // encoded size
  1077. std::size_t nparam = 1; // param count
  1078. auto const end = s.end();
  1079. auto p = s.begin();
  1080. // measure
  1081. while(p != end)
  1082. {
  1083. if(*p == '&')
  1084. {
  1085. ++p;
  1086. ++n;
  1087. ++nparam;
  1088. }
  1089. else if(*p != '%')
  1090. {
  1091. if(detail::query_chars(*p))
  1092. n += 1; // allowed
  1093. else
  1094. n += 3; // escaped
  1095. ++p;
  1096. }
  1097. else
  1098. {
  1099. // escape
  1100. n += 3;
  1101. p += 3;
  1102. }
  1103. }
  1104. // resize
  1105. auto dest = resize_impl(
  1106. id_query, n + 1, op);
  1107. *dest++ = '?';
  1108. // encode
  1109. impl_.decoded_[id_query] =
  1110. detail::re_encode_unsafe(
  1111. dest,
  1112. dest + n,
  1113. s,
  1114. detail::query_chars,
  1115. opt);
  1116. BOOST_ASSERT(
  1117. impl_.decoded_[id_query] ==
  1118. s.decoded_size());
  1119. impl_.nparam_ = nparam;
  1120. return *this;
  1121. }
  1122. params_ref
  1123. url_base::
  1124. params() noexcept
  1125. {
  1126. return params_ref(
  1127. *this,
  1128. encoding_opts{
  1129. true, false, false});
  1130. }
  1131. params_ref
  1132. url_base::
  1133. params(encoding_opts opt) noexcept
  1134. {
  1135. return params_ref(*this, opt);
  1136. }
  1137. params_encoded_ref
  1138. url_base::
  1139. encoded_params() noexcept
  1140. {
  1141. return {*this};
  1142. }
  1143. url_base&
  1144. url_base::
  1145. set_params( std::initializer_list<param_view> ps ) noexcept
  1146. {
  1147. params().assign(ps);
  1148. return *this;
  1149. }
  1150. url_base&
  1151. url_base::
  1152. set_encoded_params( std::initializer_list< param_pct_view > ps ) noexcept
  1153. {
  1154. encoded_params().assign(ps);
  1155. return *this;
  1156. }
  1157. url_base&
  1158. url_base::
  1159. remove_query() noexcept
  1160. {
  1161. op_t op(*this);
  1162. resize_impl(id_query, 0, op);
  1163. impl_.nparam_ = 0;
  1164. impl_.decoded_[id_query] = 0;
  1165. return *this;
  1166. }
  1167. //------------------------------------------------
  1168. //
  1169. // Fragment
  1170. //
  1171. //------------------------------------------------
  1172. url_base&
  1173. url_base::
  1174. remove_fragment() noexcept
  1175. {
  1176. op_t op(*this);
  1177. resize_impl(id_frag, 0, op);
  1178. impl_.decoded_[id_frag] = 0;
  1179. return *this;
  1180. }
  1181. url_base&
  1182. url_base::
  1183. set_fragment(string_view s)
  1184. {
  1185. op_t op(*this, &s);
  1186. encoding_opts opt;
  1187. auto const n = encoded_size(
  1188. s,
  1189. detail::fragment_chars,
  1190. opt);
  1191. auto dest = resize_impl(
  1192. id_frag, n + 1, op);
  1193. *dest++ = '#';
  1194. encode_unsafe(
  1195. dest,
  1196. n,
  1197. s,
  1198. detail::fragment_chars,
  1199. opt);
  1200. impl_.decoded_[id_frag] = s.size();
  1201. return *this;
  1202. }
  1203. url_base&
  1204. url_base::
  1205. set_encoded_fragment(
  1206. pct_string_view s)
  1207. {
  1208. op_t op(*this, &detail::ref(s));
  1209. encoding_opts opt;
  1210. auto const n =
  1211. detail::re_encoded_size_unsafe(
  1212. s,
  1213. detail::fragment_chars,
  1214. opt);
  1215. auto dest = resize_impl(
  1216. id_frag, n + 1, op);
  1217. *dest++ = '#';
  1218. impl_.decoded_[id_frag] =
  1219. detail::re_encode_unsafe(
  1220. dest,
  1221. dest + n,
  1222. s,
  1223. detail::fragment_chars,
  1224. opt);
  1225. BOOST_ASSERT(
  1226. impl_.decoded_[id_frag] ==
  1227. s.decoded_size());
  1228. return *this;
  1229. }
  1230. //------------------------------------------------
  1231. //
  1232. // Resolution
  1233. //
  1234. //------------------------------------------------
  1235. result<void>
  1236. url_base::
  1237. resolve(
  1238. url_view_base const& ref)
  1239. {
  1240. if (this == &ref &&
  1241. has_scheme())
  1242. {
  1243. normalize_path();
  1244. return {};
  1245. }
  1246. if(! has_scheme())
  1247. {
  1248. BOOST_URL_RETURN_EC(error::not_a_base);
  1249. }
  1250. op_t op(*this);
  1251. //
  1252. // 5.2.2. Transform References
  1253. // https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2
  1254. //
  1255. if(ref.has_scheme())
  1256. {
  1257. reserve_impl(ref.size(), op);
  1258. copy(ref);
  1259. normalize_path();
  1260. return {};
  1261. }
  1262. if(ref.has_authority())
  1263. {
  1264. reserve_impl(
  1265. impl_.offset(id_user) + ref.size(), op);
  1266. set_encoded_authority(
  1267. ref.encoded_authority());
  1268. set_encoded_path(
  1269. ref.encoded_path());
  1270. if (ref.encoded_path().empty())
  1271. set_path_absolute(false);
  1272. else
  1273. normalize_path();
  1274. if(ref.has_query())
  1275. set_encoded_query(
  1276. ref.encoded_query());
  1277. else
  1278. remove_query();
  1279. if(ref.has_fragment())
  1280. set_encoded_fragment(
  1281. ref.encoded_fragment());
  1282. else
  1283. remove_fragment();
  1284. return {};
  1285. }
  1286. if(ref.encoded_path().empty())
  1287. {
  1288. reserve_impl(
  1289. impl_.offset(id_query) +
  1290. ref.size(), op);
  1291. normalize_path();
  1292. if(ref.has_query())
  1293. {
  1294. set_encoded_query(
  1295. ref.encoded_query());
  1296. }
  1297. if(ref.has_fragment())
  1298. set_encoded_fragment(
  1299. ref.encoded_fragment());
  1300. return {};
  1301. }
  1302. if(ref.is_path_absolute())
  1303. {
  1304. reserve_impl(
  1305. impl_.offset(id_path) +
  1306. ref.size(), op);
  1307. set_encoded_path(
  1308. ref.encoded_path());
  1309. normalize_path();
  1310. if(ref.has_query())
  1311. set_encoded_query(
  1312. ref.encoded_query());
  1313. else
  1314. remove_query();
  1315. if(ref.has_fragment())
  1316. set_encoded_fragment(
  1317. ref.encoded_fragment());
  1318. else
  1319. remove_fragment();
  1320. return {};
  1321. }
  1322. // General case: ref is relative path
  1323. reserve_impl(
  1324. impl_.offset(id_query) +
  1325. ref.size(), op);
  1326. // 5.2.3. Merge Paths
  1327. auto es = encoded_segments();
  1328. if(es.size() > 0)
  1329. {
  1330. es.pop_back();
  1331. }
  1332. es.insert(es.end(),
  1333. ref.encoded_segments().begin(),
  1334. ref.encoded_segments().end());
  1335. normalize_path();
  1336. if(ref.has_query())
  1337. set_encoded_query(
  1338. ref.encoded_query());
  1339. else
  1340. remove_query();
  1341. if(ref.has_fragment())
  1342. set_encoded_fragment(
  1343. ref.encoded_fragment());
  1344. else
  1345. remove_fragment();
  1346. return {};
  1347. }
  1348. //------------------------------------------------
  1349. //
  1350. // Normalization
  1351. //
  1352. //------------------------------------------------
  1353. template <class Charset>
  1354. void
  1355. url_base::
  1356. normalize_octets_impl(
  1357. int id,
  1358. Charset const& allowed,
  1359. op_t& op) noexcept
  1360. {
  1361. char* it = s_ + impl_.offset(id);
  1362. char* end = s_ + impl_.offset(id + 1);
  1363. char d = 0;
  1364. char* dest = it;
  1365. while (it < end)
  1366. {
  1367. if (*it != '%')
  1368. {
  1369. *dest = *it;
  1370. ++it;
  1371. ++dest;
  1372. continue;
  1373. }
  1374. BOOST_ASSERT(end - it >= 3);
  1375. // decode unreserved octets
  1376. d = detail::decode_one(it + 1);
  1377. if (allowed(d))
  1378. {
  1379. *dest = d;
  1380. it += 3;
  1381. ++dest;
  1382. continue;
  1383. }
  1384. // uppercase percent-encoding triplets
  1385. *dest++ = '%';
  1386. ++it;
  1387. *dest++ = grammar::to_upper(*it++);
  1388. *dest++ = grammar::to_upper(*it++);
  1389. }
  1390. if (it != dest)
  1391. {
  1392. auto diff = it - dest;
  1393. auto n = impl_.len(id) - diff;
  1394. shrink_impl(id, n, op);
  1395. s_[size()] = '\0';
  1396. }
  1397. }
  1398. url_base&
  1399. url_base::
  1400. normalize_scheme()
  1401. {
  1402. to_lower_impl(id_scheme);
  1403. return *this;
  1404. }
  1405. url_base&
  1406. url_base::
  1407. normalize_authority()
  1408. {
  1409. op_t op(*this);
  1410. // normalize host
  1411. if (host_type() == urls::host_type::name)
  1412. {
  1413. normalize_octets_impl(
  1414. id_host,
  1415. detail::reg_name_chars, op);
  1416. }
  1417. decoded_to_lower_impl(id_host);
  1418. // normalize password
  1419. normalize_octets_impl(id_pass, detail::password_chars, op);
  1420. // normalize user
  1421. normalize_octets_impl(id_user, detail::user_chars, op);
  1422. return *this;
  1423. }
  1424. url_base&
  1425. url_base::
  1426. normalize_path()
  1427. {
  1428. op_t op(*this);
  1429. normalize_octets_impl(id_path, detail::path_chars, op);
  1430. string_view p = impl_.get(id_path);
  1431. char* p_dest = s_ + impl_.offset(id_path);
  1432. char* p_end = s_ + impl_.offset(id_path + 1);
  1433. auto pn = p.size();
  1434. auto skip_dot = 0;
  1435. bool encode_colons = false;
  1436. string_view first_seg;
  1437. //------------------------------------------------
  1438. //
  1439. // Determine unnecessary initial dot segments to skip and
  1440. // if we need to encode colons in the first segment
  1441. //
  1442. if (
  1443. !has_authority() &&
  1444. p.starts_with("/./"))
  1445. {
  1446. // check if removing the "/./" would result in "//"
  1447. // ex: "/.//", "/././/", "/././/", ...
  1448. skip_dot = 2;
  1449. while (p.substr(skip_dot, 3).starts_with("/./"))
  1450. skip_dot += 2;
  1451. if (p.substr(skip_dot).starts_with("//"))
  1452. skip_dot = 2;
  1453. else
  1454. skip_dot = 0;
  1455. }
  1456. else if (
  1457. !has_scheme())
  1458. {
  1459. if (p.starts_with("./"))
  1460. {
  1461. // check if removing the "./" would result in "//"
  1462. // ex: ".//", "././/", "././/", ...
  1463. skip_dot = 1;
  1464. while (p.substr(skip_dot, 3).starts_with("/./"))
  1465. skip_dot += 2;
  1466. if (p.substr(skip_dot).starts_with("//"))
  1467. skip_dot = 2;
  1468. else
  1469. skip_dot = 0;
  1470. if ( !skip_dot )
  1471. {
  1472. // check if removing "./"s would leave us
  1473. // a first segment with an ambiguous ":"
  1474. first_seg = p.substr(2);
  1475. while (first_seg.starts_with("./"))
  1476. first_seg = first_seg.substr(2);
  1477. auto i = first_seg.find('/');
  1478. if (i != string_view::npos)
  1479. first_seg = first_seg.substr(0, i);
  1480. encode_colons = first_seg.contains(':');
  1481. }
  1482. }
  1483. else
  1484. {
  1485. // check if normalize_octets_impl
  1486. // didn't already create a ":"
  1487. // in the first segment
  1488. first_seg = p;
  1489. auto i = first_seg.find('/');
  1490. if (i != string_view::npos)
  1491. first_seg = p.substr(0, i);
  1492. encode_colons = first_seg.contains(':');
  1493. }
  1494. }
  1495. //------------------------------------------------
  1496. //
  1497. // Encode colons in the first segment
  1498. //
  1499. if (encode_colons)
  1500. {
  1501. // prepend with "./"
  1502. // (resize_impl never throws)
  1503. auto cn =
  1504. std::count(
  1505. first_seg.begin(),
  1506. first_seg.end(),
  1507. ':');
  1508. resize_impl(
  1509. id_path, pn + (2 * cn), op);
  1510. // move the 2nd, 3rd, ... segments
  1511. auto begin = s_ + impl_.offset(id_path);
  1512. auto it = begin;
  1513. auto end = begin + pn;
  1514. while (string_view(it, 2) == "./")
  1515. it += 2;
  1516. while (*it != '/' &&
  1517. it != end)
  1518. ++it;
  1519. // we don't need op here because this is
  1520. // an internal operation
  1521. std::memmove(it + (2 * cn), it, end - it);
  1522. // move 1st segment
  1523. auto src = s_ + impl_.offset(id_path) + pn;
  1524. auto dest = s_ + impl_.offset(id_query);
  1525. src -= end - it;
  1526. dest -= end - it;
  1527. pn -= end - it;
  1528. do {
  1529. --src;
  1530. --dest;
  1531. if (*src != ':')
  1532. {
  1533. *dest = *src;
  1534. }
  1535. else
  1536. {
  1537. // use uppercase as required by
  1538. // syntax-based normalization
  1539. *dest-- = 'A';
  1540. *dest-- = '3';
  1541. *dest = '%';
  1542. }
  1543. --pn;
  1544. } while (pn);
  1545. skip_dot = 0;
  1546. p = impl_.get(id_path);
  1547. pn = p.size();
  1548. p_dest = s_ + impl_.offset(id_path);
  1549. p_end = s_ + impl_.offset(id_path + 1);
  1550. }
  1551. //------------------------------------------------
  1552. //
  1553. // Remove "." and ".." segments
  1554. //
  1555. p.remove_prefix(skip_dot);
  1556. p_dest += skip_dot;
  1557. auto n = detail::remove_dot_segments(
  1558. p_dest, p_end, p);
  1559. //------------------------------------------------
  1560. //
  1561. // Update path parameters
  1562. //
  1563. if (n != pn)
  1564. {
  1565. BOOST_ASSERT(n < pn);
  1566. shrink_impl(id_path, n + skip_dot, op);
  1567. p = encoded_path();
  1568. if (p == "/")
  1569. impl_.nseg_ = 0;
  1570. else if (!p.empty())
  1571. impl_.nseg_ = std::count(
  1572. p.begin() + 1, p.end(), '/') + 1;
  1573. else
  1574. impl_.nseg_ = 0;
  1575. impl_.decoded_[id_path] =
  1576. detail::decode_bytes_unsafe(impl_.get(id_path));
  1577. }
  1578. return *this;
  1579. }
  1580. url_base&
  1581. url_base::
  1582. normalize_query()
  1583. {
  1584. op_t op(*this);
  1585. normalize_octets_impl(
  1586. id_query, detail::query_chars, op);
  1587. return *this;
  1588. }
  1589. url_base&
  1590. url_base::
  1591. normalize_fragment()
  1592. {
  1593. op_t op(*this);
  1594. normalize_octets_impl(
  1595. id_frag, detail::fragment_chars, op);
  1596. return *this;
  1597. }
  1598. url_base&
  1599. url_base::
  1600. normalize()
  1601. {
  1602. normalize_fragment();
  1603. normalize_query();
  1604. normalize_path();
  1605. normalize_authority();
  1606. normalize_scheme();
  1607. return *this;
  1608. }
  1609. //------------------------------------------------
  1610. //
  1611. // Implementation
  1612. //
  1613. //------------------------------------------------
  1614. void
  1615. url_base::
  1616. check_invariants() const noexcept
  1617. {
  1618. BOOST_ASSERT(pi_);
  1619. BOOST_ASSERT(
  1620. impl_.len(id_scheme) == 0 ||
  1621. impl_.get(id_scheme).ends_with(':'));
  1622. BOOST_ASSERT(
  1623. impl_.len(id_user) == 0 ||
  1624. impl_.get(id_user).starts_with("//"));
  1625. BOOST_ASSERT(
  1626. impl_.len(id_pass) == 0 ||
  1627. impl_.get(id_user).starts_with("//"));
  1628. BOOST_ASSERT(
  1629. impl_.len(id_pass) == 0 ||
  1630. (impl_.len(id_pass) == 1 &&
  1631. impl_.get(id_pass) == "@") ||
  1632. (impl_.len(id_pass) > 1 &&
  1633. impl_.get(id_pass).starts_with(':') &&
  1634. impl_.get(id_pass).ends_with('@')));
  1635. BOOST_ASSERT(
  1636. impl_.len(id_user, id_path) == 0 ||
  1637. impl_.get(id_user).starts_with("//"));
  1638. BOOST_ASSERT(impl_.decoded_[id_path] >=
  1639. ((impl_.len(id_path) + 2) / 3));
  1640. BOOST_ASSERT(
  1641. impl_.len(id_port) == 0 ||
  1642. impl_.get(id_port).starts_with(':'));
  1643. BOOST_ASSERT(
  1644. impl_.len(id_query) == 0 ||
  1645. impl_.get(id_query).starts_with('?'));
  1646. BOOST_ASSERT(
  1647. (impl_.len(id_query) == 0 && impl_.nparam_ == 0) ||
  1648. (impl_.len(id_query) > 0 && impl_.nparam_ > 0));
  1649. BOOST_ASSERT(
  1650. impl_.len(id_frag) == 0 ||
  1651. impl_.get(id_frag).starts_with('#'));
  1652. BOOST_ASSERT(c_str()[size()] == '\0');
  1653. }
  1654. char*
  1655. url_base::
  1656. resize_impl(
  1657. int id,
  1658. std::size_t new_size,
  1659. op_t& op)
  1660. {
  1661. return resize_impl(
  1662. id, id + 1, new_size, op);
  1663. }
  1664. char*
  1665. url_base::
  1666. resize_impl(
  1667. int first,
  1668. int last,
  1669. std::size_t new_len,
  1670. op_t& op)
  1671. {
  1672. auto const n0 = impl_.len(first, last);
  1673. if(new_len == 0 && n0 == 0)
  1674. return s_ + impl_.offset(first);
  1675. if(new_len <= n0)
  1676. return shrink_impl(
  1677. first, last, new_len, op);
  1678. // growing
  1679. std::size_t n = new_len - n0;
  1680. reserve_impl(size() + n, op);
  1681. auto const pos =
  1682. impl_.offset(last);
  1683. // adjust chars
  1684. op.move(
  1685. s_ + pos + n,
  1686. s_ + pos,
  1687. impl_.offset(id_end) -
  1688. pos + 1);
  1689. // collapse (first, last)
  1690. impl_.collapse(first, last,
  1691. impl_.offset(last) + n);
  1692. // shift (last, end) right
  1693. impl_.adjust(last, id_end, n);
  1694. s_[size()] = '\0';
  1695. return s_ + impl_.offset(first);
  1696. }
  1697. char*
  1698. url_base::
  1699. shrink_impl(
  1700. int id,
  1701. std::size_t new_size,
  1702. op_t& op)
  1703. {
  1704. return shrink_impl(
  1705. id, id + 1, new_size, op);
  1706. }
  1707. char*
  1708. url_base::
  1709. shrink_impl(
  1710. int first,
  1711. int last,
  1712. std::size_t new_len,
  1713. op_t& op)
  1714. {
  1715. // shrinking
  1716. auto const n0 = impl_.len(first, last);
  1717. BOOST_ASSERT(new_len <= n0);
  1718. std::size_t n = n0 - new_len;
  1719. auto const pos =
  1720. impl_.offset(last);
  1721. // adjust chars
  1722. op.move(
  1723. s_ + pos - n,
  1724. s_ + pos,
  1725. impl_.offset(
  1726. id_end) - pos + 1);
  1727. // collapse (first, last)
  1728. impl_.collapse(first, last,
  1729. impl_.offset(last) - n);
  1730. // shift (last, end) left
  1731. impl_.adjust(
  1732. last, id_end, 0 - n);
  1733. s_[size()] = '\0';
  1734. return s_ + impl_.offset(first);
  1735. }
  1736. //------------------------------------------------
  1737. void
  1738. url_base::
  1739. set_scheme_impl(
  1740. string_view s,
  1741. urls::scheme id)
  1742. {
  1743. op_t op(*this, &s);
  1744. check_invariants();
  1745. grammar::parse(
  1746. s, detail::scheme_rule()
  1747. ).value(BOOST_URL_POS);
  1748. auto const n = s.size();
  1749. auto const p = impl_.offset(id_path);
  1750. // check for "./" prefix
  1751. bool const has_dot =
  1752. [this, p]
  1753. {
  1754. if(impl_.nseg_ == 0)
  1755. return false;
  1756. if(first_segment().size() < 2)
  1757. return false;
  1758. auto const src = s_ + p;
  1759. if(src[0] != '.')
  1760. return false;
  1761. if(src[1] != '/')
  1762. return false;
  1763. return true;
  1764. }();
  1765. // Remove "./"
  1766. if(has_dot)
  1767. {
  1768. // do this first, for
  1769. // strong exception safety
  1770. reserve_impl(
  1771. size() + n + 1 - 2, op);
  1772. op.move(
  1773. s_ + p,
  1774. s_ + p + 2,
  1775. size() + 1 -
  1776. (p + 2));
  1777. impl_.set_size(
  1778. id_path,
  1779. impl_.len(id_path) - 2);
  1780. s_[size()] = '\0';
  1781. }
  1782. auto dest = resize_impl(
  1783. id_scheme, n + 1, op);
  1784. s.copy(dest, n);
  1785. dest[n] = ':';
  1786. impl_.scheme_ = id;
  1787. check_invariants();
  1788. }
  1789. char*
  1790. url_base::
  1791. set_user_impl(
  1792. std::size_t n,
  1793. op_t& op)
  1794. {
  1795. check_invariants();
  1796. if(impl_.len(id_pass) != 0)
  1797. {
  1798. // keep "//"
  1799. auto dest = resize_impl(
  1800. id_user, 2 + n, op);
  1801. check_invariants();
  1802. return dest + 2;
  1803. }
  1804. // add authority
  1805. auto dest = resize_impl(
  1806. id_user, 2 + n + 1, op);
  1807. impl_.split(id_user, 2 + n);
  1808. dest[0] = '/';
  1809. dest[1] = '/';
  1810. dest[2 + n] = '@';
  1811. check_invariants();
  1812. return dest + 2;
  1813. }
  1814. char*
  1815. url_base::
  1816. set_password_impl(
  1817. std::size_t n,
  1818. op_t& op)
  1819. {
  1820. check_invariants();
  1821. if(impl_.len(id_user) != 0)
  1822. {
  1823. // already have authority
  1824. auto const dest = resize_impl(
  1825. id_pass, 1 + n + 1, op);
  1826. dest[0] = ':';
  1827. dest[n + 1] = '@';
  1828. check_invariants();
  1829. return dest + 1;
  1830. }
  1831. // add authority
  1832. auto const dest =
  1833. resize_impl(
  1834. id_user, id_host,
  1835. 2 + 1 + n + 1, op);
  1836. impl_.split(id_user, 2);
  1837. dest[0] = '/';
  1838. dest[1] = '/';
  1839. dest[2] = ':';
  1840. dest[2 + n + 1] = '@';
  1841. check_invariants();
  1842. return dest + 3;
  1843. }
  1844. char*
  1845. url_base::
  1846. set_userinfo_impl(
  1847. std::size_t n,
  1848. op_t& op)
  1849. {
  1850. // "//" {dest} "@"
  1851. check_invariants();
  1852. auto dest = resize_impl(
  1853. id_user, id_host, n + 3, op);
  1854. impl_.split(id_user, n + 2);
  1855. dest[0] = '/';
  1856. dest[1] = '/';
  1857. dest[n + 2] = '@';
  1858. check_invariants();
  1859. return dest + 2;
  1860. }
  1861. char*
  1862. url_base::
  1863. set_host_impl(
  1864. std::size_t n,
  1865. op_t& op)
  1866. {
  1867. check_invariants();
  1868. if(impl_.len(id_user) == 0)
  1869. {
  1870. // add authority
  1871. auto dest = resize_impl(
  1872. id_user, n + 2, op);
  1873. impl_.split(id_user, 2);
  1874. impl_.split(id_pass, 0);
  1875. dest[0] = '/';
  1876. dest[1] = '/';
  1877. check_invariants();
  1878. return dest + 2;
  1879. }
  1880. // already have authority
  1881. auto const dest = resize_impl(
  1882. id_host, n, op);
  1883. check_invariants();
  1884. return dest;
  1885. }
  1886. char*
  1887. url_base::
  1888. set_port_impl(
  1889. std::size_t n,
  1890. op_t& op)
  1891. {
  1892. check_invariants();
  1893. if(impl_.len(id_user) != 0)
  1894. {
  1895. // authority exists
  1896. auto dest = resize_impl(
  1897. id_port, n + 1, op);
  1898. dest[0] = ':';
  1899. check_invariants();
  1900. return dest + 1;
  1901. }
  1902. auto dest = resize_impl(
  1903. id_user, 3 + n, op);
  1904. impl_.split(id_user, 2);
  1905. impl_.split(id_pass, 0);
  1906. impl_.split(id_host, 0);
  1907. dest[0] = '/';
  1908. dest[1] = '/';
  1909. dest[2] = ':';
  1910. check_invariants();
  1911. return dest + 3;
  1912. }
  1913. //------------------------------------------------
  1914. // return the first segment of the path.
  1915. // this is needed for some algorithms.
  1916. string_view
  1917. url_base::
  1918. first_segment() const noexcept
  1919. {
  1920. if(impl_.nseg_ == 0)
  1921. return {};
  1922. auto const p0 = impl_.cs_ +
  1923. impl_.offset(id_path) +
  1924. detail::path_prefix(
  1925. impl_.get(id_path));
  1926. auto const end = impl_.cs_ +
  1927. impl_.offset(id_query);
  1928. if(impl_.nseg_ == 1)
  1929. return string_view(
  1930. p0, end - p0);
  1931. auto p = p0;
  1932. while(*p != '/')
  1933. ++p;
  1934. BOOST_ASSERT(p < end);
  1935. return string_view(p0, p - p0);
  1936. }
  1937. detail::segments_iter_impl
  1938. url_base::
  1939. edit_segments(
  1940. detail::segments_iter_impl const& it0,
  1941. detail::segments_iter_impl const& it1,
  1942. detail::any_segments_iter&& src,
  1943. // -1 = preserve
  1944. // 0 = make relative (can fail)
  1945. // 1 = make absolute
  1946. int absolute)
  1947. {
  1948. // Iterator doesn't belong to this url
  1949. BOOST_ASSERT(it0.ref.alias_of(impl_));
  1950. // Iterator doesn't belong to this url
  1951. BOOST_ASSERT(it1.ref.alias_of(impl_));
  1952. // Iterator is in the wrong order
  1953. BOOST_ASSERT(it0.index <= it1.index);
  1954. // Iterator is out of range
  1955. BOOST_ASSERT(it0.index <= impl_.nseg_);
  1956. BOOST_ASSERT(it0.pos <= impl_.len(id_path));
  1957. // Iterator is out of range
  1958. BOOST_ASSERT(it1.index <= impl_.nseg_);
  1959. BOOST_ASSERT(it1.pos <= impl_.len(id_path));
  1960. //------------------------------------------------
  1961. //
  1962. // Calculate output prefix
  1963. //
  1964. // 0 = ""
  1965. // 1 = "/"
  1966. // 2 = "./"
  1967. // 3 = "/./"
  1968. //
  1969. bool const is_abs = is_path_absolute();
  1970. if(has_authority())
  1971. {
  1972. // Check if the new
  1973. // path would be empty
  1974. if( src.fast_nseg == 0 &&
  1975. it0.index == 0 &&
  1976. it1.index == impl_.nseg_)
  1977. {
  1978. // VFALCO we don't have
  1979. // access to nchar this early
  1980. //
  1981. //BOOST_ASSERT(nchar == 0);
  1982. absolute = 0;
  1983. }
  1984. else
  1985. {
  1986. // prefix "/" required
  1987. absolute = 1;
  1988. }
  1989. }
  1990. else if(absolute < 0)
  1991. {
  1992. absolute = is_abs; // preserve
  1993. }
  1994. auto const path_pos = impl_.offset(id_path);
  1995. std::size_t nchar = 0;
  1996. std::size_t prefix = 0;
  1997. bool encode_colons = false;
  1998. bool cp_src_prefix = false;
  1999. if(it0.index > 0)
  2000. {
  2001. // first segment unchanged
  2002. prefix = src.fast_nseg > 0;
  2003. }
  2004. else if(src.fast_nseg > 0)
  2005. {
  2006. // first segment from src
  2007. if(! src.front.empty())
  2008. {
  2009. if( src.front == "." &&
  2010. src.fast_nseg > 1)
  2011. if (src.s.empty())
  2012. {
  2013. // if front is ".", we need the extra "." in the prefix
  2014. // which will maintain the invariant that segments represent
  2015. // {"."}
  2016. prefix = 2 + absolute;
  2017. }
  2018. else
  2019. {
  2020. // if the "." prefix is explicitly required from set_path
  2021. // we do not include an extra "." segment
  2022. prefix = absolute;
  2023. cp_src_prefix = true;
  2024. }
  2025. else if(absolute)
  2026. prefix = 1;
  2027. else if(has_scheme() ||
  2028. ! src.front.contains(':'))
  2029. prefix = 0;
  2030. else
  2031. {
  2032. prefix = 0;
  2033. encode_colons = true;
  2034. }
  2035. }
  2036. else
  2037. {
  2038. prefix = 2 + absolute;
  2039. }
  2040. }
  2041. else
  2042. {
  2043. // first segment from it1
  2044. auto const p =
  2045. impl_.cs_ + path_pos + it1.pos;
  2046. switch(impl_.cs_ +
  2047. impl_.offset(id_query) - p)
  2048. {
  2049. case 0:
  2050. // points to end
  2051. prefix = absolute;
  2052. break;
  2053. default:
  2054. BOOST_ASSERT(*p == '/');
  2055. if(p[1] != '/')
  2056. {
  2057. if(absolute)
  2058. prefix = 1;
  2059. else if(has_scheme() ||
  2060. ! it1.dereference().contains(':'))
  2061. prefix = 0;
  2062. else
  2063. prefix = 2;
  2064. break;
  2065. }
  2066. // empty
  2067. BOOST_FALLTHROUGH;
  2068. case 1:
  2069. // empty
  2070. BOOST_ASSERT(*p == '/');
  2071. prefix = 2 + absolute;
  2072. break;
  2073. }
  2074. }
  2075. // append '/' to new segs
  2076. // if inserting at front.
  2077. std::size_t const suffix =
  2078. it1.index == 0 &&
  2079. impl_.nseg_ > 0 &&
  2080. src.fast_nseg > 0;
  2081. //------------------------------------------------
  2082. //
  2083. // Measure the number of encoded characters
  2084. // of output, and the number of inserted
  2085. // segments including internal separators.
  2086. //
  2087. src.encode_colons = encode_colons;
  2088. std::size_t nseg = 0;
  2089. if(src.measure(nchar))
  2090. {
  2091. src.encode_colons = false;
  2092. for(;;)
  2093. {
  2094. ++nseg;
  2095. if(! src.measure(nchar))
  2096. break;
  2097. ++nchar;
  2098. }
  2099. }
  2100. switch(src.fast_nseg)
  2101. {
  2102. case 0:
  2103. BOOST_ASSERT(nseg == 0);
  2104. break;
  2105. case 1:
  2106. BOOST_ASSERT(nseg == 1);
  2107. break;
  2108. case 2:
  2109. BOOST_ASSERT(nseg >= 2);
  2110. break;
  2111. }
  2112. //------------------------------------------------
  2113. //
  2114. // Calculate [pos0, pos1) to remove
  2115. //
  2116. auto pos0 = it0.pos;
  2117. if(it0.index == 0)
  2118. {
  2119. // patch pos for prefix
  2120. pos0 = 0;
  2121. }
  2122. auto pos1 = it1.pos;
  2123. if(it1.index == 0)
  2124. {
  2125. // patch pos for prefix
  2126. pos1 = detail::path_prefix(
  2127. impl_.get(id_path));
  2128. }
  2129. else if(
  2130. it0.index == 0 &&
  2131. it1.index < impl_.nseg_ &&
  2132. nseg == 0)
  2133. {
  2134. // Remove the slash from segment it1
  2135. // if it is becoming the new first
  2136. // segment.
  2137. ++pos1;
  2138. }
  2139. // calc decoded size of old range
  2140. auto const dn0 =
  2141. detail::decode_bytes_unsafe(
  2142. string_view(
  2143. impl_.cs_ +
  2144. impl_.offset(id_path) +
  2145. pos0,
  2146. pos1 - pos0));
  2147. //------------------------------------------------
  2148. //
  2149. // Resize
  2150. //
  2151. op_t op(*this, &src.s);
  2152. char* dest;
  2153. char const* end;
  2154. {
  2155. auto const nremove = pos1 - pos0;
  2156. // check overflow
  2157. if( nchar <= max_size() && (
  2158. prefix + suffix <=
  2159. max_size() - nchar))
  2160. {
  2161. nchar = prefix + nchar + suffix;
  2162. if( nchar <= nremove ||
  2163. nchar - nremove <=
  2164. max_size() - size())
  2165. goto ok;
  2166. }
  2167. // too large
  2168. detail::throw_length_error();
  2169. ok:
  2170. auto const new_size =
  2171. size() + nchar - nremove;
  2172. reserve_impl(new_size, op);
  2173. dest = s_ + path_pos + pos0;
  2174. op.move(
  2175. dest + nchar,
  2176. s_ + path_pos + pos1,
  2177. size() - path_pos - pos1);
  2178. impl_.set_size(
  2179. id_path,
  2180. impl_.len(id_path) + nchar - nremove);
  2181. BOOST_ASSERT(size() == new_size);
  2182. end = dest + nchar;
  2183. impl_.nseg_ = impl_.nseg_ + nseg - (
  2184. it1.index - it0.index) - cp_src_prefix;
  2185. if(s_)
  2186. s_[size()] = '\0';
  2187. }
  2188. //------------------------------------------------
  2189. //
  2190. // Output segments and internal separators:
  2191. //
  2192. // prefix [ segment [ '/' segment ] ] suffix
  2193. //
  2194. auto const dest0 = dest;
  2195. switch(prefix)
  2196. {
  2197. case 3:
  2198. *dest++ = '/';
  2199. *dest++ = '.';
  2200. *dest++ = '/';
  2201. break;
  2202. case 2:
  2203. *dest++ = '.';
  2204. BOOST_FALLTHROUGH;
  2205. case 1:
  2206. *dest++ = '/';
  2207. break;
  2208. default:
  2209. break;
  2210. }
  2211. src.rewind();
  2212. if(nseg > 0)
  2213. {
  2214. src.encode_colons = encode_colons;
  2215. for(;;)
  2216. {
  2217. src.copy(dest, end);
  2218. if(--nseg == 0)
  2219. break;
  2220. *dest++ = '/';
  2221. src.encode_colons = false;
  2222. }
  2223. if(suffix)
  2224. *dest++ = '/';
  2225. }
  2226. BOOST_ASSERT(dest == dest0 + nchar);
  2227. // calc decoded size of new range,
  2228. auto const dn =
  2229. detail::decode_bytes_unsafe(
  2230. string_view(dest0, dest - dest0));
  2231. impl_.decoded_[id_path] += dn - dn0;
  2232. return detail::segments_iter_impl(
  2233. impl_, pos0, it0.index);
  2234. }
  2235. //------------------------------------------------
  2236. auto
  2237. url_base::
  2238. edit_params(
  2239. detail::params_iter_impl const& it0,
  2240. detail::params_iter_impl const& it1,
  2241. detail::any_params_iter&& src) ->
  2242. detail::params_iter_impl
  2243. {
  2244. auto pos0 = impl_.offset(id_query);
  2245. auto pos1 = pos0 + it1.pos;
  2246. pos0 = pos0 + it0.pos;
  2247. // Iterator doesn't belong to this url
  2248. BOOST_ASSERT(it0.ref.alias_of(impl_));
  2249. // Iterator doesn't belong to this url
  2250. BOOST_ASSERT(it1.ref.alias_of(impl_));
  2251. // Iterator is in the wrong order
  2252. BOOST_ASSERT(it0.index <= it1.index);
  2253. // Iterator is out of range
  2254. BOOST_ASSERT(it0.index <= impl_.nparam_);
  2255. BOOST_ASSERT(pos0 <= impl_.offset(id_frag));
  2256. // Iterator is out of range
  2257. BOOST_ASSERT(it1.index <= impl_.nparam_);
  2258. BOOST_ASSERT(pos1 <= impl_.offset(id_frag));
  2259. // calc decoded size of old range,
  2260. // minus one if '?' or '&' prefixed
  2261. auto const dn0 =
  2262. detail::decode_bytes_unsafe(
  2263. string_view(
  2264. impl_.cs_ + pos0,
  2265. pos1 - pos0)) - (
  2266. impl_.len(id_query) > 0);
  2267. //------------------------------------------------
  2268. //
  2269. // Measure the number of encoded characters
  2270. // of output, and the number of inserted
  2271. // segments including internal separators.
  2272. //
  2273. std::size_t nchar = 0;
  2274. std::size_t nparam = 0;
  2275. if(src.measure(nchar))
  2276. {
  2277. ++nchar; // for '?' or '&'
  2278. for(;;)
  2279. {
  2280. ++nparam;
  2281. if(! src.measure(nchar))
  2282. break;
  2283. ++nchar; // for '&'
  2284. }
  2285. }
  2286. //------------------------------------------------
  2287. //
  2288. // Resize
  2289. //
  2290. op_t op(*this, &src.s0, &src.s1);
  2291. char* dest;
  2292. char const* end;
  2293. {
  2294. auto const nremove = pos1 - pos0;
  2295. // check overflow
  2296. if( nchar > nremove &&
  2297. nchar - nremove >
  2298. max_size() - size())
  2299. {
  2300. // too large
  2301. detail::throw_length_error();
  2302. }
  2303. auto const nparam1 =
  2304. impl_.nparam_ + nparam - (
  2305. it1.index - it0.index);
  2306. reserve_impl(size() + nchar - nremove, op);
  2307. dest = s_ + pos0;
  2308. end = dest + nchar;
  2309. if(impl_.nparam_ > 0)
  2310. {
  2311. // needed when we move
  2312. // the beginning of the query
  2313. s_[impl_.offset(id_query)] = '&';
  2314. }
  2315. op.move(
  2316. dest + nchar,
  2317. impl_.cs_ + pos1,
  2318. size() - pos1);
  2319. impl_.set_size(
  2320. id_query,
  2321. impl_.len(id_query) +
  2322. nchar - nremove);
  2323. impl_.nparam_ = nparam1;
  2324. if(nparam1 > 0)
  2325. {
  2326. // needed when we erase
  2327. // the beginning of the query
  2328. s_[impl_.offset(id_query)] = '?';
  2329. }
  2330. if(s_)
  2331. s_[size()] = '\0';
  2332. }
  2333. auto const dest0 = dest;
  2334. //------------------------------------------------
  2335. //
  2336. // Output params and internal separators:
  2337. //
  2338. // [ '?' param ] [ '&' param ]
  2339. //
  2340. if(nparam > 0)
  2341. {
  2342. if(it0.index == 0)
  2343. *dest++ = '?';
  2344. else
  2345. *dest++ = '&';
  2346. src.rewind();
  2347. for(;;)
  2348. {
  2349. src.copy(dest, end);
  2350. if(--nparam == 0)
  2351. break;
  2352. *dest++ = '&';
  2353. }
  2354. }
  2355. // calc decoded size of new range,
  2356. // minus one if '?' or '&' prefixed
  2357. auto const dn =
  2358. detail::decode_bytes_unsafe(
  2359. string_view(dest0, dest - dest0)) - (
  2360. impl_.len(id_query) > 0);
  2361. impl_.decoded_[id_query] += (dn - dn0);
  2362. return detail::params_iter_impl(
  2363. impl_,
  2364. pos0 - impl_.offset_[id_query],
  2365. it0.index);
  2366. }
  2367. //------------------------------------------------
  2368. void
  2369. url_base::
  2370. decoded_to_lower_impl(int id) noexcept
  2371. {
  2372. char* it = s_ + impl_.offset(id);
  2373. char const* const end = s_ + impl_.offset(id + 1);
  2374. while(it < end)
  2375. {
  2376. if (*it != '%')
  2377. {
  2378. *it = grammar::to_lower(
  2379. *it);
  2380. ++it;
  2381. continue;
  2382. }
  2383. it += 3;
  2384. }
  2385. }
  2386. void
  2387. url_base::
  2388. to_lower_impl(int id) noexcept
  2389. {
  2390. char* it = s_ + impl_.offset(id);
  2391. char const* const end = s_ + impl_.offset(id + 1);
  2392. while(it < end)
  2393. {
  2394. *it = grammar::to_lower(
  2395. *it);
  2396. ++it;
  2397. }
  2398. }
  2399. } // urls
  2400. } // boost
  2401. #endif