PageRenderTime 43ms CodeModel.GetById 24ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llcommandhandler.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 237 lines | 158 code | 26 blank | 53 comment | 16 complexity | a458b6fb948dc1c1931ffae07b5908e4 MD5 | raw file
  1/**
  2 * @file llcommandhandler.cpp
  3 * @brief Central registry for text-driven "commands", most of
  4 * which manipulate user interface.  For example, the command
  5 * "agent (uuid) about" will open the UI for an avatar's profile.
  6 *
  7 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28#include "llviewerprecompiledheaders.h"
 29
 30#include "llcommandhandler.h"
 31#include "llnotificationsutil.h"
 32#include "llcommanddispatcherlistener.h"
 33#include "stringize.h"
 34
 35// system includes
 36#include <boost/tokenizer.hpp>
 37
 38#define THROTTLE_PERIOD    5    // required seconds between throttled commands
 39
 40static LLCommandDispatcherListener sCommandDispatcherListener;
 41
 42//---------------------------------------------------------------------------
 43// Underlying registry for command handlers, not directly accessible.
 44//---------------------------------------------------------------------------
 45struct LLCommandHandlerInfo
 46{
 47	LLCommandHandler::EUntrustedAccess mUntrustedBrowserAccess;
 48	LLCommandHandler* mHandler;	// safe, all of these are static objects
 49};
 50
 51class LLCommandHandlerRegistry
 52{
 53public:
 54	static LLCommandHandlerRegistry& instance();
 55	void add(const char* cmd,
 56			 LLCommandHandler::EUntrustedAccess untrusted_access,
 57			 LLCommandHandler* handler);
 58	bool dispatch(const std::string& cmd,
 59				  const LLSD& params,
 60				  const LLSD& query_map,
 61				  LLMediaCtrl* web,
 62				  const std::string& nav_type,
 63				  bool trusted_browser);
 64
 65private:
 66	friend LLSD LLCommandDispatcher::enumerate();
 67	std::map<std::string, LLCommandHandlerInfo> mMap;
 68};
 69
 70// static 
 71LLCommandHandlerRegistry& LLCommandHandlerRegistry::instance()
 72{
 73	// Force this to be initialized on first call, because we're going
 74	// to be adding items to the std::map before main() and we can't
 75	// rely on a global being initialized in the right order.
 76	static LLCommandHandlerRegistry instance;
 77	return instance;
 78}
 79
 80void LLCommandHandlerRegistry::add(const char* cmd,
 81								   LLCommandHandler::EUntrustedAccess untrusted_access,
 82								   LLCommandHandler* handler)
 83{
 84	LLCommandHandlerInfo info;
 85	info.mUntrustedBrowserAccess = untrusted_access;
 86	info.mHandler = handler;
 87
 88	mMap[cmd] = info;
 89}
 90
 91bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
 92										const LLSD& params,
 93										const LLSD& query_map,
 94										LLMediaCtrl* web,
 95										const std::string& nav_type,
 96										bool trusted_browser)
 97{
 98	static bool slurl_blocked = false;
 99	static bool slurl_throttled = false;
100	static F64 last_throttle_time = 0.0;
101	F64 cur_time = 0.0;
102	std::map<std::string, LLCommandHandlerInfo>::iterator it = mMap.find(cmd);
103	if (it == mMap.end()) return false;
104	const LLCommandHandlerInfo& info = it->second;
105	if (!trusted_browser)
106	{
107		switch (info.mUntrustedBrowserAccess)
108		{
109		case LLCommandHandler::UNTRUSTED_ALLOW:
110			// fall through and let the command be handled
111			break;
112
113		case LLCommandHandler::UNTRUSTED_BLOCK:
114			// block request from external browser, but report as
115			// "handled" because it was well formatted.
116			LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
117			if (! slurl_blocked)
118			{
119				LLNotificationsUtil::add("BlockedSLURL");
120				slurl_blocked = true;
121			}
122			return true;
123
124		case LLCommandHandler::UNTRUSTED_THROTTLE:
125			// if users actually click on a link, we don't need to throttle it
126			// (throttling mechanism is used to prevent an avalanche of clicks via
127			// javascript
128			if ( nav_type == "clicked" )
129			{
130				break;
131			}
132
133			cur_time = LLTimer::getElapsedSeconds();
134			if (cur_time < last_throttle_time + THROTTLE_PERIOD)
135			{
136				// block request from external browser if it happened
137				// within THROTTLE_PERIOD seconds of the last command
138				LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
139				if (! slurl_throttled)
140				{
141					LLNotificationsUtil::add("ThrottledSLURL");
142					slurl_throttled = true;
143				}
144				return true;
145			}
146			last_throttle_time = cur_time;
147			break;
148		}
149	}
150	if (!info.mHandler) return false;
151	return info.mHandler->handle(params, query_map, web);
152}
153
154//---------------------------------------------------------------------------
155// Automatic registration of commands, runs before main()
156//---------------------------------------------------------------------------
157
158LLCommandHandler::LLCommandHandler(const char* cmd,
159								   EUntrustedAccess untrusted_access)
160{
161	LLCommandHandlerRegistry::instance().add(cmd, untrusted_access, this);
162}
163
164LLCommandHandler::~LLCommandHandler()
165{
166	// Don't care about unregistering these, all the handlers
167	// should be static objects.
168}
169
170//---------------------------------------------------------------------------
171// Public interface
172//---------------------------------------------------------------------------
173
174// static
175bool LLCommandDispatcher::dispatch(const std::string& cmd,
176								   const LLSD& params,
177								   const LLSD& query_map,
178								   LLMediaCtrl* web,
179								   const std::string& nav_type,
180								   bool trusted_browser)
181{
182	return LLCommandHandlerRegistry::instance().dispatch(
183		cmd, params, query_map, web, nav_type, trusted_browser);
184}
185
186static std::string lookup(LLCommandHandler::EUntrustedAccess value);
187
188LLSD LLCommandDispatcher::enumerate()
189{
190	LLSD response;
191	LLCommandHandlerRegistry& registry(LLCommandHandlerRegistry::instance());
192	for (std::map<std::string, LLCommandHandlerInfo>::const_iterator chi(registry.mMap.begin()),
193																	 chend(registry.mMap.end());
194		 chi != chend; ++chi)
195	{
196		LLSD info;
197		info["untrusted"] = chi->second.mUntrustedBrowserAccess;
198		info["untrusted_str"] = lookup(chi->second.mUntrustedBrowserAccess);
199		response[chi->first] = info;
200	}
201	return response;
202}
203
204/*------------------------------ lookup stuff ------------------------------*/
205struct symbol_info
206{
207	const char* name;
208	LLCommandHandler::EUntrustedAccess value;
209};
210
211#define ent(SYMBOL)										\
212	{													\
213		#SYMBOL + 28, /* skip "LLCommandHandler::UNTRUSTED_" prefix */	\
214		SYMBOL											\
215	}
216
217symbol_info symbols[] =
218{
219	ent(LLCommandHandler::UNTRUSTED_ALLOW),		  // allow commands from untrusted browsers
220	ent(LLCommandHandler::UNTRUSTED_BLOCK),		  // ignore commands from untrusted browsers
221	ent(LLCommandHandler::UNTRUSTED_THROTTLE)	  // allow untrusted, but only a few per min.
222};
223
224#undef ent
225
226static std::string lookup(LLCommandHandler::EUntrustedAccess value)
227{
228	for (symbol_info *sii(symbols), *siend(symbols + (sizeof(symbols)/sizeof(symbols[0])));
229		 sii != siend; ++sii)
230	{
231		if (sii->value == value)
232		{
233			return sii->name;
234		}
235	}
236	return STRINGIZE("UNTRUSTED_" << value);
237}