123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- /**
- * @file llurldispatcher.cpp
- * @brief Central registry for all URL handlers
- *
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llurldispatcher.h"
- #include "llnotifications.h"
- #include "llregionhandle.h"
- #include "llsd.h"
- #include "lluri.h"
- #include "llagent.h" // For teleportViaLocation()
- #include "llcommandhandler.h"
- #include "llfloaterurldisplay.h"
- #include "llfloaterworldmap.h"
- #include "llgridmanager.h"
- #include "llpanellogin.h"
- #include "llslurl.h"
- #include "llstartup.h"
- #include "hbviewerautomation.h"
- #include "llweb.h"
- #include "llworldmap.h"
- //-----------------------------------------------------------------------------
- // LLURLDispatcherImpl class
- //-----------------------------------------------------------------------------
- class LLURLDispatcherImpl
- {
- friend class LLTeleportHandler;
- protected:
- LOG_CLASS(LLURLDispatcherImpl);
- public:
- // Returns true if handled or explicitly blocked.
- static bool dispatch(const LLSLURL& slurl, const std::string& nav_type,
- LLMediaCtrl* webp, bool trusted);
- static bool dispatchRightClick(const LLSLURL& url);
- private:
- // Handles both left and right click
- static bool dispatchCore(const LLSLURL& slurl, const std::string& nav_type,
- bool right_mouse, LLMediaCtrl* webp,
- bool trusted);
- // Handles secondlife:///app/agent/<agent_id>/about and similar by showing
- // panel in Search floater. Returns true if handled or explicitly blocked.
- static bool dispatchApp(const LLSLURL& slurl, const std::string& nav_type,
- bool right_mouse, LLMediaCtrl* webp, bool trusted);
- // Handles secondlife://Ahern/123/45/67/. Returns true if handled.
- static bool dispatchRegion(const LLSLURL& slurl,
- const std::string& nav_type, bool right_mouse);
- // Called by LLWorldMap when a location has been resolved to a region name
- static void regionHandleCallback(U64 handle, const std::string& url,
- const LLUUID& snapshot_id, bool teleport);
- // Called by LLWorldMap when a region name has been resolved to a location
- // in-world, used by places-panel display.
- static void regionNameCallback(U64 handle, const std::string& url,
- const LLUUID& snapshot_id, bool teleport);
- };
- //static
- bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
- const std::string& nav_type,
- bool right_mouse, LLMediaCtrl* webp,
- bool trusted)
- {
- if (gAutomationp &&
- !gAutomationp->onSLURLDispatch(slurl.getSLURLString(), nav_type,
- trusted))
- {
- return false;
- }
- LLSLURL::eType type = slurl.getType();
- if (type == LLSLURL::APP)
- {
- return dispatchApp(slurl, nav_type, right_mouse, webp, trusted);
- }
- if (type == LLSLURL::LOCATION)
- {
- return dispatchRegion(slurl, nav_type, right_mouse);
- }
- return false;
- }
- //static
- bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl,
- const std::string& nav_type,
- LLMediaCtrl* webp, bool trusted)
- {
- llinfos << "SLURL: " << slurl.getSLURLString() << llendl;
- return dispatchCore(slurl, nav_type, false, webp, trusted);
- }
- //static
- bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl)
- {
- llinfos << "SLURL: " << slurl.getSLURLString() << llendl;
- return dispatchCore(slurl, "clicked", true, NULL, false);
- }
- //static
- bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
- const std::string& nav_type,
- bool right_mouse, LLMediaCtrl* webp,
- bool trusted)
- {
- llinfos << "Command: " << slurl.getAppCmd() << " - Path: "
- << slurl.getAppPath() << " - Query: " << slurl.getAppQuery()
- << llendl;
- const LLSD& query_map = LLURI::queryMap(slurl.getAppQuery());
- bool handled = LLCommandHandler::dispatch(slurl.getAppCmd(),
- slurl.getAppPath(),
- query_map, webp, nav_type,
- trusted);
- // Alert if we did not handle this secondlife:///app/... SLURL
- if (!handled)
- {
- std::string url = slurl.getSLURLString();
- size_t len = url.length();
- if (len > 5) // This cannot be a valid SLURL below this size. HB
- {
- const char& last_char = url.back();
- static const std::string seps = ".,;:()[]{}\"'`%\\/-+*=|#~&@!?\t";
- if (seps.find(last_char) != std::string::npos)
- {
- // Try again, with one less character in the slurl... But be
- // careful that the newly obtained SLURL is not the same as the
- // old one, to avoid an infinite recursion (could happen with,
- // for example: "secondlife:///app/"). HB
- url.pop_back();
- LLSLURL new_slurl(url);
- if (new_slurl.getSLURLString().size() < len)
- {
- return dispatchApp(new_slurl, nav_type, right_mouse, webp,
- trusted);
- }
- }
- }
- gNotifications.add("UnsupportedCommandSLURL");
- }
- return handled;
- }
- //static
- bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl,
- const std::string& nav_type,
- bool right_mouse)
- {
- if (slurl.getType() != LLSLURL::LOCATION)
- {
- return false;
- }
- // Before we are logged in, need to update the startup screen to tell the
- // user where they are going.
- if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
- {
- LLStartUp::setStartSLURL(slurl);
- LLPanelLogin::refreshLocation();
- return true;
- }
- std::string region_name = slurl.getRegion();
- LLFloaterURLDisplay* floaterp = LLFloaterURLDisplay::getInstance(LLSD());
- floaterp->setName(region_name);
- // Request a region handle by name (false = do not TP).
- gWorldMap.sendNamedRegionRequest(region_name, regionNameCallback,
- slurl.getSLURLString(), false);
- return true;
- }
- //static
- void LLURLDispatcherImpl::regionNameCallback(U64 region_handle,
- const std::string& url,
- const LLUUID& snapshot_id,
- bool teleport)
- {
- LLSLURL slurl(url);
- if (slurl.getType() == LLSLURL::LOCATION)
- {
- std::string region_name = slurl.getRegion();
- LLVector3 local_pos = slurl.getPosition();
- // Determine whether the point is in this region
- S32 max_x = REGION_WIDTH_UNITS;
- S32 max_y = REGION_WIDTH_UNITS;
- // Variable region size support
- LLSimInfo* sim = gWorldMap.simInfoFromName(region_name);
- if (sim)
- {
- max_x = (S32)sim->getSizeX();
- max_y = (S32)sim->getSizeY();
- }
- if (local_pos.mV[VX] >= 0 && local_pos.mV[VX] < max_x &&
- local_pos.mV[VY] >= 0 && local_pos.mV[VY] < max_y)
- {
- // If point in region, we are done
- regionHandleCallback(region_handle, url, snapshot_id, teleport);
- }
- else // Otherwise find the new region from the location
- {
- // Add the position to get the new region
- LLVector3d global_pos = from_region_handle(region_handle) +
- LLVector3d(local_pos);
- U64 new_region_handle = to_region_handle(global_pos);
- gWorldMap.sendHandleRegionRequest(new_region_handle,
- LLURLDispatcherImpl::regionHandleCallback,
- url, teleport);
- }
- }
- }
- //static
- void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle,
- const std::string& url,
- const LLUUID& snapshot_id,
- bool teleport)
- {
- LL_DEBUGS("Teleport") << "Region handle = " << region_handle
- << " - Teleport URI: " << url << LL_ENDL;
- LLSLURL slurl(url);
- LLGridManager* gm = LLGridManager::getInstance();
- // We cannot teleport cross grid at this point
- if (gm->getGridHost(slurl.getGrid()) != gm->getGridHost())
- {
- LLSD args;
- args["SLURL"] = slurl.getLocationString();
- args["CURRENT_GRID"] = gm->getGridHost();
- std::string grid_label = gm->getGridHost(slurl.getGrid());
- if (!grid_label.empty())
- {
- args["GRID"] = grid_label;
- }
- else
- {
- args["GRID"] = slurl.getGrid();
- }
- gNotifications.add("CantTeleportToGrid", args);
- return;
- }
- LLVector3 local_pos = slurl.getPosition();
- if (teleport)
- {
- LLVector3d global_pos = from_region_handle(region_handle);
- global_pos += LLVector3d(local_pos);
- gAgent.teleportViaLocation(global_pos);
- if (gFloaterWorldMapp)
- {
- gFloaterWorldMapp->trackLocation(global_pos);
- }
- return;
- }
- // Display informational floater, allow user to click teleport button
- LLFloaterURLDisplay* floaterp = LLFloaterURLDisplay::getInstance(LLSD());
- floaterp->displayParcelInfo(region_handle, local_pos);
- if (snapshot_id.notNull())
- {
- floaterp->setSnapshotDisplay(snapshot_id);
- }
- std::string loc = llformat("%s %d, %d, %d", slurl.getRegion().c_str(),
- (S32)local_pos.mV[VX], (S32)local_pos.mV[VY],
- (S32)local_pos.mV[VZ]);
- floaterp->setLocationString(loc);
- }
- //-----------------------------------------------------------------------------
- // Command handler
- // Teleportation links are handled here because they are tightly coupled to URL
- // parsing and sim-fragment parsing
- //-----------------------------------------------------------------------------
- class LLTeleportHandler final : public LLCommandHandler
- {
- protected:
- LOG_CLASS(LLTeleportHandler);
- public:
- // Teleport requests *must* come from a trusted browser inside the app,
- // otherwise a malicious web page could cause a constant teleport loop. JC
- LLTeleportHandler()
- : LLCommandHandler("teleport", UNTRUSTED_CLICK_ONLY)
- {
- }
- bool handle(const LLSD& tokens, const LLSD&, LLMediaCtrl*) override
- {
- // Construct a "normal" SLURL, resolve the region to a global position,
- // and teleport to it
- size_t ts = tokens.size();
- if (ts < 1) return false;
- LLVector3 coords(128.f, 128.f, 0.f);
- if (ts >= 2)
- {
- coords.mV[VX] = tokens[1].asReal();
- }
- if (ts >= 3)
- {
- coords.mV[VY] = tokens[2].asReal();
- }
- if (ts >= 4)
- {
- coords.mV[VZ] = tokens[3].asReal();
- }
- // Region names may be %20 escaped.
- std::string region_name = LLURI::unescape(tokens[0]);
- // Build secondlife://De%20Haro/123/45/67 for use in callback
- std::string url = LLSLURL(region_name, coords).getSLURLString();
- LL_DEBUGS("Teleport") << "Region name: " << region_name
- << " - Coordinates: " << coords
- << " - Teleport URI: " << url << LL_ENDL;
- gWorldMap.sendNamedRegionRequest(region_name,
- LLURLDispatcherImpl::regionHandleCallback,
- url, true); // true = teleport
- return true;
- }
- };
- LLTeleportHandler gTeleportHandler;
- //-----------------------------------------------------------------------------
- // LLURLDispatcher class proper
- //-----------------------------------------------------------------------------
- //static
- bool LLURLDispatcher::dispatch(const std::string& url,
- const std::string& nav_type,
- LLMediaCtrl* webp, bool trusted)
- {
- return LLURLDispatcherImpl::dispatch(LLSLURL(url), nav_type, webp,
- trusted);
- }
- //static
- bool LLURLDispatcher::dispatchRightClick(const std::string& url)
- {
- return LLURLDispatcherImpl::dispatchRightClick(url);
- }
- //static
- bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url)
- {
- LLSLURL slurl(url);
- // Check to see if it is actually an SLURL... HB
- bool dispatched = slurl.isValid();
- if (dispatched)
- {
- // If yes, try and dispatch it, which may fail, but we do not care
- // about dispatch() returned boolean and still return 'dispatched' as
- // 'true' to the LLTextEditor caller, so that the latter would not try
- // and launch a web browser to process an SLURL (even if unknown to the
- // viewer) like it would be an HTML link ! HB
- // Note: text editors are considered sources of trusted URLs in order
- // to make object IM and avatar profile links in chat history work.
- // While a malicious resident could chat an app SLURL, the receiving
- // resident will see it and must affirmatively click on it.
- // *TODO: Make this trust model more refined. JC
- LLURLDispatcherImpl::dispatch(slurl, "clicked", NULL, true);
- }
- return dispatched;
- }
|