lluri.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:14k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lluri.cpp
  3.  * @author Phoenix
  4.  * @date 2006-02-08
  5.  * @brief Implementation of the LLURI class.
  6.  *
  7.  * $LicenseInfo:firstyear=2006&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2006-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "linden_common.h"
  35. #include "llapp.h"
  36. #include "lluri.h"
  37. #include "llsd.h"
  38. #include <iomanip>
  39.   
  40. #include "lluuid.h"
  41. // system includes
  42. #include <boost/tokenizer.hpp>
  43. void encode_character(std::ostream& ostr, std::string::value_type val)
  44. {
  45. ostr << "%"
  46.      << std::uppercase
  47.      << std::hex
  48.      << std::setw(2)
  49.      << std::setfill('0') 
  50.      // VWR-4010 Cannot cast to U32 because sign-extension on 
  51.      // chars > 128 will result in FFFFFFC3 instead of F3.
  52.      << static_cast<S32>(static_cast<U8>(val))
  53. // reset stream state
  54.      << std::nouppercase
  55.      << std::dec
  56.      << std::setfill(' ');
  57. }
  58. // static
  59. std::string LLURI::escape(
  60. const std::string& str,
  61. const std::string& allowed,
  62. bool is_allowed_sorted)
  63. {
  64. // *NOTE: This size determination feels like a good value to
  65. // me. If someone wante to come up with a more precise heuristic
  66. // with some data to back up the assertion that 'sort is good'
  67. // then feel free to change this test a bit.
  68. if(!is_allowed_sorted && (str.size() > 2 * allowed.size()))
  69. {
  70. // if it's already sorted, or if the url is quite long, we
  71. // want to optimize this process.
  72. std::string sorted_allowed(allowed);
  73. std::sort(sorted_allowed.begin(), sorted_allowed.end());
  74. return escape(str, sorted_allowed, true);
  75. }
  76. std::ostringstream ostr;
  77. std::string::const_iterator it = str.begin();
  78. std::string::const_iterator end = str.end();
  79. std::string::value_type c;
  80. if(is_allowed_sorted)
  81. {
  82. std::string::const_iterator allowed_begin(allowed.begin());
  83. std::string::const_iterator allowed_end(allowed.end());
  84. for(; it != end; ++it)
  85. {
  86. c = *it;
  87. if(std::binary_search(allowed_begin, allowed_end, c))
  88. {
  89. ostr << c;
  90. }
  91. else
  92. {
  93. encode_character(ostr, c);
  94. }
  95. }
  96. }
  97. else
  98. {
  99. for(; it != end; ++it)
  100. {
  101. c = *it;
  102. if(allowed.find(c) == std::string::npos)
  103. {
  104. encode_character(ostr, c);
  105. }
  106. else
  107. {
  108. ostr << c;
  109. }
  110. }
  111. }
  112. return ostr.str();
  113. }
  114. // static
  115. std::string LLURI::unescape(const std::string& str)
  116. {
  117. std::ostringstream ostr;
  118. std::string::const_iterator it = str.begin();
  119. std::string::const_iterator end = str.end();
  120. for(; it != end; ++it)
  121. {
  122. if((*it) == '%')
  123. {
  124. ++it;
  125. if(it == end) break;
  126. U8 c = hex_as_nybble(*it++);
  127. c = c << 4;
  128. if (it == end) break;
  129. c |= hex_as_nybble(*it);
  130. ostr.put((char)c);
  131. }
  132. else
  133. {
  134. ostr.put(*it);
  135. }
  136. }
  137. return ostr.str();
  138. }
  139. namespace
  140. {
  141. const std::string unreserved()
  142. {
  143. static const std::string s =   
  144. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  145. "0123456789"
  146. "-._~";
  147. return s;
  148. }
  149. const std::string sub_delims()
  150. {
  151. static const std::string s = "!$&'()*+,;=";
  152. return s;
  153. }
  154. std::string escapeHostAndPort(const std::string& s)
  155. { return LLURI::escape(s, unreserved() + sub_delims() +":"); }
  156. std::string escapePathComponent(const std::string& s)
  157. { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); }
  158. std::string escapeQueryVariable(const std::string& s)
  159. { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); }  // sub_delims - "&;=" + ":@"
  160. std::string escapeQueryValue(const std::string& s)
  161. { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
  162. }
  163. //static
  164. std::string LLURI::escape(const std::string& str)
  165. {
  166. static std::string default_allowed = unreserved();
  167. static bool initialized = false;
  168. if(!initialized)
  169. {
  170. std::sort(default_allowed.begin(), default_allowed.end());
  171. initialized = true;
  172. }
  173. return escape(str, default_allowed, true);
  174. }
  175. LLURI::LLURI()
  176. {
  177. }
  178. LLURI::LLURI(const std::string& escaped_str)
  179. {
  180. std::string::size_type delim_pos;
  181. delim_pos = escaped_str.find(':');
  182. std::string temp;
  183. if (delim_pos == std::string::npos)
  184. {
  185. mScheme = "";
  186. mEscapedOpaque = escaped_str;
  187. }
  188. else
  189. {
  190. mScheme = escaped_str.substr(0, delim_pos);
  191. mEscapedOpaque = escaped_str.substr(delim_pos+1);
  192. }
  193. parseAuthorityAndPathUsingOpaque();
  194. delim_pos = mEscapedPath.find('?');
  195. if (delim_pos != std::string::npos)
  196. {
  197. mEscapedQuery = mEscapedPath.substr(delim_pos+1);
  198. mEscapedPath = mEscapedPath.substr(0,delim_pos);
  199. }
  200. }
  201. static BOOL isDefault(const std::string& scheme, U16 port)
  202. {
  203. if (scheme == "http")
  204. return port == 80;
  205. if (scheme == "https")
  206. return port == 443;
  207. if (scheme == "ftp")
  208. return port == 21;
  209. return FALSE;
  210. }
  211. void LLURI::parseAuthorityAndPathUsingOpaque()
  212. {
  213. if (mScheme == "http" || mScheme == "https" ||
  214. mScheme == "ftp" || mScheme == "secondlife" )
  215. {
  216. if (mEscapedOpaque.substr(0,2) != "//")
  217. {
  218. return;
  219. }
  220. std::string::size_type delim_pos, delim_pos2;
  221. delim_pos = mEscapedOpaque.find('/', 2);
  222. delim_pos2 = mEscapedOpaque.find('?', 2);
  223. // no path, no query
  224. if (delim_pos == std::string::npos &&
  225. delim_pos2 == std::string::npos)
  226. {
  227. mEscapedAuthority = mEscapedOpaque.substr(2);
  228. mEscapedPath = "";
  229. }
  230. // path exist, no query
  231. else if (delim_pos2 == std::string::npos)
  232. {
  233. mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2);
  234. mEscapedPath = mEscapedOpaque.substr(delim_pos);
  235. }
  236. // no path, only query
  237. else if (delim_pos == std::string::npos ||
  238.  delim_pos2 < delim_pos)
  239. {
  240. mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos2-2);
  241. // query part will be broken out later
  242. mEscapedPath = mEscapedOpaque.substr(delim_pos2);
  243. }
  244. // path and query
  245. else
  246. {
  247. mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2);
  248. // query part will be broken out later
  249. mEscapedPath = mEscapedOpaque.substr(delim_pos);
  250. }
  251. }
  252. else if (mScheme == "about")
  253. {
  254. mEscapedPath = mEscapedOpaque;
  255. }
  256. }
  257. LLURI::LLURI(const std::string& scheme,
  258.  const std::string& userName,
  259.  const std::string& password,
  260.  const std::string& hostName,
  261.  U16 port,
  262.  const std::string& escapedPath,
  263.  const std::string& escapedQuery)
  264. : mScheme(scheme),
  265.   mEscapedPath(escapedPath),
  266.   mEscapedQuery(escapedQuery)
  267. {
  268. std::ostringstream auth;
  269. std::ostringstream opaque;
  270. opaque << "//";
  271. if (!userName.empty())
  272. {
  273. auth << escape(userName);
  274. if (!password.empty())
  275. {
  276. auth << ':' << escape(password);
  277. }
  278. auth << '@';
  279. }
  280. auth << hostName;
  281. if (!isDefault(scheme, port))
  282. {
  283. auth << ':' << port;
  284. }
  285. mEscapedAuthority = auth.str();
  286. opaque << mEscapedAuthority << escapedPath << escapedQuery;
  287. mEscapedOpaque = opaque.str();
  288. }
  289. LLURI::~LLURI()
  290. {
  291. }
  292. // static
  293. LLURI LLURI::buildHTTP(const std::string& prefix,
  294.    const LLSD& path)
  295. {
  296. LLURI result;
  297. // TODO: deal with '/' '?' '#' in host_port
  298. if (prefix.find("://") != prefix.npos)
  299. {
  300. // it is a prefix
  301. result = LLURI(prefix);
  302. }
  303. else
  304. {
  305. // it is just a host and optional port
  306. result.mScheme = "http";
  307. result.mEscapedAuthority = escapeHostAndPort(prefix);
  308. }
  309. if (path.isArray())
  310. {
  311. // break out and escape each path component
  312. for (LLSD::array_const_iterator it = path.beginArray();
  313.  it != path.endArray();
  314.  ++it)
  315. {
  316. lldebugs << "PATH: inserting " << it->asString() << llendl;
  317. result.mEscapedPath += "/" + escapePathComponent(it->asString());
  318. }
  319. }
  320. else if(path.isString())
  321. {
  322. result.mEscapedPath += "/" + escapePathComponent(path.asString());
  323. else if(path.isUndefined())
  324. {
  325.   // do nothing
  326. }
  327.     else
  328. {
  329.   llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" 
  330.   << path.type() << llendl;
  331. }
  332. result.mEscapedOpaque = "//" + result.mEscapedAuthority +
  333. result.mEscapedPath;
  334. return result;
  335. }
  336. // static
  337. LLURI LLURI::buildHTTP(const std::string& prefix,
  338.    const LLSD& path,
  339.    const LLSD& query)
  340. {
  341. LLURI uri = buildHTTP(prefix, path);
  342. // break out and escape each query component
  343. uri.mEscapedQuery = mapToQueryString(query);
  344. uri.mEscapedOpaque += uri.mEscapedQuery ;
  345. uri.mEscapedQuery.erase(0,1); // trim the leading '?'
  346. return uri;
  347. }
  348. // static
  349. LLURI LLURI::buildHTTP(const std::string& host,
  350.    const U32& port,
  351.    const LLSD& path)
  352. {
  353. return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path);
  354. }
  355. // static
  356. LLURI LLURI::buildHTTP(const std::string& host,
  357.    const U32& port,
  358.    const LLSD& path,
  359.    const LLSD& query)
  360. {
  361. return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query);
  362. }
  363. std::string LLURI::asString() const
  364. {
  365. if (mScheme.empty())
  366. {
  367. return mEscapedOpaque;
  368. }
  369. else
  370. {
  371. return mScheme + ":" + mEscapedOpaque;
  372. }
  373. }
  374. std::string LLURI::scheme() const
  375. {
  376. return mScheme;
  377. }
  378. std::string LLURI::opaque() const
  379. {
  380. return unescape(mEscapedOpaque);
  381. }
  382. std::string LLURI::authority() const
  383. {
  384. return unescape(mEscapedAuthority);
  385. }
  386. namespace {
  387. void findAuthorityParts(const std::string& authority,
  388. std::string& user,
  389. std::string& host,
  390. std::string& port)
  391. {
  392. std::string::size_type start_pos = authority.find('@');
  393. if (start_pos == std::string::npos)
  394. {
  395. user = "";
  396. start_pos = 0;
  397. }
  398. else
  399. {
  400. user = authority.substr(0, start_pos);
  401. start_pos += 1;
  402. }
  403. std::string::size_type end_pos = authority.find(':', start_pos);
  404. if (end_pos == std::string::npos)
  405. {
  406. host = authority.substr(start_pos);
  407. port = "";
  408. }
  409. else
  410. {
  411. host = authority.substr(start_pos, end_pos - start_pos);
  412. port = authority.substr(end_pos + 1);
  413. }
  414. }
  415. }
  416. std::string LLURI::hostName() const
  417. {
  418. std::string user, host, port;
  419. findAuthorityParts(mEscapedAuthority, user, host, port);
  420. return unescape(host);
  421. }
  422. std::string LLURI::userName() const
  423. {
  424. std::string user, userPass, host, port;
  425. findAuthorityParts(mEscapedAuthority, userPass, host, port);
  426. std::string::size_type pos = userPass.find(':');
  427. if (pos != std::string::npos)
  428. {
  429. user = userPass.substr(0, pos);
  430. }
  431. return unescape(user);
  432. }
  433. std::string LLURI::password() const
  434. {
  435. std::string pass, userPass, host, port;
  436. findAuthorityParts(mEscapedAuthority, userPass, host, port);
  437. std::string::size_type pos = userPass.find(':');
  438. if (pos != std::string::npos)
  439. {
  440. pass = userPass.substr(pos + 1);
  441. }
  442. return unescape(pass);
  443. }
  444. BOOL LLURI::defaultPort() const
  445. {
  446. return isDefault(mScheme, hostPort());
  447. }
  448. U16 LLURI::hostPort() const
  449. {
  450. std::string user, host, port;
  451. findAuthorityParts(mEscapedAuthority, user, host, port);
  452. if (port.empty())
  453. {
  454. if (mScheme == "http")
  455. return 80;
  456. if (mScheme == "https")
  457. return 443;
  458. if (mScheme == "ftp")
  459. return 21;
  460. return 0;
  461. }
  462. return atoi(port.c_str());
  463. }
  464. std::string LLURI::path() const
  465. {
  466. return unescape(mEscapedPath);
  467. }
  468. LLSD LLURI::pathArray() const
  469. {
  470. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  471. boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
  472. tokenizer tokens(mEscapedPath, sep);
  473. tokenizer::iterator it = tokens.begin();
  474. tokenizer::iterator end = tokens.end();
  475. LLSD params;
  476. for ( ; it != end; ++it)
  477. {
  478. params.append(*it);
  479. }
  480. return params;
  481. }
  482. std::string LLURI::query() const
  483. {
  484. return unescape(mEscapedQuery);
  485. }
  486. LLSD LLURI::queryMap() const
  487. {
  488. return queryMap(mEscapedQuery);
  489. }
  490. // static
  491. LLSD LLURI::queryMap(std::string escaped_query_string)
  492. {
  493. lldebugs << "LLURI::queryMap query params: " << escaped_query_string << llendl;
  494. LLSD result = LLSD::emptyArray();
  495. while(!escaped_query_string.empty())
  496. {
  497. // get tuple first
  498. std::string tuple;
  499. std::string::size_type tuple_begin = escaped_query_string.find('&');
  500. if (tuple_begin != std::string::npos)
  501. {
  502. tuple = escaped_query_string.substr(0, tuple_begin);
  503. escaped_query_string = escaped_query_string.substr(tuple_begin+1);
  504. }
  505. else
  506. {
  507. tuple = escaped_query_string;
  508. escaped_query_string = "";
  509. }
  510. if (tuple.empty()) continue;
  511. // parse tuple
  512. std::string::size_type key_end = tuple.find('=');
  513. if (key_end != std::string::npos)
  514. {
  515. std::string key = unescape(tuple.substr(0,key_end));
  516. std::string value = unescape(tuple.substr(key_end+1));
  517. lldebugs << "inserting key " << key << " value " << value << llendl;
  518. result[key] = value;
  519. }
  520. else
  521. {
  522. lldebugs << "inserting key " << unescape(tuple) << " value true" << llendl;
  523.     result[unescape(tuple)] = true;
  524. }
  525. }
  526. return result;
  527. }
  528. std::string LLURI::mapToQueryString(const LLSD& queryMap)
  529. {
  530. std::string query_string;
  531. if (queryMap.isMap())
  532. {
  533. bool first_element = true;
  534. LLSD::map_const_iterator iter = queryMap.beginMap();
  535. LLSD::map_const_iterator end = queryMap.endMap();
  536. std::ostringstream ostr;
  537. for (; iter != end; ++iter)
  538. {
  539. if(first_element)
  540. {
  541. ostr << "?";
  542. first_element = false;
  543. }
  544. else
  545. {
  546. ostr << "&";
  547. }
  548. ostr << escapeQueryVariable(iter->first);
  549. if(iter->second.isDefined())
  550. {
  551. ostr << "=" <<  escapeQueryValue(iter->second.asString());
  552. }
  553. }
  554. query_string = ostr.str();
  555. }
  556. return query_string;
  557. }
  558. bool operator!=(const LLURI& first, const LLURI& second)
  559. {
  560. return (first.asString() != second.asString());
  561. }