llcommandhandler.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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=viewergpl$
  8. *
  9. * Copyright (c) 2007-2009, 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 "llviewerprecompiledheaders.h"
  35. #include "llcommandhandler.h"
  36. #include "llnotifications.h"
  37. #include "llsdserialize.h"
  38. #include "llappviewer.h" // For gFrameTimeSeconds
  39. #include "llstartup.h"
  40. // Required seconds between throttled commands
  41. constexpr F32 THROTTLE_PERIOD = 5.f;
  42. class LLCommandHandlerRegistry final
  43. : public LLSingleton<LLCommandHandlerRegistry>
  44. {
  45. friend class LLSingleton<LLCommandHandlerRegistry>;
  46. protected:
  47. LOG_CLASS(LLCommandHandlerRegistry);
  48. public:
  49. LL_INLINE void add(const char* cmd,
  50. LLCommandHandler::EUntrustedAccess access,
  51. LLCommandHandler* handler)
  52. {
  53. mMap.emplace(cmd, LLCommandHandlerInfo(handler, access));
  54. }
  55. bool dispatch(const std::string& cmd, const LLSD& params,
  56. const LLSD& query_map, LLMediaCtrl* web,
  57. const std::string& nav_type, bool trusted_browser);
  58. void dump();
  59. private:
  60. void notifySlurlBlocked();
  61. void notifySlurlThrottled();
  62. private:
  63. // Underlying registry for command handlers, not directly accessible.
  64. struct LLCommandHandlerInfo
  65. {
  66. LL_INLINE LLCommandHandlerInfo(LLCommandHandler* handler,
  67. LLCommandHandler::EUntrustedAccess a)
  68. : mHandler(handler),
  69. mUntrustedBrowserAccess(a)
  70. {
  71. }
  72. // It is safe to hold a pointer since, all of these are global objects,
  73. // only destroyed at viewer program exit.
  74. LLCommandHandler* mHandler;
  75. LLCommandHandler::EUntrustedAccess mUntrustedBrowserAccess;
  76. };
  77. typedef std::map<std::string, LLCommandHandlerInfo> handlers_map_t;
  78. handlers_map_t mMap;
  79. };
  80. bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
  81. const LLSD& params,
  82. const LLSD& query_map,
  83. LLMediaCtrl* web,
  84. const std::string& nav_type,
  85. bool trusted_browser)
  86. {
  87. static F32 last_throttle_time = 0.f;
  88. handlers_map_t::iterator it = mMap.find(cmd);
  89. if (it == mMap.end()) return false;
  90. const LLCommandHandlerInfo& info = it->second;
  91. if (!trusted_browser)
  92. {
  93. switch (info.mUntrustedBrowserAccess)
  94. {
  95. case LLCommandHandler::UNTRUSTED_BLOCK:
  96. // Block request from external browser, but report as "handled"
  97. // because it was well formatted.
  98. llwarns << "Untrusted browser. Blocked SLURL command: " << cmd
  99. << llendl;
  100. notifySlurlBlocked();
  101. return true;
  102. case LLCommandHandler::UNTRUSTED_CLICK_ONLY:
  103. if (nav_type == "clicked" &&
  104. info.mHandler->canHandleUntrusted(params, query_map, web,
  105. nav_type))
  106. {
  107. break;
  108. }
  109. llwarns_once << "Blocked from untrusted browser SLURL click-only command: "
  110. << cmd << llendl;
  111. notifySlurlBlocked();
  112. return true;
  113. case LLCommandHandler::UNTRUSTED_THROTTLE:
  114. if (LLStartUp::getStartupState() < STATE_BROWSER_INIT)
  115. {
  116. return true;
  117. }
  118. if (!info.mHandler->canHandleUntrusted(params, query_map, web,
  119. nav_type))
  120. {
  121. llwarns << "Untrusted browser. Blocked SLURL command: "
  122. << cmd << llendl;
  123. notifySlurlBlocked();
  124. return true;
  125. }
  126. // If user actually clicked on a link, we do not need to
  127. // throttle it (the throttling mechanism is used to prevent an
  128. // avalanche of commands via javascript).
  129. if (nav_type == "clicked")
  130. {
  131. break;
  132. }
  133. if (gFrameTimeSeconds < last_throttle_time + THROTTLE_PERIOD)
  134. {
  135. llwarns_once << "Throttled SLURL command: " << cmd
  136. << llendl;
  137. notifySlurlThrottled();
  138. return true;
  139. }
  140. last_throttle_time = gFrameTimeSeconds;
  141. break;
  142. default: // Including LLCommandHandler::UNTRUSTED_ALLOW
  143. // Fall through and let the command be handled
  144. break;
  145. }
  146. }
  147. LL_DEBUGS("CommandHandler") << "Dispatching '" << cmd << "' with:";
  148. std::stringstream str1, str2;
  149. LLSDSerialize::toPrettyXML(params, str1);
  150. LLSDSerialize::toPrettyXML(query_map, str2);
  151. LL_CONT << "\nparams = " << str1.str() << "\nquery map = " << str2.str()
  152. << LL_ENDL;
  153. return info.mHandler ? info.mHandler->handle(params, query_map, web)
  154. : false;
  155. }
  156. void LLCommandHandlerRegistry::notifySlurlBlocked()
  157. {
  158. static F32 notify_after = 0.f;
  159. if (notify_after < gFrameTimeSeconds)
  160. {
  161. // Note: commands can arrive before we initialize everything we need
  162. // for Notification.
  163. if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
  164. {
  165. gNotifications.add("UnableToOpenCommandURL");
  166. }
  167. notify_after = gFrameTimeSeconds + 2.f * THROTTLE_PERIOD;
  168. }
  169. }
  170. void LLCommandHandlerRegistry::notifySlurlThrottled()
  171. {
  172. static F32 notify_after = 0.f;
  173. if (notify_after < gFrameTimeSeconds)
  174. {
  175. gNotifications.add("ThrottledCommandURL");
  176. notify_after = gFrameTimeSeconds + 2.f * THROTTLE_PERIOD;
  177. }
  178. }
  179. void LLCommandHandlerRegistry::dump()
  180. {
  181. std::string access;
  182. llinfos << "Existing command handlers:\n";
  183. for (handlers_map_t::const_iterator it = mMap.begin(), end = mMap.end();
  184. it != end; ++it)
  185. {
  186. const std::string& name = it->first;
  187. const LLCommandHandlerInfo& info = it->second;
  188. switch (info.mUntrustedBrowserAccess)
  189. {
  190. case LLCommandHandler::UNTRUSTED_ALLOW:
  191. access = "UNTRUSTED_ALLOW";
  192. break;
  193. case LLCommandHandler::UNTRUSTED_BLOCK:
  194. access = "UNTRUSTED_BLOCK";
  195. break;
  196. case LLCommandHandler::UNTRUSTED_CLICK_ONLY:
  197. access = "UNTRUSTED_CLICK_ONLY";
  198. break;
  199. case LLCommandHandler::UNTRUSTED_THROTTLE:
  200. access = "UNTRUSTED_THROTTLE";
  201. break;
  202. default:
  203. access = "Illegal access type !";
  204. }
  205. llcont << " - secondlife:///app/" << name << ": " << access << "\n";
  206. }
  207. llcont << llendl;
  208. }
  209. //---------------------------------------------------------------------------
  210. // Automatic registration of commands, runs before main()
  211. //---------------------------------------------------------------------------
  212. LLCommandHandler::LLCommandHandler(const char* cmd,
  213. EUntrustedAccess untrusted_access)
  214. {
  215. LLCommandHandlerRegistry::getInstance()->add(cmd, untrusted_access, this);
  216. }
  217. //static
  218. void LLCommandHandler::dump()
  219. {
  220. LLCommandHandlerRegistry::getInstance()->dump();
  221. }
  222. //---------------------------------------------------------------------------
  223. // Public interface
  224. //---------------------------------------------------------------------------
  225. //static
  226. bool LLCommandHandler::dispatch(const std::string& cmd, const LLSD& params,
  227. const LLSD& query_map, LLMediaCtrl* web,
  228. const std::string& nav_type,
  229. bool trusted_browser)
  230. {
  231. return LLCommandHandlerRegistry::getInstance()->dispatch(cmd, params,
  232. query_map, web,
  233. nav_type,
  234. trusted_browser);
  235. }