From 4e93228e25a941dde4b01c4ec934cd1907096a6f Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Mon, 19 May 2008 11:52:51 +0000 Subject: fixing exception when RestPlugin not configured. refactors RestRegionPlugin, adds error checking. --- .../Rest/Regions/GETRestRegionPlugin.cs | 184 +++++++++++++++++++++ .../Rest/Regions/RegionDetails.cs | 34 +++- .../Rest/Regions/RestRegionPlugin.cs | 76 ++------- OpenSim/ApplicationPlugins/Rest/RestPlugin.cs | 74 +++++++-- 4 files changed, 288 insertions(+), 80 deletions(-) create mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/GETRestRegionPlugin.cs diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETRestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETRestRegionPlugin.cs new file mode 100644 index 0000000..2b006e0 --- /dev/null +++ b/OpenSim/ApplicationPlugins/Rest/Regions/GETRestRegionPlugin.cs @@ -0,0 +1,184 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Timers; +using System.Xml; +using System.Xml.Serialization; +using libsecondlife; +using Mono.Addins; +using Nwc.XmlRpc; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Communications; +using OpenSim.Region.Environment.Scenes; +using OpenSim.ApplicationPlugins.Rest; + +namespace OpenSim.ApplicationPlugins.Rest.Regions +{ + + public partial class RestRegionPlugin : RestPlugin + { + #region GET methods + public string GetHandler(string request, string path, string param) + { + m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); + + try + { + // param empty: regions list + if (String.IsNullOrEmpty(param)) return GetHandlerRegions(); + + // param not empty: specific region + return GetHandlerRegion(param); + } + catch (Exception e) + { + return Failure("GET", e); + } + } + + public string GetHandlerRegions() + { + XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty); + foreach (Scene s in App.SceneManager.Scenes) + { + XmlWriter.WriteStartElement(String.Empty, "uuid", String.Empty); + XmlWriter.WriteString(s.RegionInfo.RegionID.ToString()); + XmlWriter.WriteEndElement(); + } + XmlWriter.WriteEndElement(); + + return XmlWriterResult; + } + + protected string ShortRegionInfo(string key, string value) + { + if (String.IsNullOrEmpty(value) || + String.IsNullOrEmpty(key)) return null; + + XmlWriter.WriteStartElement(String.Empty, "region", String.Empty); + XmlWriter.WriteStartElement(String.Empty, key, String.Empty); + XmlWriter.WriteString(value); + XmlWriter.WriteEndDocument(); + + return XmlWriterResult; + } + + public string GetHandlerRegion(string param) + { + // be resilient and don't get confused by a terminating '/' + param = param.TrimEnd(new char[]{'/'}); + string[] comps = param.Split('/'); + LLUUID regionID = (LLUUID)comps[0]; + + m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString()); + + if (LLUUID.Zero == regionID) throw new Exception("missing region ID"); + + Scene scene = null; + App.SceneManager.TryGetScene(regionID, out scene); + if (null == scene) return Failure("GET", "cannot find region"); + + RegionDetails details = new RegionDetails(scene.RegionInfo); + + // m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length); + // for (int i = 0; i < comps.Length; i++) m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]); + + if (1 == comps.Length) + { + // complete region details requested + XmlSerializer xs = new XmlSerializer(typeof(RegionDetails)); + xs.Serialize(XmlWriter, details); + return XmlWriterResult; + } + + if (2 == comps.Length) { + string resp = ShortRegionInfo(comps[1], details[comps[1]]); + if (null != resp) return resp; + + // m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]); + + // check for {terrain,stats,prims} + switch (comps[1].ToLower()) + { + case "terrain": + return RegionTerrain(scene); + + case "stats": + return RegionStats(scene); + + case "prims": + return RegionPrims(scene); + } + } + return Failure("GET", "too many parameters"); + } + #endregion GET methods + + protected string RegionTerrain(Scene scene) + { + return Failure("GET", "terrain not implemented"); + } + + protected string RegionStats(Scene scene) + { + int users = scene.GetAvatars().Count; + int objects = scene.Entities.Count - users; + + XmlWriter.WriteStartElement(String.Empty, "region", String.Empty); + XmlWriter.WriteStartElement(String.Empty, "stats", String.Empty); + + XmlWriter.WriteStartElement(String.Empty, "users", String.Empty); + XmlWriter.WriteString(users.ToString()); + XmlWriter.WriteEndElement(); + + XmlWriter.WriteStartElement(String.Empty, "objects", String.Empty); + XmlWriter.WriteString(objects.ToString()); + XmlWriter.WriteEndElement(); + + XmlWriter.WriteEndDocument(); + + return XmlWriterResult; + } + + protected string RegionPrims(Scene scene) + { + return Failure("GET", "prims not implemented"); + } + } +} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs index 5102e3f..c86c67f 100644 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs +++ b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs @@ -23,7 +23,7 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* +* */ using libsecondlife; @@ -65,8 +65,38 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions region_external_hostname = regInfo.ExternalHostName; if (!String.IsNullOrEmpty(regInfo.MasterAvatarFirstName)) - region_owner = String.Format("{0} {1}", regInfo.MasterAvatarFirstName, + region_owner = String.Format("{0} {1}", regInfo.MasterAvatarFirstName, regInfo.MasterAvatarLastName); } + + public string this[string idx] + { + get + { + switch(idx.ToLower()) + { + case "name": + return region_name; + case "id": + return region_id; + case "location": + return String.Format("{0}{1}", region_x, region_y); + case "owner": + return region_owner; + case "owner_id": + return region_owner_id; + case "http_port": + return region_http_port.ToString(); + case "server_uri": + return region_server_uri; + case "external_hostname": + case "hostname": + return region_external_hostname; + + default: + return null; + } + } + } } } \ No newline at end of file diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs index 0716cf6..9b888fa 100644 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs +++ b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs @@ -23,7 +23,7 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* +* */ using System; @@ -55,14 +55,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions { [Extension("/OpenSim/Startup")] - public class RestRegionPlugin : RestPlugin + public partial class RestRegionPlugin : RestPlugin { - private static readonly log4net.ILog _log = - log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - #region overriding properties - public override string Name - { + public override string Name + { get { return "REGION"; } } @@ -86,18 +83,20 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions try { base.Initialise(openSim); - if (IsEnabled) - m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); - else + if (!IsEnabled) + { m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); + return; + } + m_log.InfoFormat("{0} REST region plugin enabled", MsgID); // add REST method handlers AddRestStreamHandler("GET", "/regions/", GetHandler); } catch (Exception e) { - _log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); - _log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); + m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); + m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); } } @@ -105,58 +104,5 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions { } #endregion overriding methods - - #region methods - public string GetHandler(string request, string path, string param) - { - m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); - - // param empty: regions list - if (String.IsNullOrEmpty(param)) return GetHandlerRegions(); - - return GetHandlerRegion(param); - } - - public string GetHandlerRegions() - { - StringWriter sw = new StringWriter(); - XmlTextWriter xw = new XmlTextWriter(sw); - xw.Formatting = Formatting.Indented; - - xw.WriteStartElement(String.Empty, "regions", String.Empty); - foreach (Scene s in App.SceneManager.Scenes) - { - xw.WriteStartElement(String.Empty, "uuid", String.Empty); - xw.WriteString(s.RegionInfo.RegionID.ToString()); - xw.WriteEndElement(); - } - xw.WriteEndElement(); - xw.Close(); - - return sw.ToString(); - } - - public string GetHandlerRegion(string param) - { - string[] comps = param.Split('/'); - LLUUID regionID = (LLUUID)comps[0]; - _log.DebugFormat("{0} region UUID {1}", MsgID, regionID.ToString()); - - if (LLUUID.Zero == regionID) throw new Exception("missing region ID"); - - Scene scene = null; - App.SceneManager.TryGetScene(regionID, out scene); - - XmlSerializer xs = new XmlSerializer(typeof(RegionDetails)); - StringWriter sw = new StringWriter(); - XmlTextWriter xw = new XmlTextWriter(sw); - xw.Formatting = Formatting.Indented; - - xs.Serialize(xw, new RegionDetails(scene.RegionInfo)); - xw.Close(); - - return sw.ToString(); - } - #endregion methods } } diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs index 05ea956..199bff8 100644 --- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs +++ b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs @@ -23,16 +23,18 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* +* */ using System; using System.Threading; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Net; using System.Reflection; using System.Timers; +using System.Xml; using libsecondlife; using Mono.Addins; using Nwc.XmlRpc; @@ -54,14 +56,18 @@ namespace OpenSim.ApplicationPlugins.Rest { #region properties - protected static readonly log4net.ILog m_log = + protected static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IConfig _config; // Configuration source: Rest Plugins private IConfig _pluginConfig; // Configuration source: Plugin specific private OpenSimMain _app; // The 'server' private BaseHttpServer _httpd; // The server's RPC interface - private string _prefix; // URL prefix below which all REST URLs are living + private string _prefix; // URL prefix below + // which all REST URLs + // are living + private StringWriter _sw = null; + private XmlTextWriter _xw = null; private string _godkey; private int _reqk; @@ -100,8 +106,8 @@ namespace OpenSim.ApplicationPlugins.Rest /// public bool IsEnabled { - get - { + get + { return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false); } } @@ -109,7 +115,7 @@ namespace OpenSim.ApplicationPlugins.Rest /// /// OpenSimMain application /// - public OpenSimMain App + public OpenSimMain App { get { return _app; } } @@ -117,7 +123,7 @@ namespace OpenSim.ApplicationPlugins.Rest /// /// RPC server /// - public BaseHttpServer HttpServer + public BaseHttpServer HttpServer { get { return _httpd; } } @@ -147,6 +153,29 @@ namespace OpenSim.ApplicationPlugins.Rest /// Return the config section name /// public abstract string ConfigName { get; } + + public XmlTextWriter XmlWriter + { + get { + if (null == _xw) + { + _sw = new StringWriter(); + _xw = new XmlTextWriter(_sw); + _xw.Formatting = Formatting.Indented; + } + return _xw; } + } + + public string XmlWriterResult + { + get + { + _xw.Flush(); + _xw = null; + + return _sw.ToString(); + } + } #endregion properties @@ -171,7 +200,7 @@ namespace OpenSim.ApplicationPlugins.Rest return; } - if (!_config.GetBoolean("enabled", false)) + if (!_config.GetBoolean("enabled", false)) { m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); return; @@ -184,10 +213,11 @@ namespace OpenSim.ApplicationPlugins.Rest _godkey = _config.GetString("god_key", String.Empty); // Retrive prefix if any. _prefix = _config.GetString("prefix", "/admin"); - + // Get plugin specific config _pluginConfig = openSim.ConfigSource.Configs[ConfigName]; + m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); } catch (Exception e) @@ -200,7 +230,7 @@ namespace OpenSim.ApplicationPlugins.Rest // not possible for the openSim pointer to be null. However // were the implementation to be changed, this could // result in a silent initialization failure. Harmless - // except for lack of function and lack of any + // except for lack of function and lack of any // diagnostic indication as to why. The same is true if // the HTTP server reference is bad. // We should at least issue a message... @@ -214,7 +244,9 @@ namespace OpenSim.ApplicationPlugins.Rest public void AddRestStreamHandler(string httpMethod, string path, RestMethod method) { - if (!path.StartsWith(_prefix)) + if (!IsEnabled) return; + + if (!path.StartsWith(_prefix)) { path = String.Format("{0}{1}", _prefix, path); } @@ -226,10 +258,12 @@ namespace OpenSim.ApplicationPlugins.Rest m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path); } - - public bool VerifyGod(string key) + + protected bool VerifyGod(string key) { if (String.IsNullOrEmpty(key)) return false; + if (!IsEnabled) return false; + return key == _godkey; } @@ -241,6 +275,20 @@ namespace OpenSim.ApplicationPlugins.Rest } _handlers = null; } + + protected string Failure(string method, string message) + { + m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, message); + return String.Format("{0}", message); + } + + public string Failure(string method, Exception e) + { + m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); + m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); + + return String.Format("{0}", e.Message); + } #endregion methods } } -- cgit v1.1