PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llmessage/llservicebuilder.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 236 lines | 185 code | 10 blank | 41 comment | 29 complexity | b5e1756938a95f4a5809c53883cce710 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llservicebuilder.cpp
  3. * @brief Implementation of the LLServiceBuilder class.
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llapp.h"
  28. #include "llfile.h"
  29. #include "llservicebuilder.h"
  30. #include "llsd.h"
  31. #include "llsdserialize.h"
  32. void LLServiceBuilder::loadServiceDefinitionsFromFile(
  33. const std::string& service_filename)
  34. {
  35. llifstream service_file(service_filename, std::ios::binary);
  36. if(service_file.is_open())
  37. {
  38. LLSD service_data;
  39. LLSDSerialize::fromXMLDocument(service_data, service_file);
  40. service_file.close();
  41. // Load service
  42. LLSD service_map = service_data["services"];
  43. for(LLSD::array_iterator array_itr = service_map.beginArray();
  44. array_itr != service_map.endArray();
  45. ++array_itr)
  46. {
  47. LLSD service_llsd = (*array_itr)["service-builder"];
  48. std::string service_name = (*array_itr)["name"].asString();
  49. createServiceDefinition(service_name, service_llsd);
  50. }
  51. llinfos << "loaded config file: " << service_filename << llendl;
  52. }
  53. else
  54. {
  55. llwarns << "unable to find config file: " << service_filename << llendl;
  56. }
  57. }
  58. void LLServiceBuilder::createServiceDefinition(
  59. const std::string& service_name,
  60. LLSD& service_llsd)
  61. {
  62. if(service_llsd.isString())
  63. {
  64. mServiceMap[ service_name ] = service_llsd.asString();
  65. }
  66. else if(service_llsd.isMap())
  67. {
  68. for(LLSD::map_iterator map_itr = service_llsd.beginMap();
  69. map_itr != service_llsd.endMap();
  70. ++map_itr)
  71. {
  72. std::string compound_builder_name = service_name;
  73. compound_builder_name.append("-");
  74. compound_builder_name.append((*map_itr).first);
  75. mServiceMap[ compound_builder_name ] = (*map_itr).second.asString();
  76. }
  77. }
  78. }
  79. static
  80. bool starts_with(const std::string& text, const char* prefix)
  81. {
  82. return text.substr(0, strlen(prefix)) == prefix;
  83. }
  84. // TODO: Build a real services.xml for windows development.
  85. // and remove the base_url logic below.
  86. std::string LLServiceBuilder::buildServiceURI(const std::string& service_name) const
  87. {
  88. std::ostringstream service_url;
  89. // Find the service builder
  90. std::map<std::string, std::string>::const_iterator it =
  91. mServiceMap.find(service_name);
  92. if(it != mServiceMap.end())
  93. {
  94. // construct the service builder url
  95. LLApp* app = LLApp::instance();
  96. if(app)
  97. {
  98. // We define a base-url for some development configurations
  99. // In production neither of these are defined and all services have full urls
  100. LLSD base_url;
  101. if (starts_with(service_name,"cap"))
  102. {
  103. base_url = app->getOption("cap-base-url");
  104. }
  105. if (base_url.asString().empty())
  106. {
  107. base_url = app->getOption("services-base-url");
  108. }
  109. service_url << base_url.asString();
  110. }
  111. service_url << it->second;
  112. }
  113. else
  114. {
  115. llwarns << "Cannot find service " << service_name << llendl;
  116. }
  117. return service_url.str();
  118. }
  119. std::string LLServiceBuilder::buildServiceURI(
  120. const std::string& service_name,
  121. const LLSD& option_map) const
  122. {
  123. return russ_format(buildServiceURI(service_name), option_map);
  124. }
  125. std::string russ_format(const std::string& format_str, const LLSD& context)
  126. {
  127. std::string service_url(format_str);
  128. if(!service_url.empty() && context.isMap())
  129. {
  130. // throw in a ridiculously large limiter to make sure we don't
  131. // loop forever with bad input.
  132. int iterations = 100;
  133. bool keep_looping = true;
  134. while(keep_looping)
  135. {
  136. if(0 == --iterations)
  137. {
  138. keep_looping = false;
  139. }
  140. int depth = 0;
  141. int deepest = 0;
  142. bool find_match = false;
  143. std::string::iterator iter(service_url.begin());
  144. std::string::iterator end(service_url.end());
  145. std::string::iterator deepest_node(service_url.end());
  146. std::string::iterator deepest_node_end(service_url.end());
  147. // parse out the variables to replace by going through {}s
  148. // one at a time, starting with the "deepest" in series
  149. // {{}}, and otherwise replacing right-to-left
  150. for(; iter != end; ++iter)
  151. {
  152. switch(*iter)
  153. {
  154. case '{':
  155. ++depth;
  156. if(depth > deepest)
  157. {
  158. deepest = depth;
  159. deepest_node = iter;
  160. find_match = true;
  161. }
  162. break;
  163. case '}':
  164. --depth;
  165. if(find_match)
  166. {
  167. deepest_node_end = iter;
  168. find_match = false;
  169. }
  170. break;
  171. default:
  172. break;
  173. }
  174. }
  175. if((deepest_node == end) || (deepest_node_end == end))
  176. {
  177. break;
  178. }
  179. //replace the variable we found in the {} above.
  180. // *NOTE: since the c++ implementation only understands
  181. // params and straight string substitution, so it's a
  182. // known distance of 2 to skip the directive.
  183. std::string key(deepest_node + 2, deepest_node_end);
  184. LLSD value = context[key];
  185. switch(*(deepest_node + 1))
  186. {
  187. case '$':
  188. if(value.isDefined())
  189. {
  190. service_url.replace(
  191. deepest_node,
  192. deepest_node_end + 1,
  193. value.asString());
  194. }
  195. else
  196. {
  197. llwarns << "Unknown key: " << key << " in option map: "
  198. << LLSDOStreamer<LLSDNotationFormatter>(context)
  199. << llendl;
  200. keep_looping = false;
  201. }
  202. break;
  203. case '%':
  204. {
  205. std::string query_str = LLURI::mapToQueryString(value);
  206. service_url.replace(
  207. deepest_node,
  208. deepest_node_end + 1,
  209. query_str);
  210. }
  211. break;
  212. default:
  213. llinfos << "Unknown directive: " << *(deepest_node + 1)
  214. << llendl;
  215. keep_looping = false;
  216. break;
  217. }
  218. }
  219. }
  220. if (service_url.find('{') != std::string::npos)
  221. {
  222. llwarns << "Constructed a likely bogus service URL: " << service_url
  223. << llendl;
  224. }
  225. return service_url;
  226. }