/indra/llmessage/llservicebuilder.cpp
C++ | 236 lines | 185 code | 10 blank | 41 comment | 29 complexity | b5e1756938a95f4a5809c53883cce710 MD5 | raw file
Possible License(s): LGPL-2.1
- /**
- * @file llservicebuilder.cpp
- * @brief Implementation of the LLServiceBuilder class.
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include "llapp.h"
- #include "llfile.h"
- #include "llservicebuilder.h"
- #include "llsd.h"
- #include "llsdserialize.h"
- void LLServiceBuilder::loadServiceDefinitionsFromFile(
- const std::string& service_filename)
- {
- llifstream service_file(service_filename, std::ios::binary);
- if(service_file.is_open())
- {
- LLSD service_data;
- LLSDSerialize::fromXMLDocument(service_data, service_file);
- service_file.close();
- // Load service
- LLSD service_map = service_data["services"];
- for(LLSD::array_iterator array_itr = service_map.beginArray();
- array_itr != service_map.endArray();
- ++array_itr)
- {
- LLSD service_llsd = (*array_itr)["service-builder"];
- std::string service_name = (*array_itr)["name"].asString();
- createServiceDefinition(service_name, service_llsd);
- }
- llinfos << "loaded config file: " << service_filename << llendl;
- }
- else
- {
- llwarns << "unable to find config file: " << service_filename << llendl;
- }
- }
- void LLServiceBuilder::createServiceDefinition(
- const std::string& service_name,
- LLSD& service_llsd)
- {
- if(service_llsd.isString())
- {
- mServiceMap[ service_name ] = service_llsd.asString();
- }
- else if(service_llsd.isMap())
- {
- for(LLSD::map_iterator map_itr = service_llsd.beginMap();
- map_itr != service_llsd.endMap();
- ++map_itr)
- {
- std::string compound_builder_name = service_name;
- compound_builder_name.append("-");
- compound_builder_name.append((*map_itr).first);
- mServiceMap[ compound_builder_name ] = (*map_itr).second.asString();
- }
- }
- }
- static
- bool starts_with(const std::string& text, const char* prefix)
- {
- return text.substr(0, strlen(prefix)) == prefix;
- }
- // TODO: Build a real services.xml for windows development.
- // and remove the base_url logic below.
- std::string LLServiceBuilder::buildServiceURI(const std::string& service_name) const
- {
- std::ostringstream service_url;
- // Find the service builder
- std::map<std::string, std::string>::const_iterator it =
- mServiceMap.find(service_name);
- if(it != mServiceMap.end())
- {
- // construct the service builder url
- LLApp* app = LLApp::instance();
- if(app)
- {
- // We define a base-url for some development configurations
- // In production neither of these are defined and all services have full urls
- LLSD base_url;
- if (starts_with(service_name,"cap"))
- {
- base_url = app->getOption("cap-base-url");
- }
- if (base_url.asString().empty())
- {
- base_url = app->getOption("services-base-url");
- }
- service_url << base_url.asString();
- }
- service_url << it->second;
- }
- else
- {
- llwarns << "Cannot find service " << service_name << llendl;
- }
- return service_url.str();
- }
- std::string LLServiceBuilder::buildServiceURI(
- const std::string& service_name,
- const LLSD& option_map) const
- {
- return russ_format(buildServiceURI(service_name), option_map);
- }
- std::string russ_format(const std::string& format_str, const LLSD& context)
- {
- std::string service_url(format_str);
- if(!service_url.empty() && context.isMap())
- {
- // throw in a ridiculously large limiter to make sure we don't
- // loop forever with bad input.
- int iterations = 100;
- bool keep_looping = true;
- while(keep_looping)
- {
- if(0 == --iterations)
- {
- keep_looping = false;
- }
- int depth = 0;
- int deepest = 0;
- bool find_match = false;
- std::string::iterator iter(service_url.begin());
- std::string::iterator end(service_url.end());
- std::string::iterator deepest_node(service_url.end());
- std::string::iterator deepest_node_end(service_url.end());
- // parse out the variables to replace by going through {}s
- // one at a time, starting with the "deepest" in series
- // {{}}, and otherwise replacing right-to-left
- for(; iter != end; ++iter)
- {
- switch(*iter)
- {
- case '{':
- ++depth;
- if(depth > deepest)
- {
- deepest = depth;
- deepest_node = iter;
- find_match = true;
- }
- break;
- case '}':
- --depth;
- if(find_match)
- {
- deepest_node_end = iter;
- find_match = false;
- }
- break;
- default:
- break;
- }
- }
- if((deepest_node == end) || (deepest_node_end == end))
- {
- break;
- }
- //replace the variable we found in the {} above.
- // *NOTE: since the c++ implementation only understands
- // params and straight string substitution, so it's a
- // known distance of 2 to skip the directive.
- std::string key(deepest_node + 2, deepest_node_end);
- LLSD value = context[key];
- switch(*(deepest_node + 1))
- {
- case '$':
- if(value.isDefined())
- {
- service_url.replace(
- deepest_node,
- deepest_node_end + 1,
- value.asString());
- }
- else
- {
- llwarns << "Unknown key: " << key << " in option map: "
- << LLSDOStreamer<LLSDNotationFormatter>(context)
- << llendl;
- keep_looping = false;
- }
- break;
- case '%':
- {
- std::string query_str = LLURI::mapToQueryString(value);
- service_url.replace(
- deepest_node,
- deepest_node_end + 1,
- query_str);
- }
- break;
- default:
- llinfos << "Unknown directive: " << *(deepest_node + 1)
- << llendl;
- keep_looping = false;
- break;
- }
- }
- }
- if (service_url.find('{') != std::string::npos)
- {
- llwarns << "Constructed a likely bogus service URL: " << service_url
- << llendl;
- }
- return service_url;
- }