PageRenderTime 44ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llslurl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 482 lines | 326 code | 44 blank | 112 comment | 70 complexity | 7dd233c8a0cccd559b0165a9971d82c0 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llurlsimstring.cpp (was llsimurlstring.cpp)
  3. * @brief Handles "SLURL fragments" like Ahern/123/45 for
  4. * startup processing, login screen, prefs, etc.
  5. *
  6. * $LicenseInfo:firstyear=2010&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #include "llviewerprecompiledheaders.h"
  28. #include "llslurl.h"
  29. #include "llpanellogin.h"
  30. #include "llviewercontrol.h"
  31. #include "llviewernetwork.h"
  32. #include "llfiltersd2xmlrpc.h"
  33. #include "curl/curl.h"
  34. const char* LLSLURL::SLURL_HTTP_SCHEME = "http";
  35. const char* LLSLURL::SLURL_HTTPS_SCHEME = "https";
  36. const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
  37. const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife";
  38. const char* LLSLURL::SLURL_COM = "slurl.com";
  39. // For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag
  40. // text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
  41. // version is required also.
  42. const char* LLSLURL::WWW_SLURL_COM = "www.slurl.com";
  43. const char* LLSLURL::MAPS_SECONDLIFE_COM = "maps.secondlife.com";
  44. const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info";
  45. const char* LLSLURL::SLURL_APP_PATH = "app";
  46. const char* LLSLURL::SLURL_REGION_PATH = "region";
  47. const char* LLSLURL::SIM_LOCATION_HOME = "home";
  48. const char* LLSLURL::SIM_LOCATION_LAST = "last";
  49. // resolve a simstring from a slurl
  50. LLSLURL::LLSLURL(const std::string& slurl)
  51. {
  52. // by default we go to agni.
  53. mType = INVALID;
  54. LL_INFOS("AppInit") << "SLURL: " << slurl << LL_ENDL;
  55. if(slurl == SIM_LOCATION_HOME)
  56. {
  57. mType = HOME_LOCATION;
  58. }
  59. else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
  60. {
  61. mType = LAST_LOCATION;
  62. }
  63. else
  64. {
  65. LLURI slurl_uri;
  66. // parse the slurl as a uri
  67. if(slurl.find(':') == std::string::npos)
  68. {
  69. // There may be no scheme ('secondlife:' etc.) passed in. In that case
  70. // we want to normalize the slurl by putting the appropriate scheme
  71. // in front of the slurl. So, we grab the appropriate slurl base
  72. // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or
  73. // https://<hostname>/region/ for Standalone grid (the word region, not the region name)
  74. // these slurls are typically passed in from the 'starting location' box on the login panel,
  75. // where the user can type in <regionname>/<x>/<y>/<z>
  76. std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase();
  77. // the slurl that was passed in might have a prepended /, or not. So,
  78. // we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z>
  79. // or some such.
  80. if(slurl[0] == '/')
  81. {
  82. fixed_slurl += slurl.substr(1);
  83. }
  84. else
  85. {
  86. fixed_slurl += slurl;
  87. }
  88. // We then load the slurl into a LLURI form
  89. slurl_uri = LLURI(fixed_slurl);
  90. }
  91. else
  92. {
  93. // as we did have a scheme, implying a URI style slurl, we
  94. // simply parse it as a URI
  95. slurl_uri = LLURI(slurl);
  96. }
  97. LLSD path_array = slurl_uri.pathArray();
  98. // determine whether it's a maingrid URI or an Standalone/open style URI
  99. // by looking at the scheme. If it's a 'secondlife:' slurl scheme or
  100. // 'sl:' scheme, we know it's maingrid
  101. // At the end of this if/else block, we'll have determined the grid,
  102. // and the slurl type (APP or LOCATION)
  103. if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
  104. {
  105. // parse a maingrid style slurl. We know the grid is maingrid
  106. // so grab it.
  107. // A location slurl for maingrid (with the special schemes) can be in the form
  108. // secondlife://<regionname>/<x>/<y>/<z>
  109. // or
  110. // secondlife://<Grid>/secondlife/<region>/<x>/<y>/<z>
  111. // where if grid is empty, it specifies Agni
  112. // An app style slurl for maingrid can be
  113. // secondlife://<Grid>/app/<app parameters>
  114. // where an empty grid implies Agni
  115. // we'll start by checking the top of the 'path' which will be
  116. // either 'app', 'secondlife', or <x>.
  117. // default to maingrid
  118. mGrid = MAINGRID;
  119. if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) ||
  120. (path_array[0].asString() == LLSLURL::SLURL_APP_PATH))
  121. {
  122. // it's in the form secondlife://<grid>/(app|secondlife)
  123. // so parse the grid name to derive the grid ID
  124. if (!slurl_uri.hostName().empty())
  125. {
  126. mGrid = LLGridManager::getInstance()->getGridByLabel(slurl_uri.hostName());
  127. }
  128. else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
  129. {
  130. // If the slurl is in the form secondlife:///secondlife/<region> form,
  131. // then we are in fact on maingrid.
  132. mGrid = MAINGRID;
  133. }
  134. else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
  135. {
  136. // for app style slurls, where no grid name is specified, assume the currently
  137. // selected or logged in grid.
  138. mGrid = LLGridManager::getInstance()->getGrid();
  139. }
  140. if(mGrid.empty())
  141. {
  142. // we couldn't find the grid in the grid manager, so bail
  143. return;
  144. }
  145. // set the type as appropriate.
  146. if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
  147. {
  148. mType = LOCATION;
  149. }
  150. else
  151. {
  152. mType = APP;
  153. }
  154. path_array.erase(0);
  155. }
  156. else
  157. {
  158. // it wasn't a /secondlife/<region> or /app/<params>, so it must be secondlife://<region>
  159. // therefore the hostname will be the region name, and it's a location type
  160. mType = LOCATION;
  161. // 'normalize' it so the region name is in fact the head of the path_array
  162. path_array.insert(0, slurl_uri.hostName());
  163. }
  164. }
  165. else if((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) ||
  166. (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) ||
  167. (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME))
  168. {
  169. // We're dealing with either a Standalone style slurl or slurl.com slurl
  170. if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) ||
  171. (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) ||
  172. (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM))
  173. {
  174. // slurl.com implies maingrid
  175. mGrid = MAINGRID;
  176. }
  177. else
  178. {
  179. // Don't try to match any old http://<host>/ URL as a SLurl.
  180. // SLE SLurls will have the grid hostname in the URL, so only
  181. // match http URLs if the hostname matches the grid hostname
  182. // (or its a slurl.com or maps.secondlife.com URL).
  183. if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME ||
  184. slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) &&
  185. slurl_uri.hostName() != LLGridManager::getInstance()->getGrid())
  186. {
  187. return;
  188. }
  189. // As it's a Standalone grid/open, we will always have a hostname, as Standalone/open style
  190. // urls are properly formed, unlike the stinky maingrid style
  191. mGrid = slurl_uri.hostName();
  192. }
  193. if (path_array.size() == 0)
  194. {
  195. // um, we need a path...
  196. return;
  197. }
  198. // we need to normalize the urls so
  199. // the path portion starts with the 'command' that we want to do
  200. // it can either be region or app.
  201. if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) ||
  202. (path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH))
  203. {
  204. // strip off 'region' or 'secondlife'
  205. path_array.erase(0);
  206. // it's a location
  207. mType = LOCATION;
  208. }
  209. else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
  210. {
  211. mType = APP;
  212. path_array.erase(0);
  213. // leave app appended.
  214. }
  215. else
  216. {
  217. // not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL
  218. return;
  219. }
  220. }
  221. else
  222. {
  223. // invalid scheme, so bail
  224. return;
  225. }
  226. if(path_array.size() == 0)
  227. {
  228. // we gotta have some stuff after the specifier as to whether it's a region or command
  229. return;
  230. }
  231. // now that we know whether it's an app slurl or a location slurl,
  232. // parse the slurl into the proper data structures.
  233. if(mType == APP)
  234. {
  235. // grab the app command type and strip it (could be a command to jump somewhere,
  236. // or whatever )
  237. mAppCmd = path_array[0].asString();
  238. path_array.erase(0);
  239. // Grab the parameters
  240. mAppPath = path_array;
  241. // and the query
  242. mAppQuery = slurl_uri.query();
  243. mAppQueryMap = slurl_uri.queryMap();
  244. return;
  245. }
  246. else if(mType == LOCATION)
  247. {
  248. // at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z
  249. // are collectively optional
  250. // are optional
  251. mRegion = LLURI::unescape(path_array[0].asString());
  252. path_array.erase(0);
  253. // parse the x, y, and optionally z
  254. if(path_array.size() >= 2)
  255. {
  256. mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
  257. if((F32(mPosition[VX]) < 0.f) ||
  258. (mPosition[VX] > REGION_WIDTH_METERS) ||
  259. (F32(mPosition[VY]) < 0.f) ||
  260. (mPosition[VY] > REGION_WIDTH_METERS) ||
  261. (F32(mPosition[VZ]) < 0.f) ||
  262. (mPosition[VZ] > REGION_HEIGHT_METERS))
  263. {
  264. mType = INVALID;
  265. return;
  266. }
  267. }
  268. else
  269. {
  270. // if x, y and z were not fully passed in, go to the middle of the region.
  271. // teleport will adjust the actual location to make sure you're on the ground
  272. // and such
  273. mPosition = LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0);
  274. }
  275. }
  276. }
  277. }
  278. // Create a slurl for the middle of the region
  279. LLSLURL::LLSLURL(const std::string& grid,
  280. const std::string& region)
  281. {
  282. mGrid = grid;
  283. mRegion = region;
  284. mType = LOCATION;
  285. mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0);
  286. }
  287. // create a slurl given the position. The position will be modded with the region
  288. // width handling global positions as well
  289. LLSLURL::LLSLURL(const std::string& grid,
  290. const std::string& region,
  291. const LLVector3& position)
  292. {
  293. mGrid = grid;
  294. mRegion = region;
  295. S32 x = llround( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) );
  296. S32 y = llround( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) );
  297. S32 z = llround( (F32)position[VZ] );
  298. mType = LOCATION;
  299. mPosition = LLVector3(x, y, z);
  300. }
  301. // create a simstring
  302. LLSLURL::LLSLURL(const std::string& region,
  303. const LLVector3& position)
  304. {
  305. *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
  306. region, position);
  307. }
  308. // create a slurl from a global position
  309. LLSLURL::LLSLURL(const std::string& grid,
  310. const std::string& region,
  311. const LLVector3d& global_position)
  312. {
  313. *this = LLSLURL(grid,
  314. region, LLVector3(global_position.mdV[VX],
  315. global_position.mdV[VY],
  316. global_position.mdV[VZ]));
  317. }
  318. // create a slurl from a global position
  319. LLSLURL::LLSLURL(const std::string& region,
  320. const LLVector3d& global_position)
  321. {
  322. *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
  323. region, global_position);
  324. }
  325. LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb)
  326. {
  327. mType = APP;
  328. mAppCmd = command;
  329. mAppPath = LLSD::emptyArray();
  330. mAppPath.append(LLSD(id));
  331. mAppPath.append(LLSD(verb));
  332. }
  333. std::string LLSLURL::getSLURLString() const
  334. {
  335. switch(mType)
  336. {
  337. case HOME_LOCATION:
  338. return SIM_LOCATION_HOME;
  339. case LAST_LOCATION:
  340. return SIM_LOCATION_LAST;
  341. case LOCATION:
  342. {
  343. // lookup the grid
  344. S32 x = llround( (F32)mPosition[VX] );
  345. S32 y = llround( (F32)mPosition[VY] );
  346. S32 z = llround( (F32)mPosition[VZ] );
  347. return LLGridManager::getInstance()->getSLURLBase(mGrid) +
  348. LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z);
  349. }
  350. case APP:
  351. {
  352. std::ostringstream app_url;
  353. app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd;
  354. for(LLSD::array_const_iterator i = mAppPath.beginArray();
  355. i != mAppPath.endArray();
  356. i++)
  357. {
  358. app_url << "/" << i->asString();
  359. }
  360. if(mAppQuery.length() > 0)
  361. {
  362. app_url << "?" << mAppQuery;
  363. }
  364. return app_url.str();
  365. }
  366. default:
  367. LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL;
  368. return std::string();
  369. }
  370. }
  371. std::string LLSLURL::getLoginString() const
  372. {
  373. std::stringstream unescaped_start;
  374. switch(mType)
  375. {
  376. case LOCATION:
  377. unescaped_start << "uri:"
  378. << mRegion << "&"
  379. << llround(mPosition[0]) << "&"
  380. << llround(mPosition[1]) << "&"
  381. << llround(mPosition[2]);
  382. break;
  383. case HOME_LOCATION:
  384. unescaped_start << "home";
  385. break;
  386. case LAST_LOCATION:
  387. unescaped_start << "last";
  388. break;
  389. default:
  390. LL_WARNS("AppInit") << "Unexpected SLURL type for login string" << (int)mType << LL_ENDL;
  391. break;
  392. }
  393. return xml_escape_string(unescaped_start.str());
  394. }
  395. bool LLSLURL::operator==(const LLSLURL& rhs)
  396. {
  397. if(rhs.mType != mType) return false;
  398. switch(mType)
  399. {
  400. case LOCATION:
  401. return ((mGrid == rhs.mGrid) &&
  402. (mRegion == rhs.mRegion) &&
  403. (mPosition == rhs.mPosition));
  404. case APP:
  405. return getSLURLString() == rhs.getSLURLString();
  406. case HOME_LOCATION:
  407. case LAST_LOCATION:
  408. return true;
  409. default:
  410. return false;
  411. }
  412. }
  413. bool LLSLURL::operator !=(const LLSLURL& rhs)
  414. {
  415. return !(*this == rhs);
  416. }
  417. std::string LLSLURL::getLocationString() const
  418. {
  419. return llformat("%s/%d/%d/%d",
  420. mRegion.c_str(),
  421. (int)llround(mPosition[0]),
  422. (int)llround(mPosition[1]),
  423. (int)llround(mPosition[2]));
  424. }
  425. std::string LLSLURL::asString() const
  426. {
  427. std::ostringstream result;
  428. result << " mAppCmd:" << getAppCmd() <<
  429. " mAppPath:" + getAppPath().asString() <<
  430. " mAppQueryMap:" + getAppQueryMap().asString() <<
  431. " mAppQuery: " + getAppQuery() <<
  432. " mGrid: " + getGrid() <<
  433. " mRegion: " + getRegion() <<
  434. " mPosition: " <<
  435. " mType: " << mType <<
  436. " mPosition: " << mPosition;
  437. return result.str();
  438. }