llurldispatcher.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /**
  2. * @file llurldispatcher.cpp
  3. * @brief Central registry for all URL handlers
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewergpl$
  6. *
  7. * Copyright (c) 2007-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llurldispatcher.h"
  34. #include "llnotifications.h"
  35. #include "llregionhandle.h"
  36. #include "llsd.h"
  37. #include "lluri.h"
  38. #include "llagent.h" // For teleportViaLocation()
  39. #include "llcommandhandler.h"
  40. #include "llfloaterurldisplay.h"
  41. #include "llfloaterworldmap.h"
  42. #include "llgridmanager.h"
  43. #include "llpanellogin.h"
  44. #include "llslurl.h"
  45. #include "llstartup.h"
  46. #include "hbviewerautomation.h"
  47. #include "llweb.h"
  48. #include "llworldmap.h"
  49. //-----------------------------------------------------------------------------
  50. // LLURLDispatcherImpl class
  51. //-----------------------------------------------------------------------------
  52. class LLURLDispatcherImpl
  53. {
  54. friend class LLTeleportHandler;
  55. protected:
  56. LOG_CLASS(LLURLDispatcherImpl);
  57. public:
  58. // Returns true if handled or explicitly blocked.
  59. static bool dispatch(const LLSLURL& slurl, const std::string& nav_type,
  60. LLMediaCtrl* webp, bool trusted);
  61. static bool dispatchRightClick(const LLSLURL& url);
  62. private:
  63. // Handles both left and right click
  64. static bool dispatchCore(const LLSLURL& slurl, const std::string& nav_type,
  65. bool right_mouse, LLMediaCtrl* webp,
  66. bool trusted);
  67. // Handles secondlife:///app/agent/<agent_id>/about and similar by showing
  68. // panel in Search floater. Returns true if handled or explicitly blocked.
  69. static bool dispatchApp(const LLSLURL& slurl, const std::string& nav_type,
  70. bool right_mouse, LLMediaCtrl* webp, bool trusted);
  71. // Handles secondlife://Ahern/123/45/67/. Returns true if handled.
  72. static bool dispatchRegion(const LLSLURL& slurl,
  73. const std::string& nav_type, bool right_mouse);
  74. // Called by LLWorldMap when a location has been resolved to a region name
  75. static void regionHandleCallback(U64 handle, const std::string& url,
  76. const LLUUID& snapshot_id, bool teleport);
  77. // Called by LLWorldMap when a region name has been resolved to a location
  78. // in-world, used by places-panel display.
  79. static void regionNameCallback(U64 handle, const std::string& url,
  80. const LLUUID& snapshot_id, bool teleport);
  81. };
  82. //static
  83. bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
  84. const std::string& nav_type,
  85. bool right_mouse, LLMediaCtrl* webp,
  86. bool trusted)
  87. {
  88. if (gAutomationp &&
  89. !gAutomationp->onSLURLDispatch(slurl.getSLURLString(), nav_type,
  90. trusted))
  91. {
  92. return false;
  93. }
  94. LLSLURL::eType type = slurl.getType();
  95. if (type == LLSLURL::APP)
  96. {
  97. return dispatchApp(slurl, nav_type, right_mouse, webp, trusted);
  98. }
  99. if (type == LLSLURL::LOCATION)
  100. {
  101. return dispatchRegion(slurl, nav_type, right_mouse);
  102. }
  103. return false;
  104. }
  105. //static
  106. bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl,
  107. const std::string& nav_type,
  108. LLMediaCtrl* webp, bool trusted)
  109. {
  110. llinfos << "SLURL: " << slurl.getSLURLString() << llendl;
  111. return dispatchCore(slurl, nav_type, false, webp, trusted);
  112. }
  113. //static
  114. bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl)
  115. {
  116. llinfos << "SLURL: " << slurl.getSLURLString() << llendl;
  117. return dispatchCore(slurl, "clicked", true, NULL, false);
  118. }
  119. //static
  120. bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
  121. const std::string& nav_type,
  122. bool right_mouse, LLMediaCtrl* webp,
  123. bool trusted)
  124. {
  125. llinfos << "Command: " << slurl.getAppCmd() << " - Path: "
  126. << slurl.getAppPath() << " - Query: " << slurl.getAppQuery()
  127. << llendl;
  128. const LLSD& query_map = LLURI::queryMap(slurl.getAppQuery());
  129. bool handled = LLCommandHandler::dispatch(slurl.getAppCmd(),
  130. slurl.getAppPath(),
  131. query_map, webp, nav_type,
  132. trusted);
  133. // Alert if we did not handle this secondlife:///app/... SLURL
  134. if (!handled)
  135. {
  136. std::string url = slurl.getSLURLString();
  137. size_t len = url.length();
  138. if (len > 5) // This cannot be a valid SLURL below this size. HB
  139. {
  140. const char& last_char = url.back();
  141. static const std::string seps = ".,;:()[]{}\"'`%\\/-+*=|#~&@!?\t";
  142. if (seps.find(last_char) != std::string::npos)
  143. {
  144. // Try again, with one less character in the slurl... But be
  145. // careful that the newly obtained SLURL is not the same as the
  146. // old one, to avoid an infinite recursion (could happen with,
  147. // for example: "secondlife:///app/"). HB
  148. url.pop_back();
  149. LLSLURL new_slurl(url);
  150. if (new_slurl.getSLURLString().size() < len)
  151. {
  152. return dispatchApp(new_slurl, nav_type, right_mouse, webp,
  153. trusted);
  154. }
  155. }
  156. }
  157. gNotifications.add("UnsupportedCommandSLURL");
  158. }
  159. return handled;
  160. }
  161. //static
  162. bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl,
  163. const std::string& nav_type,
  164. bool right_mouse)
  165. {
  166. if (slurl.getType() != LLSLURL::LOCATION)
  167. {
  168. return false;
  169. }
  170. // Before we are logged in, need to update the startup screen to tell the
  171. // user where they are going.
  172. if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
  173. {
  174. LLStartUp::setStartSLURL(slurl);
  175. LLPanelLogin::refreshLocation();
  176. return true;
  177. }
  178. std::string region_name = slurl.getRegion();
  179. LLFloaterURLDisplay* floaterp = LLFloaterURLDisplay::getInstance(LLSD());
  180. floaterp->setName(region_name);
  181. // Request a region handle by name (false = do not TP).
  182. gWorldMap.sendNamedRegionRequest(region_name, regionNameCallback,
  183. slurl.getSLURLString(), false);
  184. return true;
  185. }
  186. //static
  187. void LLURLDispatcherImpl::regionNameCallback(U64 region_handle,
  188. const std::string& url,
  189. const LLUUID& snapshot_id,
  190. bool teleport)
  191. {
  192. LLSLURL slurl(url);
  193. if (slurl.getType() == LLSLURL::LOCATION)
  194. {
  195. std::string region_name = slurl.getRegion();
  196. LLVector3 local_pos = slurl.getPosition();
  197. // Determine whether the point is in this region
  198. S32 max_x = REGION_WIDTH_UNITS;
  199. S32 max_y = REGION_WIDTH_UNITS;
  200. // Variable region size support
  201. LLSimInfo* sim = gWorldMap.simInfoFromName(region_name);
  202. if (sim)
  203. {
  204. max_x = (S32)sim->getSizeX();
  205. max_y = (S32)sim->getSizeY();
  206. }
  207. if (local_pos.mV[VX] >= 0 && local_pos.mV[VX] < max_x &&
  208. local_pos.mV[VY] >= 0 && local_pos.mV[VY] < max_y)
  209. {
  210. // If point in region, we are done
  211. regionHandleCallback(region_handle, url, snapshot_id, teleport);
  212. }
  213. else // Otherwise find the new region from the location
  214. {
  215. // Add the position to get the new region
  216. LLVector3d global_pos = from_region_handle(region_handle) +
  217. LLVector3d(local_pos);
  218. U64 new_region_handle = to_region_handle(global_pos);
  219. gWorldMap.sendHandleRegionRequest(new_region_handle,
  220. LLURLDispatcherImpl::regionHandleCallback,
  221. url, teleport);
  222. }
  223. }
  224. }
  225. //static
  226. void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle,
  227. const std::string& url,
  228. const LLUUID& snapshot_id,
  229. bool teleport)
  230. {
  231. LL_DEBUGS("Teleport") << "Region handle = " << region_handle
  232. << " - Teleport URI: " << url << LL_ENDL;
  233. LLSLURL slurl(url);
  234. LLGridManager* gm = LLGridManager::getInstance();
  235. // We cannot teleport cross grid at this point
  236. if (gm->getGridHost(slurl.getGrid()) != gm->getGridHost())
  237. {
  238. LLSD args;
  239. args["SLURL"] = slurl.getLocationString();
  240. args["CURRENT_GRID"] = gm->getGridHost();
  241. std::string grid_label = gm->getGridHost(slurl.getGrid());
  242. if (!grid_label.empty())
  243. {
  244. args["GRID"] = grid_label;
  245. }
  246. else
  247. {
  248. args["GRID"] = slurl.getGrid();
  249. }
  250. gNotifications.add("CantTeleportToGrid", args);
  251. return;
  252. }
  253. LLVector3 local_pos = slurl.getPosition();
  254. if (teleport)
  255. {
  256. LLVector3d global_pos = from_region_handle(region_handle);
  257. global_pos += LLVector3d(local_pos);
  258. gAgent.teleportViaLocation(global_pos);
  259. if (gFloaterWorldMapp)
  260. {
  261. gFloaterWorldMapp->trackLocation(global_pos);
  262. }
  263. return;
  264. }
  265. // Display informational floater, allow user to click teleport button
  266. LLFloaterURLDisplay* floaterp = LLFloaterURLDisplay::getInstance(LLSD());
  267. floaterp->displayParcelInfo(region_handle, local_pos);
  268. if (snapshot_id.notNull())
  269. {
  270. floaterp->setSnapshotDisplay(snapshot_id);
  271. }
  272. std::string loc = llformat("%s %d, %d, %d", slurl.getRegion().c_str(),
  273. (S32)local_pos.mV[VX], (S32)local_pos.mV[VY],
  274. (S32)local_pos.mV[VZ]);
  275. floaterp->setLocationString(loc);
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Command handler
  279. // Teleportation links are handled here because they are tightly coupled to URL
  280. // parsing and sim-fragment parsing
  281. //-----------------------------------------------------------------------------
  282. class LLTeleportHandler final : public LLCommandHandler
  283. {
  284. protected:
  285. LOG_CLASS(LLTeleportHandler);
  286. public:
  287. // Teleport requests *must* come from a trusted browser inside the app,
  288. // otherwise a malicious web page could cause a constant teleport loop. JC
  289. LLTeleportHandler()
  290. : LLCommandHandler("teleport", UNTRUSTED_CLICK_ONLY)
  291. {
  292. }
  293. bool handle(const LLSD& tokens, const LLSD&, LLMediaCtrl*) override
  294. {
  295. // Construct a "normal" SLURL, resolve the region to a global position,
  296. // and teleport to it
  297. size_t ts = tokens.size();
  298. if (ts < 1) return false;
  299. LLVector3 coords(128.f, 128.f, 0.f);
  300. if (ts >= 2)
  301. {
  302. coords.mV[VX] = tokens[1].asReal();
  303. }
  304. if (ts >= 3)
  305. {
  306. coords.mV[VY] = tokens[2].asReal();
  307. }
  308. if (ts >= 4)
  309. {
  310. coords.mV[VZ] = tokens[3].asReal();
  311. }
  312. // Region names may be %20 escaped.
  313. std::string region_name = LLURI::unescape(tokens[0]);
  314. // Build secondlife://De%20Haro/123/45/67 for use in callback
  315. std::string url = LLSLURL(region_name, coords).getSLURLString();
  316. LL_DEBUGS("Teleport") << "Region name: " << region_name
  317. << " - Coordinates: " << coords
  318. << " - Teleport URI: " << url << LL_ENDL;
  319. gWorldMap.sendNamedRegionRequest(region_name,
  320. LLURLDispatcherImpl::regionHandleCallback,
  321. url, true); // true = teleport
  322. return true;
  323. }
  324. };
  325. LLTeleportHandler gTeleportHandler;
  326. //-----------------------------------------------------------------------------
  327. // LLURLDispatcher class proper
  328. //-----------------------------------------------------------------------------
  329. //static
  330. bool LLURLDispatcher::dispatch(const std::string& url,
  331. const std::string& nav_type,
  332. LLMediaCtrl* webp, bool trusted)
  333. {
  334. return LLURLDispatcherImpl::dispatch(LLSLURL(url), nav_type, webp,
  335. trusted);
  336. }
  337. //static
  338. bool LLURLDispatcher::dispatchRightClick(const std::string& url)
  339. {
  340. return LLURLDispatcherImpl::dispatchRightClick(url);
  341. }
  342. //static
  343. bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url)
  344. {
  345. LLSLURL slurl(url);
  346. // Check to see if it is actually an SLURL... HB
  347. bool dispatched = slurl.isValid();
  348. if (dispatched)
  349. {
  350. // If yes, try and dispatch it, which may fail, but we do not care
  351. // about dispatch() returned boolean and still return 'dispatched' as
  352. // 'true' to the LLTextEditor caller, so that the latter would not try
  353. // and launch a web browser to process an SLURL (even if unknown to the
  354. // viewer) like it would be an HTML link ! HB
  355. // Note: text editors are considered sources of trusted URLs in order
  356. // to make object IM and avatar profile links in chat history work.
  357. // While a malicious resident could chat an app SLURL, the receiving
  358. // resident will see it and must affirmatively click on it.
  359. // *TODO: Make this trust model more refined. JC
  360. LLURLDispatcherImpl::dispatch(slurl, "clicked", NULL, true);
  361. }
  362. return dispatched;
  363. }