URI.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. //
  2. // URI.cpp
  3. //
  4. // $Id: //poco/1.4/Foundation/src/URI.cpp#5 $
  5. //
  6. // Library: Foundation
  7. // Package: URI
  8. // Module: URI
  9. //
  10. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #include "Poco/URI.h"
  16. #include "Poco/NumberFormatter.h"
  17. #include "Poco/Exception.h"
  18. #include "Poco/String.h"
  19. #include "Poco/NumberParser.h"
  20. #include "Poco/Path.h"
  21. namespace Poco {
  22. const std::string URI::RESERVED_PATH = "?#";
  23. const std::string URI::RESERVED_QUERY = "?#/";
  24. const std::string URI::RESERVED_FRAGMENT = "";
  25. const std::string URI::ILLEGAL = "%<>{}|\\\"^`";
  26. URI::URI():
  27. _port(0)
  28. {
  29. }
  30. URI::URI(const std::string& uri):
  31. _port(0)
  32. {
  33. parse(uri);
  34. }
  35. URI::URI(const char* uri):
  36. _port(0)
  37. {
  38. parse(std::string(uri));
  39. }
  40. URI::URI(const std::string& scheme, const std::string& pathEtc):
  41. _scheme(scheme),
  42. _port(0)
  43. {
  44. toLowerInPlace(_scheme);
  45. _port = getWellKnownPort();
  46. std::string::const_iterator beg = pathEtc.begin();
  47. std::string::const_iterator end = pathEtc.end();
  48. parsePathEtc(beg, end);
  49. }
  50. URI::URI(const std::string& scheme, const std::string& authority, const std::string& pathEtc):
  51. _scheme(scheme)
  52. {
  53. toLowerInPlace(_scheme);
  54. std::string::const_iterator beg = authority.begin();
  55. std::string::const_iterator end = authority.end();
  56. parseAuthority(beg, end);
  57. beg = pathEtc.begin();
  58. end = pathEtc.end();
  59. parsePathEtc(beg, end);
  60. }
  61. URI::URI(const std::string& scheme, const std::string& authority, const std::string& path, const std::string& query):
  62. _scheme(scheme),
  63. _path(path),
  64. _query(query)
  65. {
  66. toLowerInPlace(_scheme);
  67. std::string::const_iterator beg = authority.begin();
  68. std::string::const_iterator end = authority.end();
  69. parseAuthority(beg, end);
  70. }
  71. URI::URI(const std::string& scheme, const std::string& authority, const std::string& path, const std::string& query, const std::string& fragment):
  72. _scheme(scheme),
  73. _path(path),
  74. _query(query),
  75. _fragment(fragment)
  76. {
  77. toLowerInPlace(_scheme);
  78. std::string::const_iterator beg = authority.begin();
  79. std::string::const_iterator end = authority.end();
  80. parseAuthority(beg, end);
  81. }
  82. URI::URI(const URI& uri):
  83. _scheme(uri._scheme),
  84. _userInfo(uri._userInfo),
  85. _host(uri._host),
  86. _port(uri._port),
  87. _path(uri._path),
  88. _query(uri._query),
  89. _fragment(uri._fragment)
  90. {
  91. }
  92. URI::URI(const URI& baseURI, const std::string& relativeURI):
  93. _scheme(baseURI._scheme),
  94. _userInfo(baseURI._userInfo),
  95. _host(baseURI._host),
  96. _port(baseURI._port),
  97. _path(baseURI._path),
  98. _query(baseURI._query),
  99. _fragment(baseURI._fragment)
  100. {
  101. resolve(relativeURI);
  102. }
  103. URI::URI(const Path& path):
  104. _scheme("file"),
  105. _port(0)
  106. {
  107. Path absolutePath(path);
  108. absolutePath.makeAbsolute();
  109. _path = absolutePath.toString(Path::PATH_UNIX);
  110. }
  111. URI::~URI()
  112. {
  113. }
  114. URI& URI::operator = (const URI& uri)
  115. {
  116. if (&uri != this)
  117. {
  118. _scheme = uri._scheme;
  119. _userInfo = uri._userInfo;
  120. _host = uri._host;
  121. _port = uri._port;
  122. _path = uri._path;
  123. _query = uri._query;
  124. _fragment = uri._fragment;
  125. }
  126. return *this;
  127. }
  128. URI& URI::operator = (const std::string& uri)
  129. {
  130. clear();
  131. parse(uri);
  132. return *this;
  133. }
  134. URI& URI::operator = (const char* uri)
  135. {
  136. clear();
  137. parse(std::string(uri));
  138. return *this;
  139. }
  140. void URI::swap(URI& uri)
  141. {
  142. std::swap(_scheme, uri._scheme);
  143. std::swap(_userInfo, uri._userInfo);
  144. std::swap(_host, uri._host);
  145. std::swap(_port, uri._port);
  146. std::swap(_path, uri._path);
  147. std::swap(_query, uri._query);
  148. std::swap(_fragment, uri._fragment);
  149. }
  150. void URI::clear()
  151. {
  152. _scheme.clear();
  153. _userInfo.clear();
  154. _host.clear();
  155. _port = 0;
  156. _path.clear();
  157. _query.clear();
  158. _fragment.clear();
  159. }
  160. std::string URI::toString() const
  161. {
  162. std::string uri;
  163. if (isRelative())
  164. {
  165. encode(_path, RESERVED_PATH, uri);
  166. }
  167. else
  168. {
  169. uri = _scheme;
  170. uri += ':';
  171. std::string auth = getAuthority();
  172. if (!auth.empty() || _scheme == "file")
  173. {
  174. uri.append("//");
  175. uri.append(auth);
  176. }
  177. if (!_path.empty())
  178. {
  179. if (!auth.empty() && _path[0] != '/')
  180. uri += '/';
  181. encode(_path, RESERVED_PATH, uri);
  182. }
  183. else if (!_query.empty() || !_fragment.empty())
  184. {
  185. uri += '/';
  186. }
  187. }
  188. if (!_query.empty())
  189. {
  190. uri += '?';
  191. uri.append(_query);
  192. }
  193. if (!_fragment.empty())
  194. {
  195. uri += '#';
  196. encode(_fragment, RESERVED_FRAGMENT, uri);
  197. }
  198. return uri;
  199. }
  200. void URI::setScheme(const std::string& scheme)
  201. {
  202. _scheme = scheme;
  203. toLowerInPlace(_scheme);
  204. if (_port == 0)
  205. _port = getWellKnownPort();
  206. }
  207. void URI::setUserInfo(const std::string& userInfo)
  208. {
  209. _userInfo.clear();
  210. decode(userInfo, _userInfo);
  211. }
  212. void URI::setHost(const std::string& host)
  213. {
  214. _host = host;
  215. }
  216. unsigned short URI::getPort() const
  217. {
  218. if (_port == 0)
  219. return getWellKnownPort();
  220. else
  221. return _port;
  222. }
  223. void URI::setPort(unsigned short port)
  224. {
  225. _port = port;
  226. }
  227. std::string URI::getAuthority() const
  228. {
  229. std::string auth;
  230. if (!_userInfo.empty())
  231. {
  232. auth.append(_userInfo);
  233. auth += '@';
  234. }
  235. if (_host.find(':') != std::string::npos)
  236. {
  237. auth += '[';
  238. auth += _host;
  239. auth += ']';
  240. }
  241. else auth.append(_host);
  242. if (_port && !isWellKnownPort())
  243. {
  244. auth += ':';
  245. NumberFormatter::append(auth, _port);
  246. }
  247. return auth;
  248. }
  249. void URI::setAuthority(const std::string& authority)
  250. {
  251. _userInfo.clear();
  252. _host.clear();
  253. _port = 0;
  254. std::string::const_iterator beg = authority.begin();
  255. std::string::const_iterator end = authority.end();
  256. parseAuthority(beg, end);
  257. }
  258. void URI::setPath(const std::string& path)
  259. {
  260. _path.clear();
  261. decode(path, _path);
  262. }
  263. void URI::setRawQuery(const std::string& query)
  264. {
  265. _query = query;
  266. }
  267. void URI::setQuery(const std::string& query)
  268. {
  269. _query.clear();
  270. encode(query, RESERVED_QUERY, _query);
  271. }
  272. void URI::addQueryParameter(const std::string& param, const std::string& val)
  273. {
  274. std::string reserved(RESERVED_QUERY);
  275. reserved += "=&";
  276. if (!_query.empty()) _query += '&';
  277. encode(param, reserved, _query);
  278. _query += '=';
  279. encode(val, reserved, _query);
  280. }
  281. std::string URI::getQuery() const
  282. {
  283. std::string query;
  284. decode(_query, query);
  285. return query;
  286. }
  287. URI::QueryParameters URI::getQueryParameters() const
  288. {
  289. QueryParameters result;
  290. std::string::const_iterator it(_query.begin());
  291. std::string::const_iterator end(_query.end());
  292. while (it != end)
  293. {
  294. std::string name;
  295. std::string value;
  296. while (it != end && *it != '=' && *it != '&')
  297. {
  298. if (*it == '+')
  299. name += ' ';
  300. else
  301. name += *it;
  302. ++it;
  303. }
  304. if (it != end && *it == '=')
  305. {
  306. ++it;
  307. while (it != end && *it != '&')
  308. {
  309. if (*it == '+')
  310. value += ' ';
  311. else
  312. value += *it;
  313. ++it;
  314. }
  315. }
  316. std::string decodedName;
  317. std::string decodedValue;
  318. URI::decode(name, decodedName);
  319. URI::decode(value, decodedValue);
  320. result.push_back(std::make_pair(decodedName, decodedValue));
  321. if (it != end && *it == '&') ++it;
  322. }
  323. return result;
  324. }
  325. void URI::setQueryParameters(const QueryParameters& params)
  326. {
  327. _query.clear();
  328. for (QueryParameters::const_iterator it = params.begin(); it != params.end(); ++it)
  329. {
  330. addQueryParameter(it->first, it->second);
  331. }
  332. }
  333. void URI::setFragment(const std::string& fragment)
  334. {
  335. _fragment.clear();
  336. decode(fragment, _fragment);
  337. }
  338. void URI::setPathEtc(const std::string& pathEtc)
  339. {
  340. _path.clear();
  341. _query.clear();
  342. _fragment.clear();
  343. std::string::const_iterator beg = pathEtc.begin();
  344. std::string::const_iterator end = pathEtc.end();
  345. parsePathEtc(beg, end);
  346. }
  347. std::string URI::getPathEtc() const
  348. {
  349. std::string pathEtc;
  350. encode(_path, RESERVED_PATH, pathEtc);
  351. if (!_query.empty())
  352. {
  353. pathEtc += '?';
  354. pathEtc += _query;
  355. }
  356. if (!_fragment.empty())
  357. {
  358. pathEtc += '#';
  359. encode(_fragment, RESERVED_FRAGMENT, pathEtc);
  360. }
  361. return pathEtc;
  362. }
  363. std::string URI::getPathAndQuery() const
  364. {
  365. std::string pathAndQuery;
  366. encode(_path, RESERVED_PATH, pathAndQuery);
  367. if (!_query.empty())
  368. {
  369. pathAndQuery += '?';
  370. pathAndQuery += _query;
  371. }
  372. return pathAndQuery;
  373. }
  374. void URI::resolve(const std::string& relativeURI)
  375. {
  376. URI parsedURI(relativeURI);
  377. resolve(parsedURI);
  378. }
  379. void URI::resolve(const URI& relativeURI)
  380. {
  381. if (!relativeURI._scheme.empty())
  382. {
  383. _scheme = relativeURI._scheme;
  384. _userInfo = relativeURI._userInfo;
  385. _host = relativeURI._host;
  386. _port = relativeURI._port;
  387. _path = relativeURI._path;
  388. _query = relativeURI._query;
  389. removeDotSegments();
  390. }
  391. else
  392. {
  393. if (!relativeURI._host.empty())
  394. {
  395. _userInfo = relativeURI._userInfo;
  396. _host = relativeURI._host;
  397. _port = relativeURI._port;
  398. _path = relativeURI._path;
  399. _query = relativeURI._query;
  400. removeDotSegments();
  401. }
  402. else
  403. {
  404. if (relativeURI._path.empty())
  405. {
  406. if (!relativeURI._query.empty())
  407. _query = relativeURI._query;
  408. }
  409. else
  410. {
  411. if (relativeURI._path[0] == '/')
  412. {
  413. _path = relativeURI._path;
  414. removeDotSegments();
  415. }
  416. else
  417. {
  418. mergePath(relativeURI._path);
  419. }
  420. _query = relativeURI._query;
  421. }
  422. }
  423. }
  424. _fragment = relativeURI._fragment;
  425. }
  426. bool URI::isRelative() const
  427. {
  428. return _scheme.empty();
  429. }
  430. bool URI::empty() const
  431. {
  432. return _scheme.empty() && _host.empty() && _path.empty() && _query.empty() && _fragment.empty();
  433. }
  434. bool URI::operator == (const URI& uri) const
  435. {
  436. return equals(uri);
  437. }
  438. bool URI::operator == (const std::string& uri) const
  439. {
  440. URI parsedURI(uri);
  441. return equals(parsedURI);
  442. }
  443. bool URI::operator != (const URI& uri) const
  444. {
  445. return !equals(uri);
  446. }
  447. bool URI::operator != (const std::string& uri) const
  448. {
  449. URI parsedURI(uri);
  450. return !equals(parsedURI);
  451. }
  452. bool URI::equals(const URI& uri) const
  453. {
  454. return _scheme == uri._scheme
  455. && _userInfo == uri._userInfo
  456. && _host == uri._host
  457. && getPort() == uri.getPort()
  458. && _path == uri._path
  459. && _query == uri._query
  460. && _fragment == uri._fragment;
  461. }
  462. void URI::normalize()
  463. {
  464. removeDotSegments(!isRelative());
  465. }
  466. void URI::removeDotSegments(bool removeLeading)
  467. {
  468. if (_path.empty()) return;
  469. bool leadingSlash = *(_path.begin()) == '/';
  470. bool trailingSlash = *(_path.rbegin()) == '/';
  471. std::vector<std::string> segments;
  472. std::vector<std::string> normalizedSegments;
  473. getPathSegments(segments);
  474. for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
  475. {
  476. if (*it == "..")
  477. {
  478. if (!normalizedSegments.empty())
  479. {
  480. if (normalizedSegments.back() == "..")
  481. normalizedSegments.push_back(*it);
  482. else
  483. normalizedSegments.pop_back();
  484. }
  485. else if (!removeLeading)
  486. {
  487. normalizedSegments.push_back(*it);
  488. }
  489. }
  490. else if (*it != ".")
  491. {
  492. normalizedSegments.push_back(*it);
  493. }
  494. }
  495. buildPath(normalizedSegments, leadingSlash, trailingSlash);
  496. }
  497. void URI::getPathSegments(std::vector<std::string>& segments)
  498. {
  499. getPathSegments(_path, segments);
  500. }
  501. void URI::getPathSegments(const std::string& path, std::vector<std::string>& segments)
  502. {
  503. std::string::const_iterator it = path.begin();
  504. std::string::const_iterator end = path.end();
  505. std::string seg;
  506. while (it != end)
  507. {
  508. if (*it == '/')
  509. {
  510. if (!seg.empty())
  511. {
  512. segments.push_back(seg);
  513. seg.clear();
  514. }
  515. }
  516. else seg += *it;
  517. ++it;
  518. }
  519. if (!seg.empty())
  520. segments.push_back(seg);
  521. }
  522. void URI::encode(const std::string& str, const std::string& reserved, std::string& encodedStr)
  523. {
  524. for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
  525. {
  526. char c = *it;
  527. if ((c >= 'a' && c <= 'z') ||
  528. (c >= 'A' && c <= 'Z') ||
  529. (c >= '0' && c <= '9') ||
  530. c == '-' || c == '_' ||
  531. c == '.' || c == '~')
  532. {
  533. encodedStr += c;
  534. }
  535. else if (c <= 0x20 || c >= 0x7F || ILLEGAL.find(c) != std::string::npos || reserved.find(c) != std::string::npos)
  536. {
  537. encodedStr += '%';
  538. encodedStr += NumberFormatter::formatHex((unsigned) (unsigned char) c, 2);
  539. }
  540. else encodedStr += c;
  541. }
  542. }
  543. void URI::decode(const std::string& str, std::string& decodedStr, bool plusAsSpace)
  544. {
  545. bool inQuery = false;
  546. std::string::const_iterator it = str.begin();
  547. std::string::const_iterator end = str.end();
  548. while (it != end)
  549. {
  550. char c = *it++;
  551. if (c == '?') inQuery = true;
  552. // spaces may be encoded as plus signs in the query
  553. if (inQuery && plusAsSpace && c == '+') c = ' ';
  554. else if (c == '%')
  555. {
  556. if (it == end) throw SyntaxException("URI encoding: no hex digit following percent sign", str);
  557. char hi = *it++;
  558. if (it == end) throw SyntaxException("URI encoding: two hex digits must follow percent sign", str);
  559. char lo = *it++;
  560. if (hi >= '0' && hi <= '9')
  561. c = hi - '0';
  562. else if (hi >= 'A' && hi <= 'F')
  563. c = hi - 'A' + 10;
  564. else if (hi >= 'a' && hi <= 'f')
  565. c = hi - 'a' + 10;
  566. else throw SyntaxException("URI encoding: not a hex digit");
  567. c *= 16;
  568. if (lo >= '0' && lo <= '9')
  569. c += lo - '0';
  570. else if (lo >= 'A' && lo <= 'F')
  571. c += lo - 'A' + 10;
  572. else if (lo >= 'a' && lo <= 'f')
  573. c += lo - 'a' + 10;
  574. else throw SyntaxException("URI encoding: not a hex digit");
  575. }
  576. decodedStr += c;
  577. }
  578. }
  579. bool URI::isWellKnownPort() const
  580. {
  581. return _port == getWellKnownPort();
  582. }
  583. unsigned short URI::getWellKnownPort() const
  584. {
  585. if (_scheme == "ftp")
  586. return 21;
  587. else if (_scheme == "ssh")
  588. return 22;
  589. else if (_scheme == "telnet")
  590. return 23;
  591. else if (_scheme == "http")
  592. return 80;
  593. else if (_scheme == "nntp")
  594. return 119;
  595. else if (_scheme == "ldap")
  596. return 389;
  597. else if (_scheme == "https")
  598. return 443;
  599. else if (_scheme == "rtsp")
  600. return 554;
  601. else if (_scheme == "sip")
  602. return 5060;
  603. else if (_scheme == "sips")
  604. return 5061;
  605. else if (_scheme == "xmpp")
  606. return 5222;
  607. else
  608. return 0;
  609. }
  610. void URI::parse(const std::string& uri)
  611. {
  612. std::string::const_iterator it = uri.begin();
  613. std::string::const_iterator end = uri.end();
  614. if (it == end) return;
  615. if (*it != '/' && *it != '.' && *it != '?' && *it != '#')
  616. {
  617. std::string scheme;
  618. while (it != end && *it != ':' && *it != '?' && *it != '#' && *it != '/') scheme += *it++;
  619. if (it != end && *it == ':')
  620. {
  621. ++it;
  622. if (it == end) throw SyntaxException("URI scheme must be followed by authority or path", uri);
  623. setScheme(scheme);
  624. if (*it == '/')
  625. {
  626. ++it;
  627. if (it != end && *it == '/')
  628. {
  629. ++it;
  630. parseAuthority(it, end);
  631. }
  632. else --it;
  633. }
  634. parsePathEtc(it, end);
  635. }
  636. else
  637. {
  638. it = uri.begin();
  639. parsePathEtc(it, end);
  640. }
  641. }
  642. else parsePathEtc(it, end);
  643. }
  644. void URI::parseAuthority(std::string::const_iterator& it, const std::string::const_iterator& end)
  645. {
  646. std::string userInfo;
  647. std::string part;
  648. while (it != end && *it != '/' && *it != '?' && *it != '#')
  649. {
  650. if (*it == '@')
  651. {
  652. userInfo = part;
  653. part.clear();
  654. }
  655. else part += *it;
  656. ++it;
  657. }
  658. std::string::const_iterator pbeg = part.begin();
  659. std::string::const_iterator pend = part.end();
  660. parseHostAndPort(pbeg, pend);
  661. _userInfo = userInfo;
  662. }
  663. void URI::parseHostAndPort(std::string::const_iterator& it, const std::string::const_iterator& end)
  664. {
  665. if (it == end) return;
  666. std::string host;
  667. if (*it == '[')
  668. {
  669. // IPv6 address
  670. ++it;
  671. while (it != end && *it != ']') host += *it++;
  672. if (it == end) throw SyntaxException("unterminated IPv6 address");
  673. ++it;
  674. }
  675. else
  676. {
  677. while (it != end && *it != ':') host += *it++;
  678. }
  679. if (it != end && *it == ':')
  680. {
  681. ++it;
  682. std::string port;
  683. while (it != end) port += *it++;
  684. if (!port.empty())
  685. {
  686. int nport = 0;
  687. if (NumberParser::tryParse(port, nport) && nport > 0 && nport < 65536)
  688. _port = (unsigned short) nport;
  689. else
  690. throw SyntaxException("bad or invalid port number", port);
  691. }
  692. else _port = getWellKnownPort();
  693. }
  694. else _port = getWellKnownPort();
  695. _host = host;
  696. toLowerInPlace(_host);
  697. }
  698. void URI::parsePath(std::string::const_iterator& it, const std::string::const_iterator& end)
  699. {
  700. std::string path;
  701. while (it != end && *it != '?' && *it != '#') path += *it++;
  702. decode(path, _path);
  703. }
  704. void URI::parsePathEtc(std::string::const_iterator& it, const std::string::const_iterator& end)
  705. {
  706. if (it == end) return;
  707. if (*it != '?' && *it != '#')
  708. parsePath(it, end);
  709. if (it != end && *it == '?')
  710. {
  711. ++it;
  712. parseQuery(it, end);
  713. }
  714. if (it != end && *it == '#')
  715. {
  716. ++it;
  717. parseFragment(it, end);
  718. }
  719. }
  720. void URI::parseQuery(std::string::const_iterator& it, const std::string::const_iterator& end)
  721. {
  722. _query.clear();
  723. while (it != end && *it != '#') _query += *it++;
  724. }
  725. void URI::parseFragment(std::string::const_iterator& it, const std::string::const_iterator& end)
  726. {
  727. std::string fragment;
  728. while (it != end) fragment += *it++;
  729. decode(fragment, _fragment);
  730. }
  731. void URI::mergePath(const std::string& path)
  732. {
  733. std::vector<std::string> segments;
  734. std::vector<std::string> normalizedSegments;
  735. bool addLeadingSlash = false;
  736. if (!_path.empty())
  737. {
  738. getPathSegments(segments);
  739. bool endsWithSlash = *(_path.rbegin()) == '/';
  740. if (!endsWithSlash && !segments.empty())
  741. segments.pop_back();
  742. addLeadingSlash = _path[0] == '/';
  743. }
  744. getPathSegments(path, segments);
  745. addLeadingSlash = addLeadingSlash || (!path.empty() && path[0] == '/');
  746. bool hasTrailingSlash = (!path.empty() && *(path.rbegin()) == '/');
  747. bool addTrailingSlash = false;
  748. for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
  749. {
  750. if (*it == "..")
  751. {
  752. addTrailingSlash = true;
  753. if (!normalizedSegments.empty())
  754. normalizedSegments.pop_back();
  755. }
  756. else if (*it != ".")
  757. {
  758. addTrailingSlash = false;
  759. normalizedSegments.push_back(*it);
  760. }
  761. else addTrailingSlash = true;
  762. }
  763. buildPath(normalizedSegments, addLeadingSlash, hasTrailingSlash || addTrailingSlash);
  764. }
  765. void URI::buildPath(const std::vector<std::string>& segments, bool leadingSlash, bool trailingSlash)
  766. {
  767. _path.clear();
  768. bool first = true;
  769. for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
  770. {
  771. if (first)
  772. {
  773. first = false;
  774. if (leadingSlash)
  775. _path += '/';
  776. else if (_scheme.empty() && (*it).find(':') != std::string::npos)
  777. _path.append("./");
  778. }
  779. else _path += '/';
  780. _path.append(*it);
  781. }
  782. if (trailingSlash)
  783. _path += '/';
  784. }
  785. } // namespace Poco